Queer European MD passionate about IT

helper.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. """Make a self-consistent bot help section."""
  2. # Project modules
  3. from collections import OrderedDict
  4. from davtelepot.bot import Bot
  5. from davtelepot.messages import default_help_messages
  6. from davtelepot.utilities import (
  7. get_cleaned_text, make_inline_keyboard,
  8. make_lines_of_buttons, make_button,
  9. recursive_dictionary_update
  10. )
  11. def get_commands_description(bot: Bot, update, user_record):
  12. """Get a string description of `bot` commands.
  13. Show only commands available for `update` sender.
  14. """
  15. user_role = bot.Role.get_user_role(
  16. user_record=user_record
  17. )
  18. commands = {}
  19. for command, details in bot.commands.items():
  20. if 'description' not in details or not details['description']:
  21. continue
  22. if 'authorization_level' not in details:
  23. continue
  24. command_role = bot.Role.get_role_by_name(details['authorization_level'])
  25. if command_role.code < user_role.code:
  26. continue
  27. if command_role.code not in commands:
  28. commands[command_role.code] = []
  29. commands[command_role.code].append(
  30. "/{command}{authorization_level}: {description}".format(
  31. command=bot.get_message(
  32. messages=details['language_labelled_commands'],
  33. default_message=command,
  34. user_record=user_record, update=update
  35. ),
  36. authorization_level=(
  37. f" <i>[{command_role.plural}]</i>"
  38. if command_role.code != bot.Role.default_role_code
  39. else ""
  40. ),
  41. description=bot.get_message(
  42. 'commands', command, 'description',
  43. user_record=user_record, update=update,
  44. default_message=(
  45. details['description']
  46. if type(details['description']) is str
  47. else ''
  48. )
  49. )
  50. )
  51. )
  52. return "\n".join(
  53. [
  54. command
  55. for role, commands in sorted(
  56. commands.items(),
  57. key=(lambda x: -x[0])
  58. )
  59. for command in sorted(
  60. commands
  61. )
  62. ]
  63. )
  64. # [
  65. # "/{command}{authorization_level}: {description}".format(
  66. # command=command,
  67. # authorization_level=(
  68. # ""
  69. # if 1
  70. # else ""
  71. # ),
  72. # description=bot.get_message(
  73. # 'commands', command, 'description',
  74. # user_record=user_record, update=update,
  75. # default_message=(
  76. # details['description']
  77. # if type(details['description']) is str
  78. # else ''
  79. # )
  80. # )
  81. # )
  82. # if 'description' in details and details['description']
  83. # and user_role.code <= bot.Role.get_user_role(
  84. # user_role_id=details['authorization_level']
  85. # ).code
  86. # ]
  87. # )
  88. def _make_button(text=None, callback_data='',
  89. prefix='help:///', delimiter='|', data=None):
  90. return make_button(text=text, callback_data=callback_data,
  91. prefix=prefix, delimiter=delimiter, data=data)
  92. def get_back_to_help_menu_keyboard(bot, update, user_record):
  93. """Return a keyboard to let user come back to help menu."""
  94. return make_inline_keyboard(
  95. [
  96. _make_button(
  97. text=bot.get_message(
  98. 'help', 'help_command', 'back_to_help_menu',
  99. update=update, user_record=user_record
  100. ),
  101. data=['menu']
  102. )
  103. ],
  104. 1
  105. )
  106. def get_help_buttons(bot, update, user_record):
  107. """Get `bot` help menu inline keyboard.
  108. Show only buttons available for `update` sender.
  109. """
  110. user_role = bot.Role.get_user_role(
  111. user_record=user_record
  112. )
  113. buttons_list = [
  114. _make_button(
  115. text=bot.get_message(
  116. 'help_sections', section['name'], 'label',
  117. update=update, user_record=user_record,
  118. ),
  119. data=['section', name]
  120. )
  121. for name, section in bot.messages['help_sections'].items()
  122. if 'authorization_level' in section
  123. and user_role.code <= bot.Role.get_user_role(
  124. user_role_id=section['authorization_level']
  125. ).code
  126. ]
  127. return dict(
  128. inline_keyboard=(
  129. make_lines_of_buttons(buttons_list, 3)
  130. + make_lines_of_buttons(
  131. [
  132. _make_button(
  133. text=bot.get_message(
  134. 'help', 'commands_button_label',
  135. update=update, user_record=user_record,
  136. ),
  137. data=['commands']
  138. )
  139. ],
  140. 1
  141. )
  142. )
  143. )
  144. async def _help_command(bot, update, user_record):
  145. if not bot.authorization_function(update=update,
  146. authorization_level='everybody'):
  147. return bot.get_message(
  148. 'help', 'help_command', 'access_denied_message',
  149. update=update, user_record=user_record
  150. )
  151. reply_markup = get_help_buttons(bot, update, user_record)
  152. return dict(
  153. text=bot.get_message(
  154. 'help', 'help_command', 'text',
  155. update=update, user_record=user_record,
  156. bot=bot
  157. ),
  158. parse_mode='HTML',
  159. reply_markup=reply_markup,
  160. disable_web_page_preview=True
  161. )
  162. async def _help_button(bot, update, user_record, data):
  163. result, text, reply_markup = '', '', None
  164. if data[0] == 'commands':
  165. text = bot.get_message(
  166. 'help', 'help_command', 'header',
  167. update=update, user_record=user_record,
  168. bot=bot,
  169. commands=get_commands_description(bot, update, user_record)
  170. )
  171. reply_markup = get_back_to_help_menu_keyboard(
  172. bot=bot, update=update, user_record=user_record
  173. )
  174. elif data[0] == 'menu':
  175. text = bot.get_message(
  176. 'help', 'help_command', 'text',
  177. update=update, user_record=user_record,
  178. bot=bot
  179. )
  180. reply_markup = get_help_buttons(bot, update, user_record)
  181. elif (
  182. data[0] == 'section'
  183. and len(data) > 1
  184. and data[1] in bot.messages['help_sections']
  185. ):
  186. section = bot.messages['help_sections'][data[1]]
  187. if bot.authorization_function(
  188. update=update,
  189. authorization_level=section['authorization_level']
  190. ):
  191. text = (
  192. "<b>{label}</b>\n\n"
  193. "{description}"
  194. ).format(
  195. label=bot.get_message(
  196. 'help_sections', section['name'], 'label',
  197. update=update, user_record=user_record,
  198. ),
  199. description=bot.get_message(
  200. 'help_sections', section['name'], 'description',
  201. update=update, user_record=user_record,
  202. bot=bot
  203. ),
  204. )
  205. else:
  206. text = bot.authorization_denied_message
  207. reply_markup = get_back_to_help_menu_keyboard(
  208. bot=bot, update=update, user_record=user_record
  209. )
  210. if text or reply_markup:
  211. return dict(
  212. text=result,
  213. edit=dict(
  214. text=text,
  215. parse_mode='HTML',
  216. reply_markup=reply_markup,
  217. disable_web_page_preview=True
  218. )
  219. )
  220. return result
  221. async def _start_command(bot: Bot, update: dict,
  222. user_record: OrderedDict, language: str):
  223. text = get_cleaned_text(update=update, bot=bot, replace=['start'])
  224. if not text:
  225. return await _help_command(bot, update, user_record)
  226. update['text'] = text
  227. await bot.text_message_handler(
  228. update=update,
  229. user_record=user_record,
  230. language=language
  231. )
  232. return
  233. def init(telegram_bot: Bot, help_messages: dict = None):
  234. """Assign parsers, commands, buttons and queries to given `bot`."""
  235. if help_messages is None:
  236. help_messages = default_help_messages
  237. else:
  238. help_messages = recursive_dictionary_update(
  239. default_help_messages.copy(),
  240. help_messages.copy()
  241. )
  242. telegram_bot.messages['help'] = help_messages
  243. @telegram_bot.command("/start", authorization_level='everybody')
  244. async def start_command(bot, update, user_record, language):
  245. return await _start_command(bot=bot, update=update,
  246. user_record=user_record, language=language)
  247. @telegram_bot.command(command='/help', aliases=['00help'],
  248. reply_keyboard_button=help_messages['help_command'][
  249. 'reply_keyboard_button'],
  250. show_in_keyboard=True,
  251. description=help_messages['help_command']['description'],
  252. authorization_level='everybody')
  253. async def help_command(bot, update, user_record):
  254. return await _help_command(bot, update, user_record)
  255. @telegram_bot.button(prefix='help:///', separator='|',
  256. authorization_level='everybody')
  257. async def help_button(bot, update, user_record, data):
  258. return await _help_button(bot, update, user_record, data)