Support for multilanguage /help command
A bot guide may be built automatically using @bot.command decorator.
This commit is contained in:
parent
a2365f815d
commit
45e2bbfa3d
@ -14,7 +14,7 @@ __author__ = "Davide Testa"
|
||||
__email__ = "davide@davte.it"
|
||||
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
|
||||
__license__ = "GNU General Public License v3.0"
|
||||
__version__ = "2.2.9"
|
||||
__version__ = "2.3.0"
|
||||
__maintainer__ = "Davide Testa"
|
||||
__contact__ = "t.me/davte"
|
||||
|
||||
|
@ -181,6 +181,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
||||
self.messages['reply_keyboard_buttons'] = dict()
|
||||
self._unknown_command_message = None
|
||||
self.text_message_parsers = OrderedDict()
|
||||
# Support for /help command
|
||||
self.messages['help_sections'] = OrderedDict()
|
||||
# Handle location messages
|
||||
self.individual_location_handlers = dict()
|
||||
# Callback query-related properties
|
||||
@ -1577,6 +1579,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
||||
|
||||
def command(self, command, aliases=None, reply_keyboard_button=None,
|
||||
show_in_keyboard=False, description="",
|
||||
help_section=None,
|
||||
authorization_level='admin'):
|
||||
"""Associate a bot command with a custom handler function.
|
||||
|
||||
@ -1598,6 +1601,22 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
||||
default keyboard.
|
||||
`description` can be used to help users understand what `/command`
|
||||
does.
|
||||
`help_section` is a dict on which the corresponding help section is
|
||||
built. It may provide multilanguage support and should be
|
||||
structured as follows:
|
||||
{
|
||||
"label": { # It will be displayed as button label
|
||||
'en': "Label",
|
||||
...
|
||||
},
|
||||
"name": "section_name",
|
||||
# If missing, `authorization_level` is used
|
||||
"authorization_level": "everybody",
|
||||
"description": {
|
||||
'en': "Description in English",
|
||||
...
|
||||
},
|
||||
}
|
||||
`authorization_level` is the lowest authorization level needed to run
|
||||
the command.
|
||||
"""
|
||||
@ -1619,6 +1638,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
||||
raise TypeError(
|
||||
f'Aliases {aliases} is not a list of strings string'
|
||||
)
|
||||
if isinstance(help_section, dict):
|
||||
if 'authorization_level' not in help_section:
|
||||
help_section['authorization_level'] = authorization_level
|
||||
self.messages['help_sections'][help_section['name']] = help_section
|
||||
command = command.strip('/ ').lower()
|
||||
|
||||
def command_decorator(command_handler):
|
||||
|
@ -373,6 +373,7 @@ class Bot(davtelepot.bot.Bot):
|
||||
def command(self, command, aliases=None, show_in_keyboard=False,
|
||||
reply_keyboard_button=None, descr="", auth='admin',
|
||||
description=None,
|
||||
help_section=None,
|
||||
authorization_level=None):
|
||||
"""Define a bot command.
|
||||
|
||||
@ -387,6 +388,7 @@ class Bot(davtelepot.bot.Bot):
|
||||
reply_keyboard_button=reply_keyboard_button,
|
||||
show_in_keyboard=show_in_keyboard,
|
||||
description=description,
|
||||
help_section=help_section,
|
||||
authorization_level=authorization_level
|
||||
)
|
||||
|
||||
|
226
davtelepot/helper.py
Normal file
226
davtelepot/helper.py
Normal file
@ -0,0 +1,226 @@
|
||||
"""Make a self-consistent bot help section."""
|
||||
|
||||
# Third party modules
|
||||
from davtelepot.utilities import (
|
||||
get_cleaned_text, make_inline_keyboard,
|
||||
make_lines_of_buttons, make_button
|
||||
)
|
||||
|
||||
# Project modules
|
||||
from .messages import default_help_messages
|
||||
|
||||
|
||||
def get_command_description(bot, update, user_record):
|
||||
"""Get a string description of `bot` commands.
|
||||
|
||||
Show only commands available for `update` sender.
|
||||
"""
|
||||
user_role = bot.Role.get_user_role(
|
||||
user_record=user_record
|
||||
)
|
||||
return "\n".join(
|
||||
[
|
||||
"/{}: {}".format(
|
||||
command,
|
||||
bot.get_message(
|
||||
'commands', command, 'description',
|
||||
user_record=user_record, update=update,
|
||||
default_message=(
|
||||
details['description']
|
||||
if type(details['description']) is str
|
||||
else ''
|
||||
)
|
||||
)
|
||||
)
|
||||
for command, details in sorted(
|
||||
bot.commands.items(),
|
||||
key=lambda x:x[0]
|
||||
)
|
||||
if details['description']
|
||||
and user_role.code <= bot.Role.get_user_role(
|
||||
user_role_id=details['authorization_level']
|
||||
).code
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _make_button(text=None, callback_data='',
|
||||
prefix='help:///', delimiter='|', data=[]):
|
||||
return make_button(text=text, callback_data=callback_data,
|
||||
prefix=prefix, delimiter=delimiter, data=data)
|
||||
|
||||
|
||||
def get_back_to_help_menu_keyboard(bot, update, user_record):
|
||||
"""Return a keyboard to let user come back to help menu."""
|
||||
return make_inline_keyboard(
|
||||
[
|
||||
_make_button(
|
||||
text=bot.get_message(
|
||||
'help', 'help_command', 'back_to_help_menu',
|
||||
update=update, user_record=user_record
|
||||
),
|
||||
data=['menu']
|
||||
)
|
||||
],
|
||||
1
|
||||
)
|
||||
|
||||
|
||||
def get_help_buttons(bot, update, user_record):
|
||||
"""Get `bot` help menu inline keyboard.
|
||||
|
||||
Show only buttons available for `update` sender.
|
||||
"""
|
||||
user_role = bot.Role.get_user_role(
|
||||
user_record=user_record
|
||||
)
|
||||
buttons_list = [
|
||||
_make_button(
|
||||
text=bot.get_message(
|
||||
'help_sections', section['name'], 'label',
|
||||
update=update, user_record=user_record,
|
||||
),
|
||||
data=['section', name]
|
||||
)
|
||||
for name, section in bot.messages['help_sections'].items()
|
||||
if 'authorization_level' in section
|
||||
and user_role.code <= bot.Role.get_user_role(
|
||||
user_role_id=section['authorization_level']
|
||||
).code
|
||||
]
|
||||
return dict(
|
||||
inline_keyboard=(
|
||||
make_lines_of_buttons(buttons_list, 3)
|
||||
+ make_lines_of_buttons(
|
||||
[
|
||||
_make_button(
|
||||
text=bot.get_message(
|
||||
'help', 'commands_button_label',
|
||||
update=update, user_record=user_record,
|
||||
),
|
||||
data=['commands']
|
||||
)
|
||||
],
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _help_command(bot, update, user_record):
|
||||
if not bot.authorization_function(update=update,
|
||||
authorization_level='everybody'):
|
||||
return bot.get_message(
|
||||
'help', 'help_command', 'access_denied_message',
|
||||
update=update, user_record=user_record
|
||||
)
|
||||
reply_markup = get_help_buttons(bot, update, user_record)
|
||||
return dict(
|
||||
text=bot.get_message(
|
||||
'help', 'help_command', 'text',
|
||||
update=update, user_record=user_record,
|
||||
bot=bot
|
||||
),
|
||||
parse_mode='HTML',
|
||||
reply_markup=reply_markup,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
|
||||
|
||||
async def _help_button(bot, update, user_record, data):
|
||||
result, text, reply_markup = '', '', None
|
||||
if data[0] == 'commands':
|
||||
text = bot.get_message(
|
||||
'help', 'help_command', 'header',
|
||||
update=update, user_record=user_record,
|
||||
bot=bot,
|
||||
commands=get_command_description(bot, update, user_record)
|
||||
)
|
||||
reply_markup = get_back_to_help_menu_keyboard(
|
||||
bot=bot, update=update, user_record=user_record
|
||||
)
|
||||
elif data[0] == 'menu':
|
||||
text = bot.get_message(
|
||||
'help', 'help_command', 'text',
|
||||
update=update, user_record=user_record,
|
||||
bot=bot
|
||||
)
|
||||
reply_markup = get_help_buttons(bot, update, user_record)
|
||||
elif (
|
||||
data[0] == 'section'
|
||||
and len(data) > 1
|
||||
and data[1] in bot.messages['help_sections']
|
||||
):
|
||||
section = bot.messages['help_sections'][data[1]]
|
||||
if bot.authorization_function(
|
||||
update=update,
|
||||
authorization_level=section['authorization_level']
|
||||
):
|
||||
text = (
|
||||
"<b>{label}</b>\n\n"
|
||||
"{description}"
|
||||
).format(
|
||||
label=bot.get_message(
|
||||
'help_sections', section['name'], 'label',
|
||||
update=update, user_record=user_record,
|
||||
),
|
||||
description=bot.get_message(
|
||||
'help_sections', section['name'], 'description',
|
||||
update=update, user_record=user_record,
|
||||
bot=bot
|
||||
),
|
||||
)
|
||||
else:
|
||||
text = bot.authorization_denied_message
|
||||
reply_markup = get_back_to_help_menu_keyboard(
|
||||
bot=bot, update=update, user_record=user_record
|
||||
)
|
||||
if text or reply_markup:
|
||||
return dict(
|
||||
text=result,
|
||||
edit=dict(
|
||||
text=text,
|
||||
parse_mode='HTML',
|
||||
reply_markup=reply_markup,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
async def _start_command(bot, update, user_record):
|
||||
text = get_cleaned_text(update=update, bot=bot, replace=['start'])
|
||||
if not text:
|
||||
return await _help_command(bot, update, user_record)
|
||||
update['text'] = text
|
||||
await bot.text_message_handler(
|
||||
update=update,
|
||||
user_record=None
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
def init(bot, help_messages=None):
|
||||
"""Assign parsers, commands, buttons and queries to given `bot`."""
|
||||
if help_messages is None:
|
||||
help_messages = default_help_messages
|
||||
bot.messages['help'] = help_messages
|
||||
|
||||
@bot.command("/start", authorization_level='everybody')
|
||||
async def start_command(bot, update, user_record):
|
||||
return await _start_command(bot, update, user_record)
|
||||
|
||||
@bot.command(command='/help', aliases=['00help'],
|
||||
reply_keyboard_button=help_messages['help_command'][
|
||||
'reply_keyboard_button'],
|
||||
show_in_keyboard=True,
|
||||
description=help_messages['help_command']['description'],
|
||||
authorization_level='everybody')
|
||||
async def help_command(bot, update, user_record):
|
||||
result = await _help_command(bot, update, user_record)
|
||||
return result
|
||||
|
||||
@bot.button(prefix='help:///', separator='|',
|
||||
authorization_level='everybody')
|
||||
async def help_button(bot, update, user_record, data):
|
||||
return await _help_button(bot, update, user_record, data)
|
39
davtelepot/messages.py
Normal file
39
davtelepot/messages.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""Default messages for bot functions."""
|
||||
|
||||
default_help_messages = {
|
||||
'help_command': {
|
||||
'header': {
|
||||
'en': "<b>{bot.name} commands</b>\n\n"
|
||||
"{commands}",
|
||||
'it': "<b>Comandi di {bot.name}</b>\n\n"
|
||||
"{commands}",
|
||||
},
|
||||
'text': {
|
||||
'en': "<b>Guide</b>",
|
||||
'it': "<b>Guida</b>"
|
||||
},
|
||||
'reply_keyboard_button': {
|
||||
'en': "Help 📖",
|
||||
'it': "Guida 📖"
|
||||
},
|
||||
'description': {
|
||||
'en': "Help",
|
||||
'it': "Aiuto"
|
||||
},
|
||||
'access_denied_message': {
|
||||
'en': "Ask for authorization. If your request is accepted, send "
|
||||
"/help command again to read the guide.",
|
||||
'it': "Chiedi di essere autorizzato: se la tua richiesta "
|
||||
"verrà accolta, ripeti il comando /help per leggere "
|
||||
"il messaggio di aiuto."
|
||||
},
|
||||
'back_to_help_menu': {
|
||||
'en': "Back to guide menu 📖",
|
||||
'it': "Torna al menu Guida 📖",
|
||||
},
|
||||
},
|
||||
'commands_button_label': {
|
||||
'en': "Commands 🤖",
|
||||
'it': "Comandi 🤖",
|
||||
},
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user