diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 6e3aacc5..150e8019 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, IdFilter, AdminFilter + RegexpCommandsFilter, StateFilter, Text, IDFilter, AdminFilter from .handler import Handler from .middlewares import MiddlewareManager from .storage import BaseStorage, DELTA, DisabledStorage, EXCEEDED_COUNT, FSMContext, \ @@ -114,7 +114,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin): filters_factory.bind(ExceptionsFilter, event_handlers=[ self.errors_handlers ]) - filters_factory.bind(IdFilter, event_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 diff --git a/aiogram/dispatcher/filters/__init__.py b/aiogram/dispatcher/filters/__init__.py index b9174ee6..3f202915 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, IdFilter, AdminFilter + ExceptionsFilter, HashTag, Regexp, RegexpCommandsFilter, StateFilter, Text, IDFilter, AdminFilter from .factory import FiltersFactory from .filters import AbstractFilter, BoundFilter, Filter, FilterNotPassed, FilterRecord, execute_filter, \ check_filters, get_filter_spec, get_filters_spec @@ -23,7 +23,7 @@ __all__ = [ 'Regexp', 'StateFilter', 'Text', - 'IdFilter', + 'IDFilter', 'AdminFilter', 'get_filter_spec', 'get_filters_spec', diff --git a/aiogram/dispatcher/filters/builtin.py b/aiogram/dispatcher/filters/builtin.py index 65dd595c..c84ddca4 100644 --- a/aiogram/dispatcher/filters/builtin.py +++ b/aiogram/dispatcher/filters/builtin.py @@ -9,7 +9,7 @@ from babel.support import LazyProxy from aiogram import types from aiogram.dispatcher.filters.filters import BoundFilter, Filter -from aiogram.types import CallbackQuery, Message, InlineQuery, Poll +from aiogram.types import CallbackQuery, Message, InlineQuery, Poll, ChatType class Command(Filter): @@ -571,34 +571,50 @@ class AdminFilter(Filter): chat_id is required for InlineQuery. """ - def __init__(self, admin_chat_id: typing.Optional[int] = None, admin_current_chat: typing.Optional[bool] = False): - self.chat_id = admin_chat_id - self.check_current_chat = admin_current_chat + def __init__(self, is_chat_admin: Optional[Union[Iterable[Union[int, str]], str, int, bool]] = None): + self._all_chats = False + self.chat_ids = None + + if is_chat_admin is False: + raise ValueError("is_chat_admin cannot be False") + + if is_chat_admin: + if isinstance(is_chat_admin, bool): + self._all_chats = is_chat_admin + if isinstance(is_chat_admin, Iterable): + self.chat_ids = list(map(int, is_chat_admin)) + else: + self.chat_ids = [int(is_chat_admin)] + else: + self._all_chats = True @classmethod def validate(cls, full_config: typing.Dict[str, typing.Any]) -> typing.Optional[typing.Dict[str, typing.Any]]: result = {} - if "admin_chat_id" in full_config: # use prefix 'admin' to not conflict with IdFilter - result["admin_chat_id"] = full_config.pop("admin_chat_id") - if "admin_current_chat" in full_config: # set True if need to check current chat - result["admin_current_chat"] = full_config.pop("admin_current_chat") + if "is_chat_admin" in full_config: + result["is_chat_admin"] = full_config.pop("is_chat_admin") return result async def check(self, obj: Union[Message, CallbackQuery, InlineQuery]) -> bool: user_id = obj.from_user.id - chat_id = self.chat_id + chat_ids = None + + if self._all_chats: + if ChatType.is_private(obj): # there is no admin in private chats + return False - if not chat_id or self.check_current_chat: if isinstance(obj, Message): - chat_id = obj.chat.id + chat_ids = [obj.chat.id] elif isinstance(obj, CallbackQuery): if obj.message: - chat_id = obj.message.chat.id + chat_ids = [obj.message.chat.id] else: - raise ValueError("Cannot get current chat in a InlineQuery") + return False + else: + chat_ids = self.chat_ids - admins = [member.user.id for member in await obj.bot.get_chat_administrators(chat_id)] + admins = [member.user.id for chat_id in chat_ids for member in await obj.bot.get_chat_administrators(chat_id)] return user_id in admins diff --git a/docs/source/dispatcher/filters.rst b/docs/source/dispatcher/filters.rst index af03e163..059a4f06 100644 --- a/docs/source/dispatcher/filters.rst +++ b/docs/source/dispatcher/filters.rst @@ -111,10 +111,18 @@ ExceptionsFilter :show-inheritance: -IdFilter +IDFilter ---------------- -.. autoclass:: aiogram.dispatcher.filters.builtin.IdFilter +.. autoclass:: aiogram.dispatcher.filters.builtin.IDFilter + :members: + :show-inheritance: + + +AdminFilter +---------------- + +.. autoclass:: aiogram.dispatcher.filters.builtin.AdminFilter :members: :show-inheritance: diff --git a/examples/admin_filter_example.py b/examples/admin_filter_example.py index 052f8efe..ec8746bb 100644 --- a/examples/admin_filter_example.py +++ b/examples/admin_filter_example.py @@ -2,26 +2,31 @@ import logging from aiogram import Bot, Dispatcher, types, executor -API_TOKEN = 'API TOKEN HERE' +API_TOKEN = 'API_TOKEN_HERE' + logging.basicConfig(level=logging.DEBUG) bot = Bot(token=API_TOKEN) dp = Dispatcher(bot=bot) -chat_id = -1001241113577 - # checks specified chat -@dp.message_handler(admin_chat_id=chat_id) -async def handler(msg: types.Message): - await msg.reply(f"You are an admin of the chat '{chat_id}'", reply=False) +@dp.message_handler(is_chat_admin=-1001241113577) +async def handle_specified(msg: types.Message): + await msg.answer("You are an admin of the specified chat!") + + +# checks multiple chats +@dp.message_handler(is_chat_admin=[-1001241113577, -320463906]) +async def handle_multiple(msg: types.Message): + await msg.answer("You are an admin of multiple chats!") # checks current chat -@dp.message_handler(admin_current_chat=True) -async def handler(msg: types.Message): - await msg.reply("You are an admin of the current chat!", reply=False) +@dp.message_handler(is_chat_admin=True) +async def handler3(msg: types.Message): + await msg.answer("You are an admin of the current chat!") if __name__ == '__main__':