From 5c72bb2b589bd3d0727e58ebc75e6a084096a244 Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 04:15:22 +0300 Subject: [PATCH 1/7] Add IdFilter --- aiogram/dispatcher/dispatcher.py | 7 ++- aiogram/dispatcher/filters/__init__.py | 3 +- aiogram/dispatcher/filters/builtin.py | 66 ++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 39eb7810..0da5f621 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -9,7 +9,7 @@ import aiohttp from aiohttp.helpers import sentinel from .filters import Command, ContentTypeFilter, ExceptionsFilter, FiltersFactory, HashTag, Regexp, \ - RegexpCommandsFilter, StateFilter, Text + RegexpCommandsFilter, StateFilter, Text, IdFilter from .handler import Handler from .middlewares import MiddlewareManager from .storage import BaseStorage, DELTA, DisabledStorage, EXCEEDED_COUNT, FSMContext, \ @@ -114,6 +114,11 @@ class Dispatcher(DataMixin, ContextInstanceMixin): filters_factory.bind(ExceptionsFilter, event_handlers=[ self.errors_handlers ]) + filters_factory.bind(IdFilter, event_handlers=[ + self.message_handlers, self.edited_message_handlers, + self.channel_post_handlers, self.edited_channel_post_handlers, + self.callback_query_handlers, self.inline_query_handlers + ]) def __del__(self): self.stop_polling() diff --git a/aiogram/dispatcher/filters/__init__.py b/aiogram/dispatcher/filters/__init__.py index 2ae959cf..eb4a5a52 100644 --- a/aiogram/dispatcher/filters/__init__.py +++ b/aiogram/dispatcher/filters/__init__.py @@ -1,5 +1,5 @@ from .builtin import Command, CommandHelp, CommandPrivacy, CommandSettings, CommandStart, ContentTypeFilter, \ - ExceptionsFilter, HashTag, Regexp, RegexpCommandsFilter, StateFilter, Text + ExceptionsFilter, HashTag, Regexp, RegexpCommandsFilter, StateFilter, Text, IdFilter from .factory import FiltersFactory from .filters import AbstractFilter, BoundFilter, Filter, FilterNotPassed, FilterRecord, execute_filter, \ check_filters, get_filter_spec, get_filters_spec @@ -23,6 +23,7 @@ __all__ = [ 'Regexp', 'StateFilter', 'Text', + 'IdFilter', 'get_filter_spec', 'get_filters_spec', 'execute_filter', diff --git a/aiogram/dispatcher/filters/builtin.py b/aiogram/dispatcher/filters/builtin.py index c68bae72..f3bbdba7 100644 --- a/aiogram/dispatcher/filters/builtin.py +++ b/aiogram/dispatcher/filters/builtin.py @@ -491,3 +491,69 @@ class ExceptionsFilter(BoundFilter): return True except: return False + + +class IdFilter(Filter): + + def __init__(self, + user_id: Optional[Union[str, int]] = None, + chat_id: Optional[Union[str, int]] = None, + ): + """ + :param user_id: + :param chat_id: + """ + if user_id is None and chat_id is None: + raise ValueError("Both user_id and chat_id can't be None") + + self.user_id = user_id + self.chat_id = chat_id + + # both params should be convertible to int if they aren't None + # here we checks it + # also, by default in Telegram chat_id and user_id are Integer, + # so for convenience we cast them to int + if self.user_id: + self.user_id = int(self.user_id) + if self.chat_id: + self.chat_id = int(self.chat_id) + + @classmethod + def validate(cls, full_config: typing.Dict[str, typing.Any]) -> typing.Optional[typing.Dict[str, typing.Any]]: + result = {} + if 'user' in full_config: + result['user_id'] = full_config.pop('user') + elif 'user_id' in full_config: + result['user_id'] = full_config.pop('user_id') + + if 'chat' in full_config: + result['chat_id'] = full_config.pop('chat') + elif 'chat_id' in full_config: + result['chat_id'] = full_config.pop('chat_id') + + return result + + async def check(self, obj: Union[Message, CallbackQuery, InlineQuery]): + if isinstance(obj, Message): + user_id = obj.from_user.id + chat_id = obj.chat.id + elif isinstance(obj, CallbackQuery): + user_id = obj.from_user.id + chat_id = None + if obj.message is not None: + # if the button was sent with message + chat_id = obj.message.chat.id + elif isinstance(obj, InlineQuery): + user_id = obj.from_user.id + chat_id = None + else: + return False + + if self.user_id and self.chat_id: + return self.user_id == user_id and self.chat_id == chat_id + elif self.user_id: + return self.user_id == user_id + elif self.chat_id: + return self.chat_id == chat_id + + return False From c1fc41bd7e4da3cbd2b070197001d70c4b761245 Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 04:16:30 +0300 Subject: [PATCH 2/7] Add example of usage of IdFilter --- examples/id-filter-example.py/tmp_test.py | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/id-filter-example.py/tmp_test.py diff --git a/examples/id-filter-example.py/tmp_test.py b/examples/id-filter-example.py/tmp_test.py new file mode 100644 index 00000000..297e23e4 --- /dev/null +++ b/examples/id-filter-example.py/tmp_test.py @@ -0,0 +1,46 @@ +from aiogram import Bot, Dispatcher, executor, types +from aiogram.dispatcher.handler import SkipHandler + +API_TOKEN = 'API_TOKE_HERE' +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) + +user_id_to_test = None # todo: Set id here +chat_id_to_test = user_id_to_test + + +@dp.message_handler(user=user_id_to_test) +async def handler1(msg: types.Message): + await bot.send_message(msg.chat.id, + "Hello, checking with user=") + raise SkipHandler + + +@dp.message_handler(user_id=user_id_to_test) +async def handler2(msg: types.Message): + await bot.send_message(msg.chat.id, + "Hello, checking with user_id=") + raise SkipHandler + + +@dp.message_handler(chat=chat_id_to_test) +async def handler3(msg: types.Message): + await bot.send_message(msg.chat.id, + "Hello, checking with chat=") + raise SkipHandler + + +@dp.message_handler(chat_id=chat_id_to_test) +async def handler4(msg: types.Message): + await bot.send_message(msg.chat.id, + "Hello, checking with chat_id=") + raise SkipHandler + + +@dp.message_handler(user=user_id_to_test, chat_id=chat_id_to_test) +async def handler5(msg: types.Message): + await bot.send_message(msg.chat.id, + "Hello from user= & chat_id=") + +if __name__ == '__main__': + executor.start_polling(dp) From 6a3c13ed50c720305f27958a9233cb00b93c0286 Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 04:21:16 +0300 Subject: [PATCH 3/7] Fix example directory --- .../{id-filter-example.py/tmp_test.py => id-filter-example.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{id-filter-example.py/tmp_test.py => id-filter-example.py} (100%) diff --git a/examples/id-filter-example.py/tmp_test.py b/examples/id-filter-example.py similarity index 100% rename from examples/id-filter-example.py/tmp_test.py rename to examples/id-filter-example.py From 6bbc808a3b2f08dd0882fb4e8c7c080f67383cca Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 04:33:55 +0300 Subject: [PATCH 4/7] Add support for a list of ids and update the example --- aiogram/dispatcher/filters/builtin.py | 33 ++++++++++++++------------- examples/id-filter-example.py | 6 +++++ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/aiogram/dispatcher/filters/builtin.py b/aiogram/dispatcher/filters/builtin.py index f3bbdba7..d64fb97a 100644 --- a/aiogram/dispatcher/filters/builtin.py +++ b/aiogram/dispatcher/filters/builtin.py @@ -496,8 +496,8 @@ class ExceptionsFilter(BoundFilter): class IdFilter(Filter): def __init__(self, - user_id: Optional[Union[str, int]] = None, - chat_id: Optional[Union[str, int]] = None, + user_id: Optional[Union[Iterable[Union[int, str]], str, int]] = None, + chat_id: Optional[Union[Iterable[Union[int, str]], str, int]] = None, ): """ :param user_id: @@ -506,17 +506,18 @@ class IdFilter(Filter): if user_id is None and chat_id is None: raise ValueError("Both user_id and chat_id can't be None") - self.user_id = user_id - self.chat_id = chat_id - - # both params should be convertible to int if they aren't None - # here we checks it - # also, by default in Telegram chat_id and user_id are Integer, - # so for convenience we cast them to int - if self.user_id: - self.user_id = int(self.user_id) - if self.chat_id: - self.chat_id = int(self.chat_id) + self.user_id = None + self.chat_id = None + if user_id: + if isinstance(user_id, Iterable): + self.user_id = list(map(int, user_id)) + else: + self.user_id = [int(user_id), ] + if chat_id: + if isinstance(chat_id, Iterable): + self.chat_id = list(map(int, chat_id)) + else: + self.chat_id = [int(chat_id), ] @classmethod def validate(cls, full_config: typing.Dict[str, typing.Any]) -> typing.Optional[typing.Dict[str, typing.Any]]: @@ -550,10 +551,10 @@ class IdFilter(Filter): return False if self.user_id and self.chat_id: - return self.user_id == user_id and self.chat_id == chat_id + return user_id in self.user_id and chat_id in self.chat_id elif self.user_id: - return self.user_id == user_id + return user_id in self.user_id elif self.chat_id: - return self.chat_id == chat_id + return chat_id in self.chat_id return False diff --git a/examples/id-filter-example.py b/examples/id-filter-example.py index 297e23e4..b46ab056 100644 --- a/examples/id-filter-example.py +++ b/examples/id-filter-example.py @@ -42,5 +42,11 @@ async def handler5(msg: types.Message): await bot.send_message(msg.chat.id, "Hello from user= & chat_id=") + +@dp.message_handler(user=[user_id_to_test, 123]) # todo: add second id here +async def handler6(msg: types.Message): + print("Checked with list!") + + if __name__ == '__main__': executor.start_polling(dp) From 4f72f5cb0592d33a1d66c731f175d768a78ad546 Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 04:36:13 +0300 Subject: [PATCH 5/7] Update docs --- docs/source/dispatcher/filters.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/dispatcher/filters.rst b/docs/source/dispatcher/filters.rst index d103ac36..e3149b8c 100644 --- a/docs/source/dispatcher/filters.rst +++ b/docs/source/dispatcher/filters.rst @@ -111,6 +111,14 @@ ExceptionsFilter :show-inheritance: +ExceptionsFilter +---------------- + +.. autoclass:: aiogram.dispatcher.filters.builtin.IdFilter + :members: + :show-inheritance: + + Making own filters (Custom filters) =================================== From 80b11684801446a4e457214738adde4be1018ccd Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 16:56:47 +0300 Subject: [PATCH 6/7] Fix docs and rename id-filter-example.py -> id_filter_example.py --- docs/source/dispatcher/filters.rst | 2 +- examples/{id-filter-example.py => id_filter_example.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/{id-filter-example.py => id_filter_example.py} (100%) diff --git a/docs/source/dispatcher/filters.rst b/docs/source/dispatcher/filters.rst index e3149b8c..af03e163 100644 --- a/docs/source/dispatcher/filters.rst +++ b/docs/source/dispatcher/filters.rst @@ -111,7 +111,7 @@ ExceptionsFilter :show-inheritance: -ExceptionsFilter +IdFilter ---------------- .. autoclass:: aiogram.dispatcher.filters.builtin.IdFilter diff --git a/examples/id-filter-example.py b/examples/id_filter_example.py similarity index 100% rename from examples/id-filter-example.py rename to examples/id_filter_example.py From 8b028693b6dfd932bef4b59e7af8e3dfe55b3e89 Mon Sep 17 00:00:00 2001 From: birdi Date: Mon, 22 Jul 2019 17:49:30 +0300 Subject: [PATCH 7/7] Remove user and chat arguments, update the example --- aiogram/dispatcher/filters/builtin.py | 8 ++------ examples/id_filter_example.py | 28 +++++++-------------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/aiogram/dispatcher/filters/builtin.py b/aiogram/dispatcher/filters/builtin.py index d64fb97a..5615964c 100644 --- a/aiogram/dispatcher/filters/builtin.py +++ b/aiogram/dispatcher/filters/builtin.py @@ -522,14 +522,10 @@ class IdFilter(Filter): @classmethod def validate(cls, full_config: typing.Dict[str, typing.Any]) -> typing.Optional[typing.Dict[str, typing.Any]]: result = {} - if 'user' in full_config: - result['user_id'] = full_config.pop('user') - elif 'user_id' in full_config: + if 'user_id' in full_config: result['user_id'] = full_config.pop('user_id') - if 'chat' in full_config: - result['chat_id'] = full_config.pop('chat') - elif 'chat_id' in full_config: + if 'chat_id' in full_config: result['chat_id'] = full_config.pop('chat_id') return result diff --git a/examples/id_filter_example.py b/examples/id_filter_example.py index b46ab056..64dc3b3f 100644 --- a/examples/id_filter_example.py +++ b/examples/id_filter_example.py @@ -9,43 +9,29 @@ user_id_to_test = None # todo: Set id here chat_id_to_test = user_id_to_test -@dp.message_handler(user=user_id_to_test) -async def handler1(msg: types.Message): - await bot.send_message(msg.chat.id, - "Hello, checking with user=") - raise SkipHandler - - @dp.message_handler(user_id=user_id_to_test) -async def handler2(msg: types.Message): +async def handler1(msg: types.Message): await bot.send_message(msg.chat.id, "Hello, checking with user_id=") raise SkipHandler -@dp.message_handler(chat=chat_id_to_test) -async def handler3(msg: types.Message): - await bot.send_message(msg.chat.id, - "Hello, checking with chat=") - raise SkipHandler - - @dp.message_handler(chat_id=chat_id_to_test) -async def handler4(msg: types.Message): +async def handler2(msg: types.Message): await bot.send_message(msg.chat.id, "Hello, checking with chat_id=") raise SkipHandler -@dp.message_handler(user=user_id_to_test, chat_id=chat_id_to_test) -async def handler5(msg: types.Message): +@dp.message_handler(user_id=user_id_to_test, chat_id=chat_id_to_test) +async def handler3(msg: types.Message): await bot.send_message(msg.chat.id, "Hello from user= & chat_id=") -@dp.message_handler(user=[user_id_to_test, 123]) # todo: add second id here -async def handler6(msg: types.Message): - print("Checked with list!") +@dp.message_handler(user_id=[user_id_to_test, 123]) # todo: add second id here +async def handler4(msg: types.Message): + print("Checked user_id with list!") if __name__ == '__main__':