diff --git a/davtelepot/__init__.py b/davtelepot/__init__.py index d283752..e956684 100644 --- a/davtelepot/__init__.py +++ b/davtelepot/__init__.py @@ -11,7 +11,7 @@ __author__ = "Davide Testa" __email__ = "davide@davte.it" __credits__ = ["Marco Origlia", "Nick Lee @Nickoala"] __license__ = "GNU General Public License v3.0" -__version__ = "2.6.9" +__version__ = "2.6.10" __maintainer__ = "Davide Testa" __contact__ = "t.me/davte" diff --git a/davtelepot/bot.py b/davtelepot/bot.py index ef648e5..dd5665a 100644 --- a/davtelepot/bot.py +++ b/davtelepot/bot.py @@ -193,6 +193,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject): self.messages['reply_keyboard_buttons'] = dict() self._unknown_command_message = None self.text_message_parsers = OrderedDict() + self.document_handlers = OrderedDict() + self.individual_document_message_handlers = dict() # Support for /help command self.messages['help_sections'] = OrderedDict() # Handle location messages @@ -881,10 +883,38 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject): async def document_message_handler(self, update, user_record, language=None): """Handle `document` message update.""" - logging.info( - "A document message update was received, " - "but this handler does nothing yet." - ) + replier, reply = None, None + user_id = update['from']['id'] if 'from' in update else None + if user_id in self.individual_document_message_handlers: + replier = self.individual_document_message_handlers[user_id] + del self.individual_document_message_handlers[user_id] + else: + for check_function, handler in self.document_handlers.items(): + if check_function(update): + replier = handler['handler'] + break + if replier: + reply = await replier( + bot=self, + **{ + name: argument + for name, argument in locals().items() + if name in inspect.signature( + replier + ).parameters + } + ) + if reply: + if type(reply) is str: + reply = dict(text=reply) + try: + return await self.reply(update=update, **reply) + except Exception as e: + logging.error( + f"Failed to handle document:\n{e}", + exc_info=True + ) + return async def animation_message_handler(self, update, user_record, language=None): """Handle `animation` message update.""" @@ -2410,6 +2440,47 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject): ) return parser_decorator + def document_handler(self, condition, description='', + authorization_level='admin'): + """Decorator: define a handler for document updates matching `condition`. + + You may provide a description and a minimum authorization level. + The first handler matching condition is called (other matching handlers + are ignored). + """ + if not callable(condition): + raise TypeError( + f'Condition {condition.__name__} is not a callable' + ) + + def parser_decorator(parser): + async def decorated_parser(bot, update, user_record, language=None): + logging.info( + f"Document update matching condition " + f"`{condition.__name__}@{bot.name}` from " + f"`{update['from'] if 'from' in update else update['chat']}`" + ) + if bot.authorization_function( + update=update, + user_record=user_record, + authorization_level=authorization_level + ): + # Pass supported arguments from locals() to parser + return await parser( + **{ + name: arg + for name, arg in locals().items() + if name in inspect.signature(parser).parameters + } + ) + return dict(text=bot.authorization_denied_message) + self.document_handlers[condition] = dict( + handler=decorated_parser, + description=description, + authorization_level=authorization_level, + ) + return parser_decorator + def set_command(self, command, handler, aliases=None, reply_keyboard_button=None, show_in_keyboard=False, description="", @@ -2671,6 +2742,40 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject): del self.individual_location_handlers[identifier] return + def set_individual_document_handler(self, handler, + update=None, user_id=None): + """Set a custom document handler for the user. + + Any document update from the user will be handled by this custom + handler instead of default handlers for documents. + Custom handlers last one single use, but they can call this method and + set themselves as next custom document handler. + """ + identifier = self.get_user_identifier( + user_id=user_id, + update=update + ) + assert callable(handler), (f"Handler `{handler.name}` is not " + "callable. Custom document handler " + "could not be set.") + self.individual_document_message_handlers[identifier] = handler + return + + def remove_individual_document_handler(self, + update=None, user_id=None): + """Remove a custom document handler for the user. + + Any document update from the user will be handled by default + handlers for documents. + """ + identifier = self.get_user_identifier( + user_id=user_id, + update=update + ) + if identifier in self.individual_document_message_handlers: + del self.individual_document_message_handlers[identifier] + return + def set_individual_voice_handler(self, handler, update=None, user_id=None): """Set a custom voice message handler for the user. diff --git a/update_package.sh b/update_package.sh index 9e15983..7d0eefa 100644 --- a/update_package.sh +++ b/update_package.sh @@ -1,7 +1,8 @@ #!/bin/bash # Get current directory -this_script_directory=$(cd `dirname $0` && pwd) +this_script_directory=$(cd "$(dirname "$0")" && pwd) +packenv=""; # Python virtual environment directory: packenv variable in my_config.sh source $this_script_directory/my_config.sh;