From 6b026f238d9c9df1362ee3e76bfed26998364540 Mon Sep 17 00:00:00 2001 From: Soheab_ <33902984+Soheab@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:23:55 +0100 Subject: [PATCH 1/4] Add fields for Entry Point Command --- discord/app_commands/models.py | 24 ++++++++++++++++++++++++ discord/enums.py | 6 ++++++ discord/types/command.py | 12 +++++++++++- docs/interactions/api.rst | 20 ++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index e8a96784b87c..793a1911513b 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -35,6 +35,7 @@ AppCommandPermissionType, ChannelType, Locale, + EntryPointCommandHandlerType, try_enum, ) from ..mixins import Hashable @@ -181,6 +182,10 @@ class AppCommand(Hashable): denotes that it is a global command. nsfw: :class:`bool` Whether the command is NSFW and should only work in NSFW channels. + handler: Optional[:class:`~discord.EntryPointCommandHandlerType`] + Determines whether the interaction is handled by the app's interactions handler or by Discord. + + This is only available for commands with type :attr:`~discord.AppCommandType.primary_entry_point`. """ __slots__ = ( @@ -198,6 +203,7 @@ class AppCommand(Hashable): 'allowed_contexts', 'allowed_installs', 'nsfw', + 'handler', '_state', ) @@ -245,6 +251,11 @@ def _from_data(self, data: ApplicationCommandPayload) -> None: self.name_localizations: Dict[Locale, str] = _to_locale_dict(data.get('name_localizations') or {}) self.description_localizations: Dict[Locale, str] = _to_locale_dict(data.get('description_localizations') or {}) + handler = data.get('handler') + self.handler: Optional[EntryPointCommandHandlerType] = None # type: ignore + if handler is not None: + self.handler: EntryPointCommandHandlerType = try_enum(EntryPointCommandHandlerType, handler) + def to_dict(self) -> ApplicationCommandPayload: return { 'id': self.id, @@ -433,6 +444,19 @@ async def fetch_permissions(self, guild: Snowflake) -> GuildAppCommandPermission ) return GuildAppCommandPermissions(data=data, state=state, command=self) + def is_default_entry_point_command(self) -> bool: + """:class:`bool`: Returns ``True`` if the command is the default entry point command. + + This is determined by the command's name and handler type. + More information can be found in the :ddocs:`official Discord + documentation `. + """ + return ( + self.type is AppCommandType.primary_entry_point + and self.name.casefold() == 'launch' + and self.handler is EntryPointCommandHandlerType.discord_launch_activity + ) + class Choice(Generic[ChoiceT]): """Represents an application command argument choice. diff --git a/discord/enums.py b/discord/enums.py index 4fe5f3ffae1e..c49feb7cd15f 100644 --- a/discord/enums.py +++ b/discord/enums.py @@ -767,6 +767,7 @@ class AppCommandType(Enum): chat_input = 1 user = 2 message = 3 + primary_entry_point = 4 class AppCommandPermissionType(Enum): @@ -862,6 +863,11 @@ class SubscriptionStatus(Enum): inactive = 2 +class EntryPointCommandHandlerType(Enum): + app_handler = 1 + discord_launch_activity = 2 + + def create_unknown_value(cls: Type[E], val: Any) -> E: value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below name = f'unknown_{val}' diff --git a/discord/types/command.py b/discord/types/command.py index 7876ee6ddf0e..618fd1a93ebe 100644 --- a/discord/types/command.py +++ b/discord/types/command.py @@ -31,7 +31,7 @@ from .snowflake import Snowflake from .interactions import InteractionContextType -ApplicationCommandType = Literal[1, 2, 3] +ApplicationCommandType = Literal[1, 2, 3, 4] ApplicationCommandOptionType = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] ApplicationIntegrationType = Literal[0, 1] @@ -162,6 +162,15 @@ class _ChatInputApplicationCommand(_BaseApplicationCommand, total=False): ] +EntryPointCommandHandlerType = Literal[1, 2] + + +class _PrimaryEntryPointApplicationCommand(_BaseApplicationCommand): + description: Required[str] + type: Literal[4] + handler: EntryPointCommandHandlerType + + class _BaseContextMenuApplicationCommand(_BaseApplicationCommand): description: Literal[""] @@ -178,6 +187,7 @@ class _MessageApplicationCommand(_BaseContextMenuApplicationCommand): _ChatInputApplicationCommand, _UserApplicationCommand, _MessageApplicationCommand, + _PrimaryEntryPointApplicationCommand, ] diff --git a/docs/interactions/api.rst b/docs/interactions/api.rst index aeb6a25c613d..8f2aba5fe659 100644 --- a/docs/interactions/api.rst +++ b/docs/interactions/api.rst @@ -430,6 +430,11 @@ Enumerations .. attribute:: message A message context menu command. + .. attribute:: primary_entry_point + + .. versionadded:: 2.5 + + A command that represents the primary way to invoke an app's Activity .. class:: AppCommandPermissionType @@ -447,6 +452,21 @@ Enumerations The permission is for a user. +.. class:: EntryPointCommandHandlerType + + Represents the type of an entry point command handler. + + .. versionadded:: 2.5 + + .. attribute:: app_handler + + The app handles the interaction using an interaction token. + + .. attribute:: discord_launch_activity + + Discord handles the interaction by launching an Activity and + sending a follow-up message without coordinating with the app. + .. _discord_ui_kit: Bot UI Kit From 312f4fdfe28cf0585e014eb2b2b1346d4d21b540 Mon Sep 17 00:00:00 2001 From: Soheab_ <33902984+Soheab@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:47:19 +0100 Subject: [PATCH 2/4] command is the command? --- discord/app_commands/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index 793a1911513b..6ec0b162ef03 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -445,7 +445,7 @@ async def fetch_permissions(self, guild: Snowflake) -> GuildAppCommandPermission return GuildAppCommandPermissions(data=data, state=state, command=self) def is_default_entry_point_command(self) -> bool: - """:class:`bool`: Returns ``True`` if the command is the default entry point command. + """:class:`bool`: Returns ``True`` if this is the default entry point command. This is determined by the command's name and handler type. More information can be found in the :ddocs:`official Discord From 2615300dfa1e9165d15d544611141452f5ba5b7c Mon Sep 17 00:00:00 2001 From: Soheab_ <33902984+Soheab@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:53:38 +0100 Subject: [PATCH 3/4] Add handler to edit & to_dict --- discord/app_commands/models.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index 6ec0b162ef03..d988614ad41b 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -252,9 +252,11 @@ def _from_data(self, data: ApplicationCommandPayload) -> None: self.description_localizations: Dict[Locale, str] = _to_locale_dict(data.get('description_localizations') or {}) handler = data.get('handler') - self.handler: Optional[EntryPointCommandHandlerType] = None # type: ignore - if handler is not None: - self.handler: EntryPointCommandHandlerType = try_enum(EntryPointCommandHandlerType, handler) + if handler is None: + self.handler = None + else: + self.handler = try_enum(EntryPointCommandHandlerType, handler) + def to_dict(self) -> ApplicationCommandPayload: return { @@ -268,6 +270,7 @@ def to_dict(self) -> ApplicationCommandPayload: 'contexts': self.allowed_contexts.to_array() if self.allowed_contexts is not None else None, 'integration_types': self.allowed_installs.to_array() if self.allowed_installs is not None else None, 'options': [opt.to_dict() for opt in self.options], + 'handler': self.handler.value if self.handler is not None else None, } # type: ignore # Type checker does not understand this literal. def __str__(self) -> str: @@ -328,6 +331,7 @@ async def edit( default_member_permissions: Optional[Permissions] = MISSING, dm_permission: bool = MISSING, options: List[Union[Argument, AppCommandGroup]] = MISSING, + handler: Optional[EntryPointCommandHandlerType] = MISSING, ) -> AppCommand: """|coro| @@ -346,6 +350,10 @@ async def edit( Indicates if the application command can be used in DMs. options: List[Union[:class:`Argument`, :class:`AppCommandGroup`]] List of new options for this application command. + handler: Optional[:class:`~discord.EntryPointCommandHandlerType`] + Determines whether the interaction is handled by the app's interactions handler or by Discord. + + Only available for commands with type :attr:`~discord.AppCommandType.primary_entry_point`. Raises ------- @@ -387,6 +395,9 @@ async def edit( if options is not MISSING: payload['options'] = [option.to_dict() for option in options] + if handler is not MISSING: + payload['handler'] = handler + if not payload: return self From b98aefc62aad90061d1cd5d676feeb9ea8238757 Mon Sep 17 00:00:00 2001 From: Soheab_ <33902984+Soheab@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:27:27 +0100 Subject: [PATCH 4/4] Run black --- discord/app_commands/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index d988614ad41b..fd92a1a5da4c 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -256,7 +256,6 @@ def _from_data(self, data: ApplicationCommandPayload) -> None: self.handler = None else: self.handler = try_enum(EntryPointCommandHandlerType, handler) - def to_dict(self) -> ApplicationCommandPayload: return {