Browse Source

Merge 5596d736fd into 26855160f8

pull/9924/merge
Soheab 1 month ago
committed by GitHub
parent
commit
4311cc4b62
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 9
      discord/app_commands/models.py
  2. 114
      discord/app_commands/tree.py

9
discord/app_commands/models.py

@ -309,6 +309,10 @@ class AppCommand(Hashable):
self.id, self.id,
) )
tree = self._state._command_tree
if tree:
tree._command_ids.get(self.guild_id, {}).pop(self.name, None)
async def edit( async def edit(
self, self,
*, *,
@ -392,6 +396,11 @@ class AppCommand(Hashable):
self.id, self.id,
payload, payload,
) )
tree = self._state._command_tree
if tree:
tree._update_command_ids(data)
return AppCommand(data=data, state=state) return AppCommand(data=data, state=state)
async def fetch_permissions(self, guild: Snowflake) -> GuildAppCommandPermissions: async def fetch_permissions(self, guild: Snowflake) -> GuildAppCommandPermissions:

114
discord/app_commands/tree.py

@ -68,6 +68,7 @@ from .._types import ClientT
if TYPE_CHECKING: if TYPE_CHECKING:
from ..types.interactions import ApplicationCommandInteractionData, ApplicationCommandInteractionDataOption from ..types.interactions import ApplicationCommandInteractionData, ApplicationCommandInteractionDataOption
from ..types.command import ApplicationCommand
from ..interactions import Interaction from ..interactions import Interaction
from ..abc import Snowflake from ..abc import Snowflake
from .commands import ContextMenuCallback, CommandCallback, P, T from .commands import ContextMenuCallback, CommandCallback, P, T
@ -132,6 +133,13 @@ class CommandTree(Generic[ClientT]):
Note that you can override this on a per command basis. Note that you can override this on a per command basis.
.. versionadded:: 2.4 .. versionadded:: 2.4
store_app_command_ids: :class:`bool`
Whether to store the application command IDs on the tree. These can be used to mention a command.
Defaults to ``False``.
This must be enabled if you want to use :meth:`get_command_mention` or :meth:`get_command_id`.
.. versionadded:: 2.5
""" """
def __init__( def __init__(
@ -141,6 +149,7 @@ class CommandTree(Generic[ClientT]):
fallback_to_global: bool = True, fallback_to_global: bool = True,
allowed_contexts: AppCommandContext = MISSING, allowed_contexts: AppCommandContext = MISSING,
allowed_installs: AppInstallationType = MISSING, allowed_installs: AppInstallationType = MISSING,
store_app_command_ids: bool = False,
): ):
self.client: ClientT = client self.client: ClientT = client
self._http = client.http self._http = client.http
@ -161,6 +170,9 @@ class CommandTree(Generic[ClientT]):
# it's uncommon and N=5 anyway. # it's uncommon and N=5 anyway.
self._context_menus: Dict[Tuple[str, Optional[int], int], ContextMenu] = {} self._context_menus: Dict[Tuple[str, Optional[int], int], ContextMenu] = {}
self.store_app_command_ids: bool = store_app_command_ids
self._command_ids: Dict[Optional[int], Dict[str, int]] = {}
async def fetch_command(self, command_id: int, /, *, guild: Optional[Snowflake] = None) -> AppCommand: async def fetch_command(self, command_id: int, /, *, guild: Optional[Snowflake] = None) -> AppCommand:
"""|coro| """|coro|
@ -198,6 +210,7 @@ class CommandTree(Generic[ClientT]):
else: else:
command = await self._http.get_guild_command(self.client.application_id, guild.id, command_id) command = await self._http.get_guild_command(self.client.application_id, guild.id, command_id)
self._update_command_ids(command)
return AppCommand(data=command, state=self._state) return AppCommand(data=command, state=self._state)
async def fetch_commands(self, *, guild: Optional[Snowflake] = None) -> List[AppCommand]: async def fetch_commands(self, *, guild: Optional[Snowflake] = None) -> List[AppCommand]:
@ -238,7 +251,91 @@ class CommandTree(Generic[ClientT]):
else: else:
commands = await self._http.get_guild_commands(self.client.application_id, guild.id) commands = await self._http.get_guild_commands(self.client.application_id, guild.id)
return [AppCommand(data=data, state=self._state) for data in commands] self._update_command_ids(*commands)
return [AppCommand(data=command, state=self._state) for command in commands]
def get_command_id(
self, command: Union[AppCommand, Command, ContextMenu, Group, str], /, *, guild: Optional[Snowflake] = None
) -> Optional[int]:
"""Gets the command ID for a command.
Parameters
-----------
name: Union[:class:`~discord.app_commands.Command`, :class:`~discord.app_commands.ContextMenu`, :class:`~discord.app_commands.Group`, :class:`str`]
The name of the command to get the ID for.
guild: Optional[:class:`~discord.abc.Snowflake`]
The guild to get the command ID for. If not passed then the global command
ID is fetched instead.
Returns
--------
Optional[:class:`int`]
The command ID if found, otherwise ``None``.
.. note::
Group commands will return the ID of the root command. Subcommands do not have their own IDs.
"""
name: Optional[str] = None
if isinstance(command, AppCommand):
return command.id
if isinstance(command, (Command, Group, ContextMenu)):
name = (command.root_parent or command).name if not isinstance(command, ContextMenu) else command.name
elif isinstance(command, str):
name = command.split()[0]
return self._command_ids.get(guild.id if guild else None, {}).get(name)
def get_command_mention(
self, command: Union[AppCommand, Command, ContextMenu, Group, str], /, *, guild: Optional[Snowflake] = None
) -> Optional[str]:
"""Gets the mention string for a command.
Parameters
-----------
command: Union[:class:`~discord.app_commands.Command`, :class:`~discord.app_commands.ContextMenu`, :class:`~discord.app_commands.Group`, :class:`str`]
The command to get the mention string for.
Returns
--------
Optional[:class:`str`]
The mention string for the command if found, otherwise ``None``.
.. note::
Remember that groups cannot be mentioned, only with a subcommand.
"""
if isinstance(command, AppCommand):
return command.mention
command_id = self.get_command_id(command, guild=guild)
if command_id is None:
return None
if isinstance(command, (Command, Group, ContextMenu)):
full_name = command.qualified_name
elif isinstance(command, str):
full_name = command
return f'</{full_name}:{command_id}>'
def get_command_ids(self, guild: Optional[Snowflake] = None) -> Dict[str, int]:
"""Gets all command IDs for the given guild.
Parameters
-----------
guild: Optional[:class:`~discord.abc.Snowflake`]
The guild to get the command IDs for. If not passed then the global command
IDs are returned instead.
Returns
--------
Dict[:class:`str`, :class:`int`]
A dictionary of command names and their IDs.
"""
return self._command_ids.get(guild.id if guild else None, {})
def copy_global_to(self, *, guild: Snowflake) -> None: def copy_global_to(self, *, guild: Snowflake) -> None:
"""Copies all global commands to the specified guild. """Copies all global commands to the specified guild.
@ -1134,8 +1231,22 @@ class CommandTree(Generic[ClientT]):
raise CommandSyncFailure(e, commands) from None raise CommandSyncFailure(e, commands) from None
raise raise
self._update_command_ids(*data)
return [AppCommand(data=d, state=self._state) for d in data] return [AppCommand(data=d, state=self._state) for d in data]
def _update_command_ids(self, *data: Union[ApplicationCommandInteractionData, ApplicationCommand]) -> None:
if not self.store_app_command_ids:
return
for d in data:
command_id: int = int(d['id'])
name: str = d['name']
guild_id: Optional[int] = _get_as_snowflake(d, 'guild_id')
try:
self._command_ids[guild_id][name] = command_id
except KeyError:
self._command_ids[guild_id] = {name: command_id}
async def _dispatch_error(self, interaction: Interaction[ClientT], error: AppCommandError, /) -> None: async def _dispatch_error(self, interaction: Interaction[ClientT], error: AppCommandError, /) -> None:
command = interaction.command command = interaction.command
interaction.command_failed = True interaction.command_failed = True
@ -1274,6 +1385,7 @@ class CommandTree(Generic[ClientT]):
return return
data: ApplicationCommandInteractionData = interaction.data # type: ignore data: ApplicationCommandInteractionData = interaction.data # type: ignore
self._update_command_ids(data)
type = data.get('type', 1) type = data.get('type', 1)
if type != 1: if type != 1:
# Context menu command... # Context menu command...

Loading…
Cancel
Save