From e79895d82432e982b96f842d4dcfedb7943d1044 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Fri, 1 Apr 2022 11:15:15 -0400 Subject: [PATCH] Add Message.interaction and MessageInteraction type Fix #7819 --- discord/message.py | 81 ++++++++++++++++++++++++++++++++++- discord/types/interactions.py | 6 ++- docs/interactions/api.rst | 8 ++++ 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/discord/message.py b/discord/message.py index d7530e12c..f1272b228 100644 --- a/discord/message.py +++ b/discord/message.py @@ -48,7 +48,7 @@ from . import utils from .reaction import Reaction from .emoji import Emoji from .partial_emoji import PartialEmoji -from .enums import MessageType, ChannelType, try_enum +from .enums import InteractionType, MessageType, ChannelType, try_enum from .errors import HTTPException from .components import _component_factory from .embeds import Embed @@ -74,6 +74,8 @@ if TYPE_CHECKING: MessageActivity as MessageActivityPayload, ) + from .types.interactions import MessageInteraction as MessageInteractionPayload + from .types.components import Component as ComponentPayload from .types.threads import ThreadArchiveDuration from .types.member import ( @@ -100,6 +102,7 @@ __all__ = ( 'Attachment', 'Message', 'PartialMessage', + 'MessageInteraction', 'MessageReference', 'DeletedReferencedMessage', ) @@ -511,6 +514,65 @@ class MessageReference: to_message_reference_dict = to_dict +class MessageInteraction(Hashable): + """Represents the interaction that a :class:`Message` is a response to. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two message interactions are equal. + + .. describe:: x != y + + Checks if two message interactions are not equal. + + .. describe:: hash(x) + + Returns the message interaction's hash. + + Attributes + ----------- + id: :class:`int` + The interaction ID. + type: :class:`InteractionType` + The interaction type. + name: :class:`str` + The name of the interaction. + user: Union[:class:`User`, :class:`Member`] + The user or member that invoked the interaction. + """ + + def __init__(self, *, state: ConnectionState, guild: Optional[Guild], data: MessageInteractionPayload) -> None: + self.id: int = int(data['id']) + self.type: InteractionType = try_enum(InteractionType, data['type']) + self.name: str = data['name'] + self.user: Union[User, Member] = MISSING + + try: + payload = data['member'] + except KeyError: + self.user = state.create_user(data['user']) + else: + if guild is None: + # This is an unfortunate data loss, but it's better than giving bad data + # This is also an incredibly rare scenario. + self.user = state.create_user(data['user']) + else: + payload['user'] = data['user'] + self.user = Member(data=payload, guild=guild, state=state) # type: ignore + + def __repr__(self) -> str: + return f'' + + @property + def created_at(self) -> datetime.datetime: + """:class:`datetime.datetime`: The interaction's creation time in UTC.""" + return utils.snowflake_time(self.id) + + def flatten_handlers(cls: Type[Message]) -> Type[Message]: prefix = len('_handle_') handlers = [ @@ -1252,6 +1314,10 @@ class Message(PartialMessage, Hashable): components: List[:class:`Component`] A list of components in the message. + .. versionadded:: 2.0 + interaction: Optional[:class:`MessageInteraction`] + The interaction that this message is a response to. + .. versionadded:: 2.0 guild: Optional[:class:`Guild`] The guild that the message belongs to, if applicable. @@ -1286,6 +1352,7 @@ class Message(PartialMessage, Hashable): 'activity', 'stickers', 'components', + 'interaction', ) if TYPE_CHECKING: @@ -1330,6 +1397,15 @@ class Message(PartialMessage, Hashable): except AttributeError: self.guild = state._get_guild(utils._get_as_snowflake(data, 'guild_id')) + self.interaction: Optional[MessageInteraction] = None + + try: + interaction = data['interaction'] + except KeyError: + pass + else: + self.interaction = MessageInteraction(state=state, guild=self.guild, data=interaction) + try: ref = data['message_reference'] except KeyError: @@ -1529,6 +1605,9 @@ class Message(PartialMessage, Hashable): def _handle_components(self, components: List[ComponentPayload]): self.components = [_component_factory(d) for d in components] + def _handle_interaction(self, data: MessageInteractionPayload): + self.interaction = MessageInteraction(state=self._state, guild=self.guild, data=data) + def _rebind_cached_references(self, new_guild: Guild, new_channel: Union[TextChannel, Thread]) -> None: self.guild = new_guild self.channel = new_channel diff --git a/discord/types/interactions.py b/discord/types/interactions.py index 8c097c0ed..6e3ef68e8 100644 --- a/discord/types/interactions.py +++ b/discord/types/interactions.py @@ -235,7 +235,11 @@ class ModalSubmitInteraction(_BaseInteraction): Interaction = Union[PingInteraction, ApplicationCommandInteraction, MessageComponentInteraction, ModalSubmitInteraction] -class MessageInteraction(TypedDict): +class _MessageInteractionOptional(TypedDict, total=False): + member: Member + + +class MessageInteraction(_MessageInteractionOptional): id: Snowflake type: InteractionType name: str diff --git a/docs/interactions/api.rst b/docs/interactions/api.rst index 38fe51feb..692095eb4 100644 --- a/docs/interactions/api.rst +++ b/docs/interactions/api.rst @@ -37,6 +37,14 @@ InteractionMessage :members: :inherited-members: +MessageInteraction +~~~~~~~~~~~~~~~~~~~ + +.. attributetable:: MessageInteraction + +.. autoclass:: MessageInteraction() + :members: + Component ~~~~~~~~~~