12 changed files with 628 additions and 1013 deletions
@ -1,767 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
""" |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2015-present Rapptz |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a |
|||
copy of this software and associated documentation files (the "Software"), |
|||
to deal in the Software without restriction, including without limitation |
|||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|||
and/or sell copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
|||
""" |
|||
|
|||
from __future__ import annotations |
|||
from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Union |
|||
import asyncio |
|||
|
|||
from . import utils |
|||
from .enums import try_enum, InteractionType, InteractionResponseType |
|||
from .errors import InteractionResponded, HTTPException, ClientException |
|||
from .channel import PartialMessageable, ChannelType |
|||
|
|||
from .user import User |
|||
from .member import Member |
|||
from .message import Message, Attachment |
|||
from .object import Object |
|||
from .permissions import Permissions |
|||
from .webhook.async_ import async_context, Webhook, handle_message_parameters |
|||
|
|||
__all__ = ( |
|||
'Interaction', |
|||
'InteractionMessage', |
|||
'InteractionResponse', |
|||
) |
|||
|
|||
if TYPE_CHECKING: |
|||
from .types.interactions import ( |
|||
Interaction as InteractionPayload, |
|||
InteractionData, |
|||
) |
|||
from .guild import Guild |
|||
from .state import ConnectionState |
|||
from .file import File |
|||
from .mentions import AllowedMentions |
|||
from aiohttp import ClientSession |
|||
from .embeds import Embed |
|||
from .ui.view import View |
|||
from .channel import VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, PartialMessageable |
|||
from .threads import Thread |
|||
|
|||
InteractionChannel = Union[ |
|||
VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, Thread, PartialMessageable |
|||
] |
|||
|
|||
MISSING: Any = utils.MISSING |
|||
|
|||
|
|||
class Interaction: |
|||
"""Represents a Discord interaction. |
|||
|
|||
An interaction happens when a user does an action that needs to |
|||
be notified. Current examples are slash commands and components. |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
Attributes |
|||
----------- |
|||
id: :class:`int` |
|||
The interaction's ID. |
|||
type: :class:`InteractionType` |
|||
The interaction type. |
|||
guild_id: Optional[:class:`int`] |
|||
The guild ID the interaction was sent from. |
|||
channel_id: Optional[:class:`int`] |
|||
The channel ID the interaction was sent from. |
|||
application_id: :class:`int` |
|||
The application ID that the interaction was for. |
|||
user: Optional[Union[:class:`User`, :class:`Member`]] |
|||
The user or member that sent the interaction. |
|||
message: Optional[:class:`Message`] |
|||
The message that sent this interaction. |
|||
token: :class:`str` |
|||
The token to continue the interaction. These are valid |
|||
for 15 minutes. |
|||
data: :class:`dict` |
|||
The raw interaction data. |
|||
""" |
|||
|
|||
__slots__: Tuple[str, ...] = ( |
|||
'id', |
|||
'type', |
|||
'guild_id', |
|||
'channel_id', |
|||
'data', |
|||
'application_id', |
|||
'message', |
|||
'user', |
|||
'token', |
|||
'version', |
|||
'_permissions', |
|||
'_state', |
|||
'_session', |
|||
'_original_message', |
|||
'_cs_response', |
|||
'_cs_followup', |
|||
'_cs_channel', |
|||
) |
|||
|
|||
def __init__(self, *, data: InteractionPayload, state: ConnectionState): |
|||
self._state: ConnectionState = state |
|||
self._session: ClientSession = state.http._HTTPClient__session |
|||
self._original_message: Optional[InteractionMessage] = None |
|||
self._from_data(data) |
|||
|
|||
def _from_data(self, data: InteractionPayload): |
|||
self.id: int = int(data['id']) |
|||
self.type: InteractionType = try_enum(InteractionType, data['type']) |
|||
self.data: Optional[InteractionData] = data.get('data') |
|||
self.token: str = data['token'] |
|||
self.version: int = data['version'] |
|||
self.channel_id: Optional[int] = utils._get_as_snowflake(data, 'channel_id') |
|||
self.guild_id: Optional[int] = utils._get_as_snowflake(data, 'guild_id') |
|||
self.application_id: int = int(data['application_id']) |
|||
|
|||
self.message: Optional[Message] |
|||
try: |
|||
self.message = Message(state=self._state, channel=self.channel, data=data['message']) # type: ignore |
|||
except KeyError: |
|||
self.message = None |
|||
|
|||
self.user: Optional[Union[User, Member]] = None |
|||
self._permissions: int = 0 |
|||
|
|||
# TODO: there's a potential data loss here |
|||
if self.guild_id: |
|||
guild = self.guild or Object(id=self.guild_id) |
|||
try: |
|||
member = data['member'] # type: ignore |
|||
except KeyError: |
|||
pass |
|||
else: |
|||
self.user = Member(state=self._state, guild=guild, data=member) # type: ignore |
|||
self._permissions = int(member.get('permissions', 0)) |
|||
else: |
|||
try: |
|||
self.user = User(state=self._state, data=data['user']) |
|||
except KeyError: |
|||
pass |
|||
|
|||
@property |
|||
def guild(self) -> Optional[Guild]: |
|||
"""Optional[:class:`Guild`]: The guild the interaction was sent from.""" |
|||
return self._state and self._state._get_guild(self.guild_id) |
|||
|
|||
@utils.cached_slot_property('_cs_channel') |
|||
def channel(self) -> Optional[InteractionChannel]: |
|||
"""Optional[Union[:class:`abc.GuildChannel`, :class:`PartialMessageable`, :class:`Thread`]]: The channel the interaction was sent from. |
|||
|
|||
Note that due to a Discord limitation, DM channels are not resolved since there is |
|||
no data to complete them. These are :class:`PartialMessageable` instead. |
|||
""" |
|||
guild = self.guild |
|||
channel = guild and guild._resolve_channel(self.channel_id) |
|||
if channel is None: |
|||
if self.channel_id is not None: |
|||
type = ChannelType.text if self.guild_id is not None else ChannelType.private |
|||
return PartialMessageable(state=self._state, id=self.channel_id, type=type) |
|||
return None |
|||
return channel |
|||
|
|||
@property |
|||
def permissions(self) -> Permissions: |
|||
""":class:`Permissions`: The resolved permissions of the member in the channel, including overwrites. |
|||
|
|||
In a non-guild context where this doesn't apply, an empty permissions object is returned. |
|||
""" |
|||
return Permissions(self._permissions) |
|||
|
|||
@utils.cached_slot_property('_cs_response') |
|||
def response(self) -> InteractionResponse: |
|||
""":class:`InteractionResponse`: Returns an object responsible for handling responding to the interaction. |
|||
|
|||
A response can only be done once. If secondary messages need to be sent, consider using :attr:`followup` |
|||
instead. |
|||
""" |
|||
return InteractionResponse(self) |
|||
|
|||
@utils.cached_slot_property('_cs_followup') |
|||
def followup(self) -> Webhook: |
|||
""":class:`Webhook`: Returns the follow up webhook for follow up interactions.""" |
|||
payload = { |
|||
'id': self.application_id, |
|||
'type': 3, |
|||
'token': self.token, |
|||
} |
|||
return Webhook.from_state(data=payload, state=self._state) |
|||
|
|||
async def original_message(self) -> InteractionMessage: |
|||
"""|coro| |
|||
|
|||
Fetches the original interaction response message associated with the interaction. |
|||
|
|||
If the interaction response was :meth:`InteractionResponse.send_message` then this would |
|||
return the message that was sent using that response. Otherwise, this would return |
|||
the message that triggered the interaction. |
|||
|
|||
Repeated calls to this will return a cached value. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Fetching the original response message failed. |
|||
ClientException |
|||
The channel for the message could not be resolved. |
|||
|
|||
Returns |
|||
-------- |
|||
InteractionMessage |
|||
The original interaction response message. |
|||
""" |
|||
|
|||
if self._original_message is not None: |
|||
return self._original_message |
|||
|
|||
# TODO: fix later to not raise? |
|||
channel = self.channel |
|||
if channel is None: |
|||
raise ClientException('Channel for message could not be resolved') |
|||
|
|||
adapter = async_context.get() |
|||
data = await adapter.get_original_interaction_response( |
|||
application_id=self.application_id, |
|||
token=self.token, |
|||
session=self._session, |
|||
) |
|||
state = _InteractionMessageState(self, self._state) |
|||
message = InteractionMessage(state=state, channel=channel, data=data) # type: ignore |
|||
self._original_message = message |
|||
return message |
|||
|
|||
async def edit_original_message( |
|||
self, |
|||
*, |
|||
content: Optional[str] = MISSING, |
|||
embeds: List[Embed] = MISSING, |
|||
embed: Optional[Embed] = MISSING, |
|||
file: File = MISSING, |
|||
files: List[File] = MISSING, |
|||
view: Optional[View] = MISSING, |
|||
allowed_mentions: Optional[AllowedMentions] = None, |
|||
) -> InteractionMessage: |
|||
"""|coro| |
|||
|
|||
Edits the original interaction response message. |
|||
|
|||
This is a lower level interface to :meth:`InteractionMessage.edit` in case |
|||
you do not want to fetch the message and save an HTTP request. |
|||
|
|||
This method is also the only way to edit the original message if |
|||
the message sent was ephemeral. |
|||
|
|||
Parameters |
|||
------------ |
|||
content: Optional[:class:`str`] |
|||
The content to edit the message with or ``None`` to clear it. |
|||
embeds: List[:class:`Embed`] |
|||
A list of embeds to edit the message with. |
|||
embed: Optional[:class:`Embed`] |
|||
The embed to edit the message with. ``None`` suppresses the embeds. |
|||
This should not be mixed with the ``embeds`` parameter. |
|||
file: :class:`File` |
|||
The file to upload. This cannot be mixed with ``files`` parameter. |
|||
files: List[:class:`File`] |
|||
A list of files to send with the content. This cannot be mixed with the |
|||
``file`` parameter. |
|||
allowed_mentions: :class:`AllowedMentions` |
|||
Controls the mentions being processed in this message. |
|||
See :meth:`.abc.Messageable.send` for more information. |
|||
view: Optional[:class:`~discord.ui.View`] |
|||
The updated view to update this message with. If ``None`` is passed then |
|||
the view is removed. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Editing the message failed. |
|||
Forbidden |
|||
Edited a message that is not yours. |
|||
TypeError |
|||
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` |
|||
ValueError |
|||
The length of ``embeds`` was invalid. |
|||
|
|||
Returns |
|||
-------- |
|||
:class:`InteractionMessage` |
|||
The newly edited message. |
|||
""" |
|||
|
|||
previous_mentions: Optional[AllowedMentions] = self._state.allowed_mentions |
|||
params = handle_message_parameters( |
|||
content=content, |
|||
file=file, |
|||
files=files, |
|||
embed=embed, |
|||
embeds=embeds, |
|||
view=view, |
|||
allowed_mentions=allowed_mentions, |
|||
previous_allowed_mentions=previous_mentions, |
|||
) |
|||
adapter = async_context.get() |
|||
data = await adapter.edit_original_interaction_response( |
|||
self.application_id, |
|||
self.token, |
|||
session=self._session, |
|||
payload=params.payload, |
|||
multipart=params.multipart, |
|||
files=params.files, |
|||
) |
|||
|
|||
# The message channel types should always match |
|||
message = InteractionMessage(state=self._state, channel=self.channel, data=data) # type: ignore |
|||
if view and not view.is_finished(): |
|||
self._state.store_view(view, message.id) |
|||
return message |
|||
|
|||
async def delete_original_message(self) -> None: |
|||
"""|coro| |
|||
|
|||
Deletes the original interaction response message. |
|||
|
|||
This is a lower level interface to :meth:`InteractionMessage.delete` in case |
|||
you do not want to fetch the message and save an HTTP request. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Deleting the message failed. |
|||
Forbidden |
|||
Deleted a message that is not yours. |
|||
""" |
|||
adapter = async_context.get() |
|||
await adapter.delete_original_interaction_response( |
|||
self.application_id, |
|||
self.token, |
|||
session=self._session, |
|||
) |
|||
|
|||
|
|||
class InteractionResponse: |
|||
"""Represents a Discord interaction response. |
|||
|
|||
This type can be accessed through :attr:`Interaction.response`. |
|||
|
|||
.. versionadded:: 2.0 |
|||
""" |
|||
|
|||
__slots__: Tuple[str, ...] = ( |
|||
'_responded', |
|||
'_parent', |
|||
) |
|||
|
|||
def __init__(self, parent: Interaction): |
|||
self._parent: Interaction = parent |
|||
self._responded: bool = False |
|||
|
|||
def is_done(self) -> bool: |
|||
""":class:`bool`: Indicates whether an interaction response has been done before. |
|||
|
|||
An interaction can only be responded to once. |
|||
""" |
|||
return self._responded |
|||
|
|||
async def defer(self, *, ephemeral: bool = False) -> None: |
|||
"""|coro| |
|||
|
|||
Defers the interaction response. |
|||
|
|||
This is typically used when the interaction is acknowledged |
|||
and a secondary action will be done later. |
|||
|
|||
Parameters |
|||
----------- |
|||
ephemeral: :class:`bool` |
|||
Indicates whether the deferred message will eventually be ephemeral. |
|||
This only applies for interactions of type :attr:`InteractionType.application_command`. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Deferring the interaction failed. |
|||
InteractionResponded |
|||
This interaction has already been responded to before. |
|||
""" |
|||
if self._responded: |
|||
raise InteractionResponded(self._parent) |
|||
|
|||
defer_type: int = 0 |
|||
data: Optional[Dict[str, Any]] = None |
|||
parent = self._parent |
|||
if parent.type is InteractionType.component: |
|||
defer_type = InteractionResponseType.deferred_message_update.value |
|||
elif parent.type is InteractionType.application_command: |
|||
defer_type = InteractionResponseType.deferred_channel_message.value |
|||
if ephemeral: |
|||
data = {'flags': 64} |
|||
|
|||
if defer_type: |
|||
adapter = async_context.get() |
|||
await adapter.create_interaction_response( |
|||
parent.id, parent.token, session=parent._session, type=defer_type, data=data |
|||
) |
|||
self._responded = True |
|||
|
|||
async def pong(self) -> None: |
|||
"""|coro| |
|||
|
|||
Pongs the ping interaction. |
|||
|
|||
This should rarely be used. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Ponging the interaction failed. |
|||
InteractionResponded |
|||
This interaction has already been responded to before. |
|||
""" |
|||
if self._responded: |
|||
raise InteractionResponded(self._parent) |
|||
|
|||
parent = self._parent |
|||
if parent.type is InteractionType.ping: |
|||
adapter = async_context.get() |
|||
await adapter.create_interaction_response( |
|||
parent.id, parent.token, session=parent._session, type=InteractionResponseType.pong.value |
|||
) |
|||
self._responded = True |
|||
|
|||
async def send_message( |
|||
self, |
|||
content: Optional[Any] = None, |
|||
*, |
|||
embed: Embed = MISSING, |
|||
embeds: List[Embed] = MISSING, |
|||
view: View = MISSING, |
|||
tts: bool = False, |
|||
ephemeral: bool = False, |
|||
) -> None: |
|||
"""|coro| |
|||
|
|||
Responds to this interaction by sending a message. |
|||
|
|||
Parameters |
|||
----------- |
|||
content: Optional[:class:`str`] |
|||
The content of the message to send. |
|||
embeds: List[:class:`Embed`] |
|||
A list of embeds to send with the content. Maximum of 10. This cannot |
|||
be mixed with the ``embed`` parameter. |
|||
embed: :class:`Embed` |
|||
The rich embed for the content to send. This cannot be mixed with |
|||
``embeds`` parameter. |
|||
tts: :class:`bool` |
|||
Indicates if the message should be sent using text-to-speech. |
|||
view: :class:`discord.ui.View` |
|||
The view to send with the message. |
|||
ephemeral: :class:`bool` |
|||
Indicates if the message should only be visible to the user who started the interaction. |
|||
If a view is sent with an ephemeral message and it has no timeout set then the timeout |
|||
is set to 15 minutes. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Sending the message failed. |
|||
TypeError |
|||
You specified both ``embed`` and ``embeds``. |
|||
ValueError |
|||
The length of ``embeds`` was invalid. |
|||
InteractionResponded |
|||
This interaction has already been responded to before. |
|||
""" |
|||
if self._responded: |
|||
raise InteractionResponded(self._parent) |
|||
|
|||
payload: Dict[str, Any] = { |
|||
'tts': tts, |
|||
} |
|||
|
|||
if embed is not MISSING and embeds is not MISSING: |
|||
raise TypeError('cannot mix embed and embeds keyword arguments') |
|||
|
|||
if embed is not MISSING: |
|||
embeds = [embed] |
|||
|
|||
if embeds: |
|||
if len(embeds) > 10: |
|||
raise ValueError('embeds cannot exceed maximum of 10 elements') |
|||
payload['embeds'] = [e.to_dict() for e in embeds] |
|||
|
|||
if content is not None: |
|||
payload['content'] = str(content) |
|||
|
|||
if ephemeral: |
|||
payload['flags'] = 64 |
|||
|
|||
if view is not MISSING: |
|||
payload['components'] = view.to_components() |
|||
|
|||
parent = self._parent |
|||
adapter = async_context.get() |
|||
await adapter.create_interaction_response( |
|||
parent.id, |
|||
parent.token, |
|||
session=parent._session, |
|||
type=InteractionResponseType.channel_message.value, |
|||
data=payload, |
|||
) |
|||
|
|||
if view is not MISSING: |
|||
if ephemeral and view.timeout is None: |
|||
view.timeout = 15 * 60.0 |
|||
|
|||
self._parent._state.store_view(view) |
|||
|
|||
self._responded = True |
|||
|
|||
async def edit_message( |
|||
self, |
|||
*, |
|||
content: Optional[Any] = MISSING, |
|||
embed: Optional[Embed] = MISSING, |
|||
embeds: List[Embed] = MISSING, |
|||
attachments: List[Attachment] = MISSING, |
|||
view: Optional[View] = MISSING, |
|||
) -> None: |
|||
"""|coro| |
|||
|
|||
Responds to this interaction by editing the original message of |
|||
a component interaction. |
|||
|
|||
Parameters |
|||
----------- |
|||
content: Optional[:class:`str`] |
|||
The new content to replace the message with. ``None`` removes the content. |
|||
embeds: List[:class:`Embed`] |
|||
A list of embeds to edit the message with. |
|||
embed: Optional[:class:`Embed`] |
|||
The embed to edit the message with. ``None`` suppresses the embeds. |
|||
This should not be mixed with the ``embeds`` parameter. |
|||
attachments: List[:class:`Attachment`] |
|||
A list of attachments to keep in the message. If ``[]`` is passed |
|||
then all attachments are removed. |
|||
view: Optional[:class:`~discord.ui.View`] |
|||
The updated view to update this message with. If ``None`` is passed then |
|||
the view is removed. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Editing the message failed. |
|||
TypeError |
|||
You specified both ``embed`` and ``embeds``. |
|||
InteractionResponded |
|||
This interaction has already been responded to before. |
|||
""" |
|||
if self._responded: |
|||
raise InteractionResponded(self._parent) |
|||
|
|||
parent = self._parent |
|||
msg = parent.message |
|||
state = parent._state |
|||
message_id = msg.id if msg else None |
|||
if parent.type is not InteractionType.component: |
|||
return |
|||
|
|||
payload = {} |
|||
if content is not MISSING: |
|||
if content is None: |
|||
payload['content'] = None |
|||
else: |
|||
payload['content'] = str(content) |
|||
|
|||
if embed is not MISSING and embeds is not MISSING: |
|||
raise TypeError('cannot mix both embed and embeds keyword arguments') |
|||
|
|||
if embed is not MISSING: |
|||
if embed is None: |
|||
embeds = [] |
|||
else: |
|||
embeds = [embed] |
|||
|
|||
if embeds is not MISSING: |
|||
payload['embeds'] = [e.to_dict() for e in embeds] |
|||
|
|||
if attachments is not MISSING: |
|||
payload['attachments'] = [a.to_dict() for a in attachments] |
|||
|
|||
if view is not MISSING: |
|||
state.prevent_view_updates_for(message_id) |
|||
if view is None: |
|||
payload['components'] = [] |
|||
else: |
|||
payload['components'] = view.to_components() |
|||
|
|||
adapter = async_context.get() |
|||
await adapter.create_interaction_response( |
|||
parent.id, |
|||
parent.token, |
|||
session=parent._session, |
|||
type=InteractionResponseType.message_update.value, |
|||
data=payload, |
|||
) |
|||
|
|||
if view and not view.is_finished(): |
|||
state.store_view(view, message_id) |
|||
|
|||
self._responded = True |
|||
|
|||
|
|||
class _InteractionMessageState: |
|||
__slots__ = ('_parent', '_interaction') |
|||
|
|||
def __init__(self, interaction: Interaction, parent: ConnectionState): |
|||
self._interaction: Interaction = interaction |
|||
self._parent: ConnectionState = parent |
|||
|
|||
def _get_guild(self, guild_id): |
|||
return self._parent._get_guild(guild_id) |
|||
|
|||
def store_user(self, data): |
|||
return self._parent.store_user(data) |
|||
|
|||
def create_user(self, data): |
|||
return self._parent.create_user(data) |
|||
|
|||
@property |
|||
def http(self): |
|||
return self._parent.http |
|||
|
|||
def __getattr__(self, attr): |
|||
return getattr(self._parent, attr) |
|||
|
|||
|
|||
class InteractionMessage(Message): |
|||
"""Represents the original interaction response message. |
|||
|
|||
This allows you to edit or delete the message associated with |
|||
the interaction response. To retrieve this object see :meth:`Interaction.original_message`. |
|||
|
|||
This inherits from :class:`discord.Message` with changes to |
|||
:meth:`edit` and :meth:`delete` to work. |
|||
|
|||
.. versionadded:: 2.0 |
|||
""" |
|||
|
|||
__slots__ = () |
|||
_state: _InteractionMessageState |
|||
|
|||
async def edit( |
|||
self, |
|||
content: Optional[str] = MISSING, |
|||
embeds: List[Embed] = MISSING, |
|||
embed: Optional[Embed] = MISSING, |
|||
file: File = MISSING, |
|||
files: List[File] = MISSING, |
|||
view: Optional[View] = MISSING, |
|||
allowed_mentions: Optional[AllowedMentions] = None, |
|||
) -> InteractionMessage: |
|||
"""|coro| |
|||
|
|||
Edits the message. |
|||
|
|||
Parameters |
|||
------------ |
|||
content: Optional[:class:`str`] |
|||
The content to edit the message with or ``None`` to clear it. |
|||
embeds: List[:class:`Embed`] |
|||
A list of embeds to edit the message with. |
|||
embed: Optional[:class:`Embed`] |
|||
The embed to edit the message with. ``None`` suppresses the embeds. |
|||
This should not be mixed with the ``embeds`` parameter. |
|||
file: :class:`File` |
|||
The file to upload. This cannot be mixed with ``files`` parameter. |
|||
files: List[:class:`File`] |
|||
A list of files to send with the content. This cannot be mixed with the |
|||
``file`` parameter. |
|||
allowed_mentions: :class:`AllowedMentions` |
|||
Controls the mentions being processed in this message. |
|||
See :meth:`.abc.Messageable.send` for more information. |
|||
view: Optional[:class:`~discord.ui.View`] |
|||
The updated view to update this message with. If ``None`` is passed then |
|||
the view is removed. |
|||
|
|||
Raises |
|||
------- |
|||
HTTPException |
|||
Editing the message failed. |
|||
Forbidden |
|||
Edited a message that is not yours. |
|||
TypeError |
|||
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` |
|||
ValueError |
|||
The length of ``embeds`` was invalid. |
|||
|
|||
Returns |
|||
--------- |
|||
:class:`InteractionMessage` |
|||
The newly edited message. |
|||
""" |
|||
return await self._state._interaction.edit_original_message( |
|||
content=content, |
|||
embeds=embeds, |
|||
embed=embed, |
|||
file=file, |
|||
files=files, |
|||
view=view, |
|||
allowed_mentions=allowed_mentions, |
|||
) |
|||
|
|||
async def delete(self, *, delay: Optional[float] = None) -> None: |
|||
"""|coro| |
|||
|
|||
Deletes the message. |
|||
|
|||
Parameters |
|||
----------- |
|||
delay: Optional[:class:`float`] |
|||
If provided, the number of seconds to wait before deleting the message. |
|||
The waiting is done in the background and deletion failures are ignored. |
|||
|
|||
Raises |
|||
------ |
|||
Forbidden |
|||
You do not have proper permissions to delete the message. |
|||
NotFound |
|||
The message was deleted already. |
|||
HTTPException |
|||
Deleting the message failed. |
|||
""" |
|||
|
|||
if delay is not None: |
|||
|
|||
async def inner_call(delay: float = delay): |
|||
await asyncio.sleep(delay) |
|||
try: |
|||
await self._state._interaction.delete_original_message() |
|||
except HTTPException: |
|||
pass |
|||
|
|||
asyncio.create_task(inner_call()) |
|||
else: |
|||
await self._state._interaction.delete_original_message() |
Loading…
Reference in new issue