From c2b8cd68ed37a107f8d82acba72e1b3002ae989c Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Sun, 19 Jun 2022 18:12:29 +0200 Subject: [PATCH] feat!: Implement attachment sending (#869) * feat!: Implement attachment sending * Update interactions/client/context.py Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> * Update interactions/api/models/channel.py Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> * Update interactions/api/models/member.py Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> * Update interactions/api/models/message.py Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> * Update interactions/api/models/webhook.py Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> * fix: resolve circular import Co-authored-by: Sofia <41456914+ffl0w@users.noreply.github.com> --- interactions/api/models/channel.py | 10 +++++-- interactions/api/models/channel.pyi | 1 + interactions/api/models/member.py | 8 ++++-- interactions/api/models/member.pyi | 1 + interactions/api/models/message.py | 10 +++++-- interactions/api/models/message.pyi | 1 + interactions/api/models/webhook.py | 12 +++++--- interactions/api/models/webhook.pyi | 1 + interactions/client/context.py | 44 ++++++++++++++++++----------- interactions/client/context.pyi | 2 ++ 10 files changed, 62 insertions(+), 28 deletions(-) diff --git a/interactions/api/models/channel.py b/interactions/api/models/channel.py index 5bd92cf97..aeb099dcf 100644 --- a/interactions/api/models/channel.py +++ b/interactions/api/models/channel.py @@ -178,6 +178,7 @@ async def send( content: Optional[str] = MISSING, *, tts: Optional[bool] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, # noqa files: Optional[Union[File, List[File]]] = MISSING, embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, # noqa allowed_mentions: Optional["MessageInteraction"] = MISSING, # noqa @@ -201,6 +202,8 @@ async def send( :type tts: Optional[bool] :param files?: A file or list of files to be attached to the message. :type files: Optional[Union[File, List[File]]] + :param attachments?: The attachments to attach to the message. Needs to be uploaded to the CDN first + :type attachments: Optional[List[Attachment]] :param embeds?: An embed, or list of embeds for the message. :type embeds: Optional[Union[Embed, List[Embed]]] :param allowed_mentions?: The message interactions/mention limits that the message can refer to. @@ -217,8 +220,7 @@ async def send( _content: str = "" if content is MISSING else content _tts: bool = False if tts is MISSING else tts - # _file = None if file is None else file - # _attachments = [] if attachments else None + _attachments = [] if attachments is MISSING else [a._json for a in attachments] _allowed_mentions: dict = {} if allowed_mentions is MISSING else allowed_mentions if not embeds or embeds is MISSING: _embeds: list = [] @@ -240,6 +242,8 @@ async def send( _files = [files._json_payload(0)] files = [files] + _files.extend(_attachments) + payload = dict( content=_content, tts=_tts, @@ -255,7 +259,7 @@ async def send( # dumb hack, discord doesn't send the full author data author = {"id": None, "username": None, "discriminator": None} - author.update(res["author"]) + author |= res["author"] res["author"] = author return Message(**res, _client=self._client) diff --git a/interactions/api/models/channel.pyi b/interactions/api/models/channel.pyi index 70283ebd4..d34420f8c 100644 --- a/interactions/api/models/channel.pyi +++ b/interactions/api/models/channel.pyi @@ -79,6 +79,7 @@ class Channel(ClientSerializerMixin): files: Optional[Union[File, List[File]]] = ..., embeds: Optional[Union[Embed, List[Embed]]] = ..., allowed_mentions: Optional[MessageInteraction] = ..., + attachments: Optional[List["Attachment"]] = MISSING, # noqa components: Optional[ Union[ "ActionRow", diff --git a/interactions/api/models/member.py b/interactions/api/models/member.py index 2e5c3384b..4f2874a8b 100644 --- a/interactions/api/models/member.py +++ b/interactions/api/models/member.py @@ -214,6 +214,7 @@ async def send( ] ] = MISSING, tts: Optional[bool] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, # noqa files: Optional[Union[File, List[File]]] = MISSING, embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, # noqa allowed_mentions: Optional["MessageInteraction"] = MISSING, # noqa @@ -227,6 +228,8 @@ async def send( :type components: Optional[Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]]] :param tts?: Whether the message utilizes the text-to-speech Discord programme or not. :type tts: Optional[bool] + :param attachments?: The attachments to attach to the message. Needs to be uploaded to the CDN first + :type attachments: Optional[List[Attachment]] :param files?: A file or list of files to be attached to the message. :type files: Optional[Union[File, List[File]]] :param embeds?: An embed, or list of embeds for the message. @@ -243,7 +246,7 @@ async def send( _content: str = "" if content is MISSING else content _tts: bool = False if tts is MISSING else tts - # _attachments = [] if attachments else None + _attachments = [] if attachments is MISSING else [a._json for a in attachments] _embeds: list = ( [] if not embeds or embeds is MISSING @@ -264,7 +267,8 @@ async def send( _files = [files._json_payload(0)] files = [files] - # TODO: post-v4: Add attachments into Message obj. + _files.extend(_attachments) + payload = dict( content=_content, tts=_tts, diff --git a/interactions/api/models/member.pyi b/interactions/api/models/member.pyi index 9f8d8bad2..eda9ffebb 100644 --- a/interactions/api/models/member.pyi +++ b/interactions/api/models/member.pyi @@ -59,6 +59,7 @@ class Member(ClientSerializerMixin): components: Optional[ Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = ..., + attachments: Optional[List["Attachment"]] = ..., # noqa tts: Optional[bool] = ..., files: Optional[Union[File, List[File]]] = ..., embeds: Optional[Union[Embed, List[Embed]]] = ..., diff --git a/interactions/api/models/message.py b/interactions/api/models/message.py index ef71f1bae..8cd27da80 100644 --- a/interactions/api/models/message.py +++ b/interactions/api/models/message.py @@ -1031,6 +1031,7 @@ async def reply( tts: Optional[bool] = MISSING, embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, files: Optional[Union[File, List[File]]] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, allowed_mentions: Optional["MessageInteraction"] = MISSING, components: Optional[ Union[ @@ -1050,6 +1051,8 @@ async def reply( :type content: Optional[str] :param tts?: Whether the message utilizes the text-to-speech Discord programme or not. :type tts: Optional[bool] + :param attachments?: The attachments to attach to the message. Needs to be uploaded to the CDN first + :type attachments: Optional[List[Attachment]] :param files?: A file or list of files to be attached to the message. :type files: Optional[Union[File, List[File]]] :param embeds?: An embed, or list of embeds for the message. @@ -1076,7 +1079,7 @@ async def reply( ) _allowed_mentions: dict = {} if allowed_mentions is MISSING else allowed_mentions _message_reference = MessageReference(message_id=int(self.id))._json - + _attachments = [] if attachments is MISSING else [a._json for a in attachments] if not components or components is MISSING: _components = [] else: @@ -1090,7 +1093,8 @@ async def reply( _files = [files._json_payload(0)] files = [files] - # TODO: post-v4: Add attachments into Message obj. + _files.extend(_attachments) + payload = dict( content=_content, tts=_tts, @@ -1106,7 +1110,7 @@ async def reply( ) author = {"id": None, "username": None, "discriminator": None} - author.update(res["author"]) + author |= res["author"] res["author"] = author return Message(**res, _client=self._client) diff --git a/interactions/api/models/message.pyi b/interactions/api/models/message.pyi index b34d16d77..1c1117def 100644 --- a/interactions/api/models/message.pyi +++ b/interactions/api/models/message.pyi @@ -284,6 +284,7 @@ class Message(ClientSerializerMixin): files: Optional[Union[File, List[File]]] = MISSING, embeds: Optional[Union[Embed, List[Embed]]] = MISSING, allowed_mentions: Optional[MessageInteraction] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, # noqa components: Optional[ Union[ ActionRow, diff --git a/interactions/api/models/webhook.py b/interactions/api/models/webhook.py index 595daa894..c034395f7 100644 --- a/interactions/api/models/webhook.py +++ b/interactions/api/models/webhook.py @@ -176,6 +176,7 @@ async def execute( tts: Optional[bool] = MISSING, embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, # noqa allowed_mentions: Any = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, # noqa components: Optional[ Union[ "ActionRow", # noqa @@ -203,6 +204,8 @@ async def execute( :type avatar_url: str :param tts: true if this is a TTS message :type tts: bool + :param attachments?: The attachments to attach to the message. Needs to be uploaded to the CDN first + :type attachments: Optional[List[Attachment]] :param embeds: embedded ``rich`` content :type embeds: Union[Embed, List[Embed]] :param allowed_mentions: allowed mentions for the message @@ -225,7 +228,8 @@ async def execute( _content: str = "" if content is MISSING else content _tts: bool = False if tts is MISSING else tts - # _attachments = [] if attachments else None + _attachments = [] if attachments is MISSING else [a._json for a in attachments] + _embeds: list = ( [] if not embeds or embeds is MISSING @@ -246,7 +250,9 @@ async def execute( _files = [files._json_payload(0)] files = [files] - msg = Message( + _files.extend(_attachments) + + payload: dict = dict( content=_content, tts=_tts, attachments=_files, @@ -255,8 +261,6 @@ async def execute( allowed_mentions=_allowed_mentions, ) - payload = msg._json - if username is not MISSING: payload["username"] = username diff --git a/interactions/api/models/webhook.pyi b/interactions/api/models/webhook.pyi index d3b28e5f1..720037a31 100644 --- a/interactions/api/models/webhook.pyi +++ b/interactions/api/models/webhook.pyi @@ -53,6 +53,7 @@ class Webhook(ClientSerializerMixin): Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = MISSING, files: Optional[Union[File, List[File]]] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, # noqa thread_id: Optional[int] = MISSING, ) -> Optional[Message]: ... async def delete(self) -> None: ... diff --git a/interactions/client/context.py b/interactions/client/context.py index 2d8115773..90c16c20b 100644 --- a/interactions/client/context.py +++ b/interactions/client/context.py @@ -7,7 +7,7 @@ from ..api.models.channel import Channel from ..api.models.guild import Guild from ..api.models.member import Member -from ..api.models.message import Embed, Message, MessageInteraction, MessageReference +from ..api.models.message import Attachment, Embed, Message, MessageInteraction, MessageReference from ..api.models.misc import Snowflake from ..api.models.user import User from ..base import get_logger @@ -105,7 +105,7 @@ async def send( content: Optional[str] = MISSING, *, tts: Optional[bool] = MISSING, - # attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type. + attachments: Optional[List[Attachment]] = MISSING, embeds: Optional[Union[Embed, List[Embed]]] = MISSING, allowed_mentions: Optional[MessageInteraction] = MISSING, components: Optional[ @@ -121,6 +121,8 @@ async def send( :type content: Optional[str] :param tts?: Whether the message utilizes the text-to-speech Discord programme or not. :type tts: Optional[bool] + :param attachments?: The attachments to attach to the message. Needs to be uploaded to the CDN first + :type attachments: Optional[List[Attachment]] :param embeds?: An embed, or list of embeds for the message. :type embeds: Optional[Union[Embed, List[Embed]]] :param allowed_mentions?: The message interactions/mention limits that the message can refer to. @@ -141,8 +143,6 @@ async def send( else: _content: str = "" if content is MISSING else content _tts: bool = False if tts is MISSING else tts - # _file = None if file is None else file - # _attachments = [] if attachments else None if ( embeds is MISSING @@ -177,23 +177,24 @@ async def send( _ephemeral: int = (1 << 6) if ephemeral else 0 - # TODO: post-v4: Add attachments into Message obj. - payload: dict = dict( + _attachments = [] if attachments is MISSING else [a._json for a in attachments] + + return dict( content=_content, tts=_tts, embeds=_embeds, allowed_mentions=_allowed_mentions, components=_components, + attachments=_attachments, flags=_ephemeral, ) - return payload async def edit( self, content: Optional[str] = MISSING, *, tts: Optional[bool] = MISSING, - # file: Optional[FileIO] = None, + attachments: Optional[List[Attachment]] = MISSING, embeds: Optional[Union[Embed, List[Embed]]] = MISSING, allowed_mentions: Optional[MessageInteraction] = MISSING, message_reference: Optional[MessageReference] = MISSING, @@ -217,22 +218,33 @@ async def edit( payload["content"] = _content _tts: bool = False if tts is MISSING else tts payload["tts"] = _tts - # _file = None if file is None else file if self.message.embeds is not None or embeds is not MISSING: if embeds is MISSING: embeds = self.message.embeds _embeds: list = ( - [] - if not embeds - else ( - [embed._json for embed in embeds] - if isinstance(embeds, list) - else [embeds._json] - ) + ([embed._json for embed in embeds] if isinstance(embeds, list) else [embeds._json]) + if embeds + else [] ) + payload["embeds"] = _embeds + if self.message.attachments is not None or attachments is not MISSING: + if attachments is MISSING: + attachments = self.message.attachments + _attachments: list = ( + ( + [attachment._json for attachment in attachments] + if isinstance(attachments, list) + else [attachments._json] + ) + if attachments + else [] + ) + + payload["attachments"] = _attachments + _allowed_mentions: dict = {} if allowed_mentions is MISSING else allowed_mentions _message_reference: dict = {} if message_reference is MISSING else message_reference._json diff --git a/interactions/client/context.pyi b/interactions/client/context.pyi index b301a7222..a7fccb672 100644 --- a/interactions/client/context.pyi +++ b/interactions/client/context.pyi @@ -56,6 +56,7 @@ class _Context(ClientSerializerMixin): components: Optional[ Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = ..., + attachments: Optional[List["Attachment"]] = ..., # noqa ephemeral: Optional[bool] = ... ) -> dict: ... async def edit( @@ -66,6 +67,7 @@ class _Context(ClientSerializerMixin): embeds: Optional[Union[Embed, List[Embed]]] = ..., allowed_mentions: Optional[MessageInteraction] = ..., message_reference: Optional[MessageReference] = ..., + attachments: Optional[List["Attachment"]] = MISSING, # noqa components: Optional[ Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = ...