diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index 10ae7fdf..f41ca551 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -250,6 +250,7 @@ class Methods(Helper): DELETE_CHAT_STICKER_SET = Item() # deleteChatStickerSet ANSWER_CALLBACK_QUERY = Item() # answerCallbackQuery SET_MY_COMMANDS = Item() # setMyCommands + DELETE_MY_COMMANDS = Item() # deleteMyCommands GET_MY_COMMANDS = Item() # getMyCommands # Updating messages diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 07d4b963..8bd153b9 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -2241,31 +2241,95 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.ANSWER_CALLBACK_QUERY, payload) - async def set_my_commands(self, commands: typing.List[types.BotCommand]) -> base.Boolean: + async def set_my_commands(self, + commands: typing.List[types.BotCommand], + scope: typing.Optional[types.BotCommandScope] = None, + language_code: typing.Optional[base.String] = None, + ) -> base.Boolean: """ Use this method to change the list of the bot's commands. Source: https://core.telegram.org/bots/api#setmycommands - :param commands: A JSON-serialized list of bot commands to be set as the list of the bot's commands. - At most 100 commands can be specified. + :param commands: A JSON-serialized list of bot commands to be + set as the list of the bot's commands. At most 100 commands + can be specified. :type commands: :obj: `typing.List[types.BotCommand]` + + :param scope: A JSON-serialized object, describing scope of + users for which the commands are relevant. Defaults to + BotCommandScopeDefault. + :type scope: :obj: `typing.Optional[types.BotCommandScope]` + + :param language_code: A two-letter ISO 639-1 language code. If + empty, commands will be applied to all users from the given + scope, for whose language there are no dedicated commands + :type language_code: :obj: `typing.Optional[base.String]` + :return: Returns True on success. :rtype: :obj:`base.Boolean` """ commands = prepare_arg(commands) + scope = prepare_arg(scope) payload = generate_payload(**locals()) return await self.request(api.Methods.SET_MY_COMMANDS, payload) - async def get_my_commands(self) -> typing.List[types.BotCommand]: + async def delete_my_commands(self, + scope: typing.Optional[types.BotCommandScope] = None, + language_code: typing.Optional[base.String] = None, + ) -> base.Boolean: """ - Use this method to get the current list of the bot's commands. + Use this method to delete the list of the bot's commands for the + given scope and user language. After deletion, higher level + commands will be shown to affected users. + + Source: https://core.telegram.org/bots/api#deletemycommands + + :param scope: A JSON-serialized object, describing scope of + users for which the commands are relevant. Defaults to + BotCommandScopeDefault. + :type scope: :obj: `typing.Optional[types.BotCommandScope]` + + :param language_code: A two-letter ISO 639-1 language code. If + empty, commands will be applied to all users from the given + scope, for whose language there are no dedicated commands + :type language_code: :obj: `typing.Optional[base.String]` + + :return: Returns True on success. + :rtype: :obj:`base.Boolean` + """ + scope = prepare_arg(scope) + payload = generate_payload(**locals()) + + return await self.request(api.Methods.DELETE_MY_COMMANDS, payload) + + async def get_my_commands(self, + scope: typing.Optional[types.BotCommandScope] = None, + language_code: typing.Optional[base.String] = None, + ) -> typing.List[types.BotCommand]: + """ + Use this method to get the current list of the bot's commands + for the given scope and user language. Returns Array of + BotCommand on success. If commands aren't set, an empty list is + returned. Source: https://core.telegram.org/bots/api#getmycommands - :return: Returns Array of BotCommand on success. + + :param scope: A JSON-serialized object, describing scope of + users for which the commands are relevant. Defaults to + BotCommandScopeDefault. + :type scope: :obj: `typing.Optional[types.BotCommandScope]` + + :param language_code: A two-letter ISO 639-1 language code. If + empty, commands will be applied to all users from the given + scope, for whose language there are no dedicated commands + :type language_code: :obj: `typing.Optional[base.String]` + + :return: Returns Array of BotCommand on success or empty list. :rtype: :obj:`typing.List[types.BotCommand]` """ + scope = prepare_arg(scope) payload = generate_payload(**locals()) result = await self.request(api.Methods.GET_MY_COMMANDS, payload) diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index 90909e81..648a2e6f 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -4,6 +4,10 @@ from .animation import Animation from .audio import Audio from .auth_widget_data import AuthWidgetData from .bot_command import BotCommand +from .bot_command_scope import BotCommandScope, BotCommandScopeAllChatAdministrators, \ + BotCommandScopeAllGroupChats, BotCommandScopeAllPrivateChats, BotCommandScopeChat, \ + BotCommandScopeChatAdministrators, BotCommandScopeChatMember, \ + BotCommandScopeDefault, BotCommandScopeTypes from .callback_game import CallbackGame from .callback_query import CallbackQuery from .chat import Chat, ChatActions, ChatType @@ -82,6 +86,15 @@ __all__ = ( 'Audio', 'AuthWidgetData', 'BotCommand', + 'BotCommandScope', + 'BotCommandScopeAllChatAdministrators', + 'BotCommandScopeAllGroupChats', + 'BotCommandScopeAllPrivateChats', + 'BotCommandScopeChat', + 'BotCommandScopeChatAdministrators', + 'BotCommandScopeChatMember', + 'BotCommandScopeDefault', + 'BotCommandScopeTypes', 'CallbackGame', 'CallbackQuery', 'Chat', diff --git a/aiogram/types/bot_command_scope.py b/aiogram/types/bot_command_scope.py new file mode 100644 index 00000000..f5dedd5d --- /dev/null +++ b/aiogram/types/bot_command_scope.py @@ -0,0 +1,103 @@ +import typing + +from . import base, fields +from ..utils import helper + + +class BotCommandScopeTypes(helper.Helper): + mode = helper.HelperMode.lowercase + + DEFAULT = helper.Item() # default + ALL_PRIVATE_CHATS = helper.Item() # all_private_chats + ALL_GROUP_CHATS = helper.Item() # all_group_chats + ALL_CHAT_ADMINISTRATORS = helper.Item() # all_chat_administrators + CHAT = helper.Item() # chat + CHAT_ADMINISTRATORS = helper.Item() # chat_administrators + CHAT_MEMBER = helper.Item() # chat_member + + +class BotCommandScope(base.TelegramObject): + """ + This object represents the scope to which bot commands are applied. + Currently, the following 7 scopes are supported: + BotCommandScopeDefault + BotCommandScopeAllPrivateChats + BotCommandScopeAllGroupChats + BotCommandScopeAllChatAdministrators + BotCommandScopeChat + BotCommandScopeChatAdministrators + BotCommandScopeChatMember + + https://core.telegram.org/bots/api#botcommandscope + """ + type: base.String = fields.Field() + + +class BotCommandScopeDefault(BotCommandScope): + """ + Represents the default scope of bot commands. + Default commands are used if no commands with a narrower scope are + specified for the user. + """ + type = fields.Field(default=BotCommandScopeTypes.DEFAULT) + + +class BotCommandScopeAllPrivateChats(BotCommandScope): + """ + Represents the scope of bot commands, covering all private chats. + """ + type = fields.Field(default=BotCommandScopeTypes.ALL_PRIVATE_CHATS) + + +class BotCommandScopeAllGroupChats(BotCommandScope): + """ + Represents the scope of bot commands, covering all group and + supergroup chats. + """ + type = fields.Field(default=BotCommandScopeTypes.ALL_GROUP_CHATS) + + +class BotCommandScopeAllChatAdministrators(BotCommandScope): + """ + Represents the scope of bot commands, covering all group and + supergroup chat administrators. + """ + type = fields.Field(default=BotCommandScopeTypes.ALL_CHAT_ADMINISTRATORS) + + +class BotCommandScopeChat(BotCommandScope): + """ + Represents the scope of bot commands, covering a specific chat. + """ + type = fields.Field(default=BotCommandScopeTypes.CHAT) + chat_id: typing.Union[base.String, base.Integer] = fields.Field() + + def __init__(self, chat_id: typing.Union[base.String, base.Integer], **kwargs): + super().__init__(chat_id=chat_id, **kwargs) + + +class BotCommandScopeChatAdministrators(BotCommandScopeChat): + """ + Represents the scope of bot commands, covering all administrators + of a specific group or supergroup chat. + """ + type = fields.Field(default=BotCommandScopeTypes.CHAT_ADMINISTRATORS) + chat_id: typing.Union[base.String, base.Integer] = fields.Field() + + +class BotCommandScopeChatMember(BotCommandScopeChat): + """ + Represents the scope of bot commands, covering a specific member of + a group or supergroup chat. + """ + type = fields.Field(default=BotCommandScopeTypes.CHAT_MEMBER) + chat_id: typing.Union[base.String, base.Integer] = fields.Field() + user_id: base.Integer = fields.Field() + + def __init__( + self, + chat_id: typing.Union[base.String, base.Integer], + user_id: base.Integer, + **kwargs, + ): + super().__init__(chat_id=chat_id, user_id=user_id, **kwargs)