Browse Source

Merge 5596d736fd into 26855160f8

pull/9924/merge
Soheab 4 weeks 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,
)
tree = self._state._command_tree
if tree:
tree._command_ids.get(self.guild_id, {}).pop(self.name, None)
async def edit(
self,
*,
@ -392,6 +396,11 @@ class AppCommand(Hashable):
self.id,
payload,
)
tree = self._state._command_tree
if tree:
tree._update_command_ids(data)
return AppCommand(data=data, state=state)
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:
from ..types.interactions import ApplicationCommandInteractionData, ApplicationCommandInteractionDataOption
from ..types.command import ApplicationCommand
from ..interactions import Interaction
from ..abc import Snowflake
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.
.. 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__(
@ -141,6 +149,7 @@ class CommandTree(Generic[ClientT]):
fallback_to_global: bool = True,
allowed_contexts: AppCommandContext = MISSING,
allowed_installs: AppInstallationType = MISSING,
store_app_command_ids: bool = False,
):
self.client: ClientT = client
self._http = client.http
@ -161,6 +170,9 @@ class CommandTree(Generic[ClientT]):
# it's uncommon and N=5 anyway.
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:
"""|coro|
@ -198,6 +210,7 @@ class CommandTree(Generic[ClientT]):
else:
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)
async def fetch_commands(self, *, guild: Optional[Snowflake] = None) -> List[AppCommand]:
@ -238,7 +251,91 @@ class CommandTree(Generic[ClientT]):
else:
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:
"""Copies all global commands to the specified guild.
@ -1134,8 +1231,22 @@ class CommandTree(Generic[ClientT]):
raise CommandSyncFailure(e, commands) from None
raise
self._update_command_ids(*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:
command = interaction.command
interaction.command_failed = True
@ -1274,6 +1385,7 @@ class CommandTree(Generic[ClientT]):
return
data: ApplicationCommandInteractionData = interaction.data # type: ignore
self._update_command_ids(data)
type = data.get('type', 1)
if type != 1:
# Context menu command...

Loading…
Cancel
Save