Queer European MD passionate about IT
Bläddra i källkod

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.
Davte 5 år sedan
förälder
incheckning
e412548edf
1 ändrade filer med 46 tillägg och 10 borttagningar
  1. 46 10
      davtelepot/bot.py

+ 46 - 10
davtelepot/bot.py

@@ -42,7 +42,7 @@ from aiohttp import web
 from davtelepot.api import TelegramBot, TelegramError
 from davtelepot.database import ObjectWithDatabase
 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
 )
 
@@ -168,6 +168,7 @@ class Bot(TelegramBot, ObjectWithDatabase):
         self.text_message_parsers = OrderedDict()
         # Callback query-related properties
         self.callback_handlers = OrderedDict()
+        self._callback_data_separator = None
         # Inline query-related properties
         self.inline_query_handlers = OrderedDict()
         self._default_inline_query_answer = None
@@ -348,6 +349,25 @@ class Bot(TelegramBot, ObjectWithDatabase):
             return self._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
     def default_inline_query_answer(self):
         """Answer to be returned if inline query returned None.
@@ -1387,24 +1407,28 @@ class Bot(TelegramBot, ObjectWithDatabase):
             authorization_level=authorization_level
         )(handler)
 
-    def button(self, data, description='', authorization_level='admin'):
-        """Associate a bot button prefix (`data`) with a handler.
+    def button(self, prefix, separator=None, description='',
+               authorization_level='admin'):
+        """Associate a bot button `prefix` with a handler.
 
-        When a callback data text starts with <data>, the associated handler is
-            called upon the update.
+        When a callback data text starts with `prefix`, the associated handler
+            is called upon the update.
         Decorate button handlers like this:
             ```
-            @bot.button('a_prefix:///', "A button", 'user')
-            async def button_handler(bot, update, user_record):
+            @bot.button('a_prefix:///', description="A button",
+                        authorization_level='user')
+            async def button_handler(bot, update, user_record, data):
                 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.
         `authorization_level` is the lowest authorization level needed to
             be allowed to push the button.
         """
-        if not isinstance(data, str):
+        if not isinstance(prefix, str):
             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):
@@ -1419,8 +1443,20 @@ class Bot(TelegramBot, ObjectWithDatabase):
                     authorization_level=authorization_level
                 ):
                     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
-            self.callback_handlers[data] = dict(
+            self.callback_handlers[prefix] = dict(
                 handler=decorated_button_handler,
                 description=description,
                 authorization_level=authorization_level