Added Bot() property callback_data_separator and method to set it

It will be used to parse callback data unless a more specific separator 
is passed to @Bot().button decorator. If both are None, data will be a 
string without prefix.
This commit is contained in:
Davte 2019-07-15 13:02:44 +02:00
parent f689d9b95a
commit e412548edf

View File

@ -42,7 +42,7 @@ from aiohttp import web
from davtelepot.api import TelegramBot, TelegramError from davtelepot.api import TelegramBot, TelegramError
from davtelepot.database import ObjectWithDatabase from davtelepot.database import ObjectWithDatabase
from davtelepot.utilities import ( from davtelepot.utilities import (
escape_html_chars, get_secure_key, make_inline_query_answer, escape_html_chars, extract, get_secure_key, make_inline_query_answer,
make_lines_of_buttons, remove_html_tags make_lines_of_buttons, remove_html_tags
) )
@ -168,6 +168,7 @@ class Bot(TelegramBot, ObjectWithDatabase):
self.text_message_parsers = OrderedDict() self.text_message_parsers = OrderedDict()
# Callback query-related properties # Callback query-related properties
self.callback_handlers = OrderedDict() self.callback_handlers = OrderedDict()
self._callback_data_separator = None
# Inline query-related properties # Inline query-related properties
self.inline_query_handlers = OrderedDict() self.inline_query_handlers = OrderedDict()
self._default_inline_query_answer = None self._default_inline_query_answer = None
@ -348,6 +349,25 @@ class Bot(TelegramBot, ObjectWithDatabase):
return self._unknown_command_message return self._unknown_command_message
return self.__class__._unknown_command_message return self.__class__._unknown_command_message
@property
def callback_data_separator(self):
"""Separator between callback data elements.
Example of callback_data: 'my_button_prefix:///1|4|test'
Prefix: `my_button_prefix:///`
Separator: `|` <--- this is returned
Data: `['1', '4', 'test']`
"""
return self._callback_data_separator
def set_callback_data_separator(self, separator):
"""Set a callback_data separator.
See property `callback_data_separator` for details.
"""
assert type(separator) is str, "Separator must be a string!"
self._callback_data_separator = separator
@property @property
def default_inline_query_answer(self): def default_inline_query_answer(self):
"""Answer to be returned if inline query returned None. """Answer to be returned if inline query returned None.
@ -1387,24 +1407,28 @@ class Bot(TelegramBot, ObjectWithDatabase):
authorization_level=authorization_level authorization_level=authorization_level
)(handler) )(handler)
def button(self, data, description='', authorization_level='admin'): def button(self, prefix, separator=None, description='',
"""Associate a bot button prefix (`data`) with a handler. authorization_level='admin'):
"""Associate a bot button `prefix` with a handler.
When a callback data text starts with <data>, the associated handler is When a callback data text starts with `prefix`, the associated handler
called upon the update. is called upon the update.
Decorate button handlers like this: Decorate button handlers like this:
``` ```
@bot.button('a_prefix:///', "A button", 'user') @bot.button('a_prefix:///', description="A button",
async def button_handler(bot, update, user_record): authorization_level='user')
async def button_handler(bot, update, user_record, data):
return "Result" return "Result"
``` ```
`separator` will be used to parse callback data received when a button
starting with `prefix` will be pressed.
`description` contains information about the button. `description` contains information about the button.
`authorization_level` is the lowest authorization level needed to `authorization_level` is the lowest authorization level needed to
be allowed to push the button. be allowed to push the button.
""" """
if not isinstance(data, str): if not isinstance(prefix, str):
raise TypeError( raise TypeError(
f'Inline button callback_data {data} is not a string' f'Inline button callback_data {prefix} is not a string'
) )
def button_decorator(handler): def button_decorator(handler):
@ -1419,8 +1443,20 @@ class Bot(TelegramBot, ObjectWithDatabase):
authorization_level=authorization_level authorization_level=authorization_level
): ):
return await handler(bot, update, user_record) return await handler(bot, update, user_record)
# Remove `prefix` from `ðata`
data = extract(update['data'], prefix)
# If a specific separator or default separator is set,
# use it to split `data` string in a list.
# Cast numeric `data` elements to `int`.
_separator = separator or self.callback_data_separator
if _separator:
data = [
int(element) if element.isnumeric()
else element
for element in data.split(_separator)
]
return bot.unauthorized_message return bot.unauthorized_message
self.callback_handlers[data] = dict( self.callback_handlers[prefix] = dict(
handler=decorated_button_handler, handler=decorated_button_handler,
description=description, description=description,
authorization_level=authorization_level authorization_level=authorization_level