diff --git a/interactions/api/models/user.py b/interactions/api/models/user.py index 004d59cd7..97a5b87cf 100644 --- a/interactions/api/models/user.py +++ b/interactions/api/models/user.py @@ -1,11 +1,15 @@ -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, List, Optional, Union from ...utils.attrs_utils import ClientSerializerMixin, define, field +from ...utils.missing import MISSING +from ..error import LibraryException from .flags import UserFlags -from .misc import IDMixin, Snowflake +from .misc import AllowedMentions, File, IDMixin, Snowflake if TYPE_CHECKING: + from ...client.models.component import ActionRow, Button, SelectMenu from .gw import Presence + from .message import Attachment, Embed, Message __all__ = ("User",) @@ -111,3 +115,93 @@ def presence(self) -> Optional["Presence"]: from .gw import Presence return self._client.cache[Presence].get(self.id) + + async def send( + self, + content: Optional[str] = MISSING, + *, + components: Optional[ + Union[ + "ActionRow", + "Button", + "SelectMenu", + List["ActionRow"], + List["Button"], + List["SelectMenu"], + ] + ] = MISSING, + tts: Optional[bool] = MISSING, + attachments: Optional[List["Attachment"]] = MISSING, + files: Optional[Union[File, List[File]]] = MISSING, + embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, + allowed_mentions: Optional[Union[AllowedMentions, dict]] = MISSING, + ) -> "Message": + """ + Sends a DM to the user. + + :param content?: The contents of the message as a string or string-converted value. + :type content?: Optional[str] + :param components?: A component, or list of components for the message. + :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. + :type embeds?: Optional[Union[Embed, List[Embed]]] + :param allowed_mentions?: The allowed mentions for the message. + :type allowed_mentions?: Optional[Union[AllowedMentions, dict]] + :return: The sent message as an object. + :rtype: Message + """ + if not self._client: + raise LibraryException(code=13) + from ...client.models.component import _build_components + from .message import Message + + _content: str = "" if content is MISSING else content + _tts: bool = False if tts is MISSING else tts + _attachments = [] if attachments is MISSING else [a._json for a in attachments] + _embeds: list = ( + [] + if not embeds or embeds is MISSING + else ([embed._json for embed in embeds] if isinstance(embeds, list) else [embeds._json]) + ) + _allowed_mentions: dict = ( + {} + if allowed_mentions is MISSING + else allowed_mentions._json + if isinstance(allowed_mentions, AllowedMentions) + else allowed_mentions + ) + if not components or components is MISSING: + _components = [] + else: + _components = _build_components(components=components) + + if not files or files is MISSING: + _files = [] + elif isinstance(files, list): + _files = [file._json_payload(id) for id, file in enumerate(files)] + else: + _files = [files._json_payload(0)] + files = [files] + + _files.extend(_attachments) + + payload = dict( + content=_content, + tts=_tts, + attachments=_files, + embeds=_embeds, + components=_components, + allowed_mentions=_allowed_mentions, + ) + channel = await self._client.create_dm(recipient_id=int(self.id)) + res = await self._client.create_message( + channel_id=int(channel["id"]), payload=payload, files=files + ) + + return Message(**res, _client=self._client)