Revamp bot commands and bot command scopes

Closes #777
This commit is contained in:
Dan 2022-03-28 13:23:12 +02:00
parent aa41ac5fd2
commit 7bfcd5ac5f
16 changed files with 543 additions and 95 deletions

View File

@ -288,6 +288,8 @@ def pyrogram_api():
set_game_score
get_game_high_scores
set_bot_commands
get_bot_commands
delete_bot_commands
""",
authorization="""
Authorization
@ -395,8 +397,8 @@ def pyrogram_api():
VoiceChatEnded
VoiceChatMembersInvited
""",
bots_keyboard="""
Bots & Keyboards
bot_keyboards="""
Bot keyboards
ReplyKeyboardMarkup
KeyboardButton
ReplyKeyboardRemove
@ -407,7 +409,18 @@ def pyrogram_api():
CallbackQuery
GameHighScore
CallbackGame
""",
bot_commands="""
Bot commands
BotCommand
BotCommandScope
BotCommandScopeDefault
BotCommandScopeAllPrivateChats
BotCommandScopeAllGroupChats
BotCommandScopeAllChatAdministrators
BotCommandScopeChat
BotCommandScopeChatAdministrators
BotCommandScopeChatMember
""",
input_media="""
Input Media

View File

@ -51,18 +51,31 @@ Messages & Media
{messages_media}
Bots & Keyboards
----------------
Bot keyboards
-------------
.. autosummary::
:nosignatures:
{bots_keyboard}
{bot_keyboards}
.. toctree::
:hidden:
{bots_keyboard}
{bot_keyboards}
Bot commands
-------------
.. autosummary::
:nosignatures:
{bot_commands}
.. toctree::
:hidden:
{bot_commands}
Input Media
-----------

View File

@ -18,6 +18,8 @@
from .answer_callback_query import AnswerCallbackQuery
from .answer_inline_query import AnswerInlineQuery
from .delete_bot_commands import DeleteBotCommands
from .get_bot_commands import GetBotCommands
from .get_game_high_scores import GetGameHighScores
from .get_inline_bot_results import GetInlineBotResults
from .request_callback_answer import RequestCallbackAnswer
@ -36,6 +38,8 @@ class Bots(
SendGame,
SetGameScore,
GetGameHighScores,
SetBotCommands
SetBotCommands,
GetBotCommands,
DeleteBotCommands
):
pass

View File

@ -0,0 +1,61 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw, types
from pyrogram.scaffold import Scaffold
class DeleteBotCommands(Scaffold):
async def delete_bot_commands(
self: "pyrogram.Client",
scope: "types.BotCommandScope" = types.BotCommandScopeDefault(),
language_code: str = "",
):
"""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.
The commands passed will overwrite any command set previously.
This method can be used by the own bot only.
Parameters:
scope (:obj:`~pyrogram.types.BotCommandScope`, *optional*):
An object describing the scope of users for which the commands are relevant.
Defaults to :obj:`~pyrogram.types.BotCommandScopeDefault`.
language_code (``str``, *optional*):
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.
Returns:
``bool``: On success, True is returned.
Example:
.. code-block:: python
# Delete commands
app.delete_bot_commands()
"""
return await self.send(
raw.functions.bots.ResetBotCommands(
scope=await scope.write(self),
lang_code=language_code,
)
)

View File

@ -0,0 +1,62 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw, types
from pyrogram.scaffold import Scaffold
class GetBotCommands(Scaffold):
async def get_bot_commands(
self: "pyrogram.Client",
scope: "types.BotCommandScope" = types.BotCommandScopeDefault(),
language_code: str = "",
):
"""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.
The commands passed will overwrite any command set previously.
This method can be used by the own bot only.
Parameters:
scope (:obj:`~pyrogram.types.BotCommandScope`, *optional*):
An object describing the scope of users for which the commands are relevant.
Defaults to :obj:`~pyrogram.types.BotCommandScopeDefault`.
language_code (``str``, *optional*):
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.
Returns:
List of :obj:`~pyrogram.types.BotCommand`: On success, the list of bot commands is returned.
Example:
.. code-block:: python
# Get commands
commands = app.get_bot_commands()
print(commands)
"""
return await self.send(
raw.functions.bots.GetBotCommands(
scope=await scope.write(self),
lang_code=language_code,
)
)

View File

@ -16,22 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import List, Optional
from typing import List
import pyrogram
from pyrogram import raw, types
from pyrogram.scaffold import Scaffold
class SetBotCommands(Scaffold):
async def set_bot_commands(
self,
commands: Optional[List[types.BotCommand]],
scope: types.BotCommandScope = types.BotCommandScope(
types.BotCommandScope.DEFAULT
),
lang_code: str = "",
self: "pyrogram.Client",
commands: List["types.BotCommand"],
scope: "types.BotCommandScope" = types.BotCommandScopeDefault(),
language_code: str = "",
):
"""Set the bot commands list.
"""Set the list of the bot's commands.
The commands passed will overwrite any command set previously.
This method can be used by the own bot only.
@ -39,10 +38,19 @@ class SetBotCommands(Scaffold):
Parameters:
commands (List of :obj:`~pyrogram.types.BotCommand`):
A list of bot commands.
Pass None to remove all commands.
At most 100 commands can be specified.
scope (:obj:`~pyrogram.types.BotCommandScope`, *optional*):
An object describing the scope of users for which the commands are relevant.
Defaults to :obj:`~pyrogram.types.BotCommandScopeDefault`.
language_code (``str``, *optional*):
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.
Returns:
``bool``: True on success, False otherwise.
``bool``: On success, True is returned.
Example:
.. code-block:: python
@ -53,15 +61,12 @@ class SetBotCommands(Scaffold):
app.set_bot_commands([
BotCommand("start", "Start the bot"),
BotCommand("settings", "Bot settings")])
# Remove commands
app.set_bot_commands(None)
"""
return await self.send(
raw.functions.bots.SetBotCommands(
commands=[c.write() for c in commands or []],
scope=scope.write(),
lang_code=lang_code,
commands=[c.write() for c in commands],
scope=await scope.write(self),
lang_code=language_code,
)
)

View File

@ -16,7 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .bot_command import BotCommand, BotCommandScope
from .bot_command import BotCommand
from .bot_command_scope import BotCommandScope
from .bot_command_scope_all_chat_administrators import BotCommandScopeAllChatAdministrators
from .bot_command_scope_all_group_chats import BotCommandScopeAllGroupChats
from .bot_command_scope_all_private_chats import BotCommandScopeAllPrivateChats
from .bot_command_scope_chat import BotCommandScopeChat
from .bot_command_scope_chat_administrators import BotCommandScopeChatAdministrators
from .bot_command_scope_chat_member import BotCommandScopeChatMember
from .bot_command_scope_default import BotCommandScopeDefault
from .callback_game import CallbackGame
from .callback_query import CallbackQuery
from .force_reply import ForceReply
@ -41,4 +49,11 @@ __all__ = [
"LoginUrl",
"BotCommand",
"BotCommandScope",
"BotCommandScopeAllChatAdministrators",
"BotCommandScopeAllGroupChats",
"BotCommandScopeAllPrivateChats",
"BotCommandScopeChat",
"BotCommandScopeChatAdministrators",
"BotCommandScopeChatMember",
"BotCommandScopeDefault",
]

View File

@ -26,10 +26,11 @@ class BotCommand(Object):
Parameters:
command (``str``):
The bot command, for example: "/start".
Text of the command; 1-32 characters.
Can contain only lowercase English letters, digits and underscores.
description (``str``):
Description of the bot command.
Description of the command; 1-256 characters.
"""
def __init__(self, command: str, description: str):
@ -38,77 +39,15 @@ class BotCommand(Object):
self.command = command
self.description = description
def write(self):
def write(self) -> "raw.types.BotCommand":
return raw.types.BotCommand(
command=self.command,
description=self.description,
)
class BotCommandScope(Object):
"""
Represents a scope where the bot commands, specified
using bots.setBotCommands will be valid.
Parameters:
scope (``str``):
- DEFAULT: The commands will be valid in all chats (default value)
- PRIVATE: The specified bot commands will only be valid in all private
chats with users.
- GROUP: The specified bot commands will be valid in all groups and supergroups
- GROUP_ADMINS: The specified bot commands will be valid only for chat
administrators, in all groups and supergroups.
- PEER: The specified bot commands will be valid only in a specific dialog
- PEER_ADMINS: The specified bot commands will be valid for all admins of the
specified group or supergroup.
- PEER_USER: The specified bot commands will be valid only for a specific user
in the specified chat
"""
DEFAULT = "default"
PRIVATE = "users"
GROUP = "chats"
GROUP_ADMINS = "chat_admins"
PEER = "peer"
PEER_ADMINS = "peer_admins"
PEER_USER = "peer_user"
raw_scopes = {
DEFAULT: raw.types.BotCommandScopeDefault,
PRIVATE: raw.types.BotCommandScopeUsers,
GROUP: raw.types.BotCommandScopeChats,
GROUP_ADMINS: raw.types.BotCommandScopeChatAdmins,
PEER: lambda peer: raw.types.BotCommandScopePeer(peer),
PEER_ADMINS: lambda peer: raw.types.BotCommandScopePeerAdmins(peer),
PEER_USER: lambda peer, user_id: raw.types.BotCommandScopePeerUser(
peer, user_id
),
}
def __init__(
self,
scope: str,
peer: raw.types.InputPeerUser = None,
user_id: raw.types.InputUser = None,
):
super().__init__()
self.scope = scope
self.peer = peer
self.user_id = user_id
def write(self):
if self.scope in ["peer", "peer_admins"]:
return self.raw_scopes[self.scope](self.peer)
elif self.scope == "peer_user":
return self.raw_scopes[self.scopes](self.peer, self.user_id)
return self.raw_scopes[self.scope]()
@staticmethod
def read(c: "raw.types.BotCommand") -> "BotCommand":
return BotCommand(
command=c.command,
description=c.description
)

View File

@ -0,0 +1,73 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from ..object import Object
class BotCommandScope(Object):
"""Represents the scope to which bot commands are applied.
Currently, the following 7 scopes are supported:
- :obj:`~pyrogram.types.BotCommandScopeDefault`
- :obj:`~pyrogram.types.BotCommandScopeAllPrivateChats`
- :obj:`~pyrogram.types.BotCommandScopeAllGroupChats`
- :obj:`~pyrogram.types.BotCommandScopeAllChatAdministrators`
- :obj:`~pyrogram.types.BotCommandScopeChat`
- :obj:`~pyrogram.types.BotCommandScopeChatAdministrators`
- :obj:`~pyrogram.types.BotCommandScopeChatMember`
**Determining list of commands**
The following algorithm is used to determine the list of commands for a particular user viewing the bot menu.
The first list of commands which is set is returned:
**Commands in the chat with the bot**:
- BotCommandScopeChat + language_code
- BotCommandScopeChat
- BotCommandScopeAllPrivateChats + language_code
- BotCommandScopeAllPrivateChats
- BotCommandScopeDefault + language_code
- BotCommandScopeDefault
**Commands in group and supergroup chats**
- BotCommandScopeChatMember + language_code
- BotCommandScopeChatMember
- BotCommandScopeChatAdministrators + language_code (administrators only)
- BotCommandScopeChatAdministrators (administrators only)
- BotCommandScopeChat + language_code
- BotCommandScopeChat
- BotCommandScopeAllChatAdministrators + language_code (administrators only)
- BotCommandScopeAllChatAdministrators (administrators only)
- BotCommandScopeAllGroupChats + language_code
- BotCommandScopeAllGroupChats
- BotCommandScopeDefault + language_code
- BotCommandScopeDefault
"""
def __init__(self, type: str):
super().__init__()
self.type = type
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
raise NotImplementedError

View File

@ -0,0 +1,32 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeAllChatAdministrators(BotCommandScope):
"""Represents the scope of bot commands, covering all group and supergroup chat administrators.
"""
def __init__(self):
super().__init__("all_chat_administrators")
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopeChatAdmins()

View File

@ -0,0 +1,32 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeAllGroupChats(BotCommandScope):
"""Represents the scope of bot commands, covering all group and supergroup chats.
"""
def __init__(self):
super().__init__("all_group_chats")
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopeChats()

View File

@ -0,0 +1,32 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeAllPrivateChats(BotCommandScope):
"""Represents the scope of bot commands, covering all private chats.
"""
def __init__(self):
super().__init__("all_private_chats")
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopeUsers()

View File

@ -0,0 +1,43 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeChat(BotCommandScope):
"""Represents the scope of bot commands, covering a specific chat.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier for the target chat or username of the target supergroup (in the format
@supergroupusername).
"""
def __init__(self, chat_id: Union[int, str]):
super().__init__("chat")
self.chat_id = chat_id
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopePeer(
peer=await client.resolve_peer(self.chat_id)
)

View File

@ -0,0 +1,43 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeChatAdministrators(BotCommandScope):
"""Represents the scope of bot commands, covering all administrators of a specific group or supergroup chat.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier for the target chat or username of the target supergroup (in the format
@supergroupusername).
"""
def __init__(self, chat_id: Union[int, str]):
super().__init__("chat_administrators")
self.chat_id = chat_id
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopePeerAdmins(
peer=await client.resolve_peer(self.chat_id)
)

View File

@ -0,0 +1,48 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
class BotCommandScopeChatMember(BotCommandScope):
"""Represents the scope of bot commands, covering a specific member of a group or supergroup chat.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier for the target chat or username of the target supergroup (in the format
@supergroupusername).
user_id (``int`` | ``str``):
Unique identifier of the target user.
"""
def __init__(self, chat_id: Union[int, str], user_id: Union[int, str]):
super().__init__("chat_member")
self.chat_id = chat_id
self.user_id = user_id
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopePeerUser(
peer=await client.resolve_peer(self.chat_id),
user_id=await client.resolve_peer(self.user_id)
)

View File

@ -0,0 +1,33 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from .bot_command_scope import BotCommandScope
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.
"""
def __init__(self):
super().__init__("default")
async def write(self, client: "pyrogram.Client") -> "raw.base.BotCommandScope":
return raw.types.BotCommandScopeDefault()