mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-07 12:18:59 +00:00
Refactor internal message sending and editing parameter passing
This reduces some repetition in many functions and is ripped out of the webhook code. This also removes the unused HTTP functions for interaction responses since those belong in the webhook code rather than the HTTPClient.
This commit is contained in:
parent
4248bb3717
commit
9c066a8cf6
@ -51,6 +51,7 @@ from .permissions import PermissionOverwrite, Permissions
|
|||||||
from .role import Role
|
from .role import Role
|
||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
from .file import File
|
from .file import File
|
||||||
|
from .http import handle_message_parameters
|
||||||
from .voice_client import VoiceClient, VoiceProtocol
|
from .voice_client import VoiceClient, VoiceProtocol
|
||||||
from .sticker import GuildSticker, StickerItem
|
from .sticker import GuildSticker, StickerItem
|
||||||
from . import utils
|
from . import utils
|
||||||
@ -1330,107 +1331,40 @@ class Messageable:
|
|||||||
channel = await self._get_channel()
|
channel = await self._get_channel()
|
||||||
state = self._state
|
state = self._state
|
||||||
content = str(content) if content is not None else None
|
content = str(content) if content is not None else None
|
||||||
|
previous_allowed_mention = state.allowed_mentions
|
||||||
if embed is not None and embeds is not None:
|
|
||||||
raise InvalidArgument('cannot pass both embed and embeds parameter to send()')
|
|
||||||
|
|
||||||
if embed is not None:
|
|
||||||
embed = embed.to_dict()
|
|
||||||
|
|
||||||
elif embeds is not None:
|
|
||||||
if len(embeds) > 10:
|
|
||||||
raise InvalidArgument('embeds parameter must be a list of up to 10 elements')
|
|
||||||
embeds = [embed.to_dict() for embed in embeds]
|
|
||||||
|
|
||||||
if stickers is not None:
|
if stickers is not None:
|
||||||
stickers = [sticker.id for sticker in stickers]
|
stickers = [sticker.id for sticker in stickers]
|
||||||
|
|
||||||
if allowed_mentions is not None:
|
|
||||||
if state.allowed_mentions is not None:
|
|
||||||
allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
|
|
||||||
else:
|
else:
|
||||||
allowed_mentions = allowed_mentions.to_dict()
|
stickers = MISSING
|
||||||
else:
|
|
||||||
allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict()
|
|
||||||
|
|
||||||
if mention_author is not None:
|
|
||||||
allowed_mentions = allowed_mentions or AllowedMentions().to_dict()
|
|
||||||
allowed_mentions['replied_user'] = bool(mention_author)
|
|
||||||
|
|
||||||
if reference is not None:
|
if reference is not None:
|
||||||
try:
|
try:
|
||||||
reference = reference.to_message_reference_dict()
|
reference = reference.to_message_reference_dict()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise InvalidArgument('reference parameter must be Message, MessageReference, or PartialMessage') from None
|
raise InvalidArgument('reference parameter must be Message, MessageReference, or PartialMessage') from None
|
||||||
|
else:
|
||||||
|
reference = MISSING
|
||||||
|
|
||||||
if view:
|
if view and not hasattr(view, '__discord_ui_view__'):
|
||||||
if not hasattr(view, '__discord_ui_view__'):
|
|
||||||
raise InvalidArgument(f'view parameter must be View not {view.__class__!r}')
|
raise InvalidArgument(f'view parameter must be View not {view.__class__!r}')
|
||||||
|
|
||||||
components = view.to_components()
|
with handle_message_parameters(
|
||||||
else:
|
|
||||||
components = None
|
|
||||||
|
|
||||||
if file is not None and files is not None:
|
|
||||||
raise InvalidArgument('cannot pass both file and files parameter to send()')
|
|
||||||
|
|
||||||
if file is not None:
|
|
||||||
if not isinstance(file, File):
|
|
||||||
raise InvalidArgument('file parameter must be File')
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = await state.http.send_files(
|
|
||||||
channel.id,
|
|
||||||
files=[file],
|
|
||||||
allowed_mentions=allowed_mentions,
|
|
||||||
content=content,
|
content=content,
|
||||||
tts=tts,
|
tts=tts,
|
||||||
embed=embed,
|
file=file if file is not None else MISSING,
|
||||||
embeds=embeds,
|
files=files if files is not None else MISSING,
|
||||||
nonce=nonce,
|
embed=embed if embed is not None else MISSING,
|
||||||
message_reference=reference,
|
embeds=embeds if embeds is not None else MISSING,
|
||||||
stickers=stickers,
|
|
||||||
components=components,
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
elif files is not None:
|
|
||||||
if len(files) > 10:
|
|
||||||
raise InvalidArgument('files parameter must be a list of up to 10 elements')
|
|
||||||
elif not all(isinstance(file, File) for file in files):
|
|
||||||
raise InvalidArgument('files parameter must be a list of File')
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = await state.http.send_files(
|
|
||||||
channel.id,
|
|
||||||
files=files,
|
|
||||||
content=content,
|
|
||||||
tts=tts,
|
|
||||||
embed=embed,
|
|
||||||
embeds=embeds,
|
|
||||||
nonce=nonce,
|
nonce=nonce,
|
||||||
allowed_mentions=allowed_mentions,
|
allowed_mentions=allowed_mentions,
|
||||||
message_reference=reference,
|
message_reference=reference,
|
||||||
|
previous_allowed_mentions=previous_allowed_mention,
|
||||||
|
mention_author=mention_author,
|
||||||
stickers=stickers,
|
stickers=stickers,
|
||||||
components=components,
|
view=view,
|
||||||
)
|
) as params:
|
||||||
finally:
|
data = await state.http.send_message(channel.id, params=params)
|
||||||
for f in files:
|
|
||||||
f.close()
|
|
||||||
else:
|
|
||||||
data = await state.http.send_message(
|
|
||||||
channel.id,
|
|
||||||
content,
|
|
||||||
tts=tts,
|
|
||||||
embed=embed,
|
|
||||||
embeds=embeds,
|
|
||||||
nonce=nonce,
|
|
||||||
allowed_mentions=allowed_mentions,
|
|
||||||
message_reference=reference,
|
|
||||||
stickers=stickers,
|
|
||||||
components=components,
|
|
||||||
)
|
|
||||||
|
|
||||||
ret = state.create_message(channel=channel, data=data)
|
ret = state.create_message(channel=channel, data=data)
|
||||||
if view:
|
if view:
|
||||||
|
461
discord/http.py
461
discord/http.py
@ -35,14 +35,15 @@ from typing import (
|
|||||||
Iterable,
|
Iterable,
|
||||||
List,
|
List,
|
||||||
Literal,
|
Literal,
|
||||||
|
NamedTuple,
|
||||||
Optional,
|
Optional,
|
||||||
|
overload,
|
||||||
Sequence,
|
Sequence,
|
||||||
TYPE_CHECKING,
|
|
||||||
Tuple,
|
Tuple,
|
||||||
|
TYPE_CHECKING,
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
overload,
|
|
||||||
)
|
)
|
||||||
from urllib.parse import quote as _uriquote
|
from urllib.parse import quote as _uriquote
|
||||||
import weakref
|
import weakref
|
||||||
@ -58,6 +59,11 @@ _log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .file import File
|
from .file import File
|
||||||
|
from .ui.view import View
|
||||||
|
from .embeds import Embed
|
||||||
|
from .mentions import AllowedMentions
|
||||||
|
from .message import Attachment
|
||||||
|
from .flags import MessageFlags
|
||||||
from .enums import (
|
from .enums import (
|
||||||
AuditLogAction,
|
AuditLogAction,
|
||||||
InteractionResponseType,
|
InteractionResponseType,
|
||||||
@ -110,6 +116,149 @@ async def json_or_text(response: aiohttp.ClientResponse) -> Union[Dict[str, Any]
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class MultipartParameters(NamedTuple):
|
||||||
|
payload: Optional[Dict[str, Any]]
|
||||||
|
multipart: Optional[List[Dict[str, Any]]]
|
||||||
|
files: Optional[List[File]]
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self,
|
||||||
|
exc_type: Optional[Type[BE]],
|
||||||
|
exc: Optional[BE],
|
||||||
|
traceback: Optional[TracebackType],
|
||||||
|
) -> None:
|
||||||
|
if self.files:
|
||||||
|
for file in self.files:
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_message_parameters(
|
||||||
|
content: Optional[str] = MISSING,
|
||||||
|
*,
|
||||||
|
username: str = MISSING,
|
||||||
|
avatar_url: Any = MISSING,
|
||||||
|
tts: bool = False,
|
||||||
|
nonce: Optional[Union[int, str]] = None,
|
||||||
|
flags: MessageFlags = MISSING,
|
||||||
|
file: File = MISSING,
|
||||||
|
files: List[File] = MISSING,
|
||||||
|
embed: Optional[Embed] = MISSING,
|
||||||
|
embeds: List[Embed] = MISSING,
|
||||||
|
attachments: List[Attachment] = MISSING,
|
||||||
|
view: Optional[View] = MISSING,
|
||||||
|
allowed_mentions: Optional[AllowedMentions] = MISSING,
|
||||||
|
message_reference: Optional[message.MessageReference] = MISSING,
|
||||||
|
stickers: Optional[SnowflakeList] = MISSING,
|
||||||
|
previous_allowed_mentions: Optional[AllowedMentions] = None,
|
||||||
|
mention_author: Optional[bool] = None,
|
||||||
|
) -> MultipartParameters:
|
||||||
|
if files is not MISSING and file is not MISSING:
|
||||||
|
raise TypeError('Cannot mix file and files keyword arguments.')
|
||||||
|
if embeds is not MISSING and embed is not MISSING:
|
||||||
|
raise TypeError('Cannot mix embed and embeds keyword arguments.')
|
||||||
|
|
||||||
|
payload = {}
|
||||||
|
if embeds is not MISSING:
|
||||||
|
if len(embeds) > 10:
|
||||||
|
raise InvalidArgument('embeds has a maximum of 10 elements.')
|
||||||
|
payload['embeds'] = [e.to_dict() for e in embeds]
|
||||||
|
|
||||||
|
if embed is not MISSING:
|
||||||
|
if embed is None:
|
||||||
|
payload['embeds'] = []
|
||||||
|
else:
|
||||||
|
payload['embeds'] = [embed.to_dict()]
|
||||||
|
|
||||||
|
if content is not MISSING:
|
||||||
|
if content is not None:
|
||||||
|
payload['content'] = str(content)
|
||||||
|
else:
|
||||||
|
payload['content'] = None
|
||||||
|
|
||||||
|
if view is not MISSING:
|
||||||
|
if view is not None:
|
||||||
|
payload['components'] = view.to_components()
|
||||||
|
else:
|
||||||
|
payload['components'] = []
|
||||||
|
|
||||||
|
if nonce is not MISSING:
|
||||||
|
payload['nonce'] = str(nonce)
|
||||||
|
|
||||||
|
if message_reference is not MISSING:
|
||||||
|
payload['message_reference'] = message_reference
|
||||||
|
|
||||||
|
if attachments is not MISSING:
|
||||||
|
# Note: This will be overwritten if file or files is provided
|
||||||
|
# However, right now this is only passed via Message.edit not Messageable.send
|
||||||
|
payload['attachments'] = [a.to_dict() for a in attachments]
|
||||||
|
|
||||||
|
if stickers is not MISSING:
|
||||||
|
if stickers is not None:
|
||||||
|
payload['sticker_ids'] = stickers
|
||||||
|
else:
|
||||||
|
payload['sticker_ids'] = []
|
||||||
|
|
||||||
|
payload['tts'] = tts
|
||||||
|
if avatar_url:
|
||||||
|
payload['avatar_url'] = str(avatar_url)
|
||||||
|
if username:
|
||||||
|
payload['username'] = username
|
||||||
|
|
||||||
|
if flags is not MISSING:
|
||||||
|
payload['flags'] = flags.value
|
||||||
|
|
||||||
|
if allowed_mentions:
|
||||||
|
if previous_allowed_mentions is not None:
|
||||||
|
payload['allowed_mentions'] = previous_allowed_mentions.merge(allowed_mentions).to_dict()
|
||||||
|
else:
|
||||||
|
payload['allowed_mentions'] = allowed_mentions.to_dict()
|
||||||
|
elif previous_allowed_mentions is not None:
|
||||||
|
payload['allowed_mentions'] = previous_allowed_mentions.to_dict()
|
||||||
|
|
||||||
|
if mention_author is not None:
|
||||||
|
try:
|
||||||
|
payload['allowed_mentions']['replied_user'] = mention_author
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
multipart = []
|
||||||
|
if file is not MISSING:
|
||||||
|
files = [file]
|
||||||
|
|
||||||
|
if files:
|
||||||
|
for index, file in enumerate(files):
|
||||||
|
attachments_payload = []
|
||||||
|
for index, file in enumerate(files):
|
||||||
|
attachment = {
|
||||||
|
'id': index,
|
||||||
|
'filename': file.filename,
|
||||||
|
}
|
||||||
|
|
||||||
|
if file.description is not None:
|
||||||
|
attachment['description'] = file.description
|
||||||
|
|
||||||
|
attachments_payload.append(attachment)
|
||||||
|
|
||||||
|
payload['attachments'] = attachments_payload
|
||||||
|
|
||||||
|
multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
|
||||||
|
payload = None
|
||||||
|
for index, file in enumerate(files):
|
||||||
|
multipart.append(
|
||||||
|
{
|
||||||
|
'name': f'files[{index}]',
|
||||||
|
'value': file.fp,
|
||||||
|
'filename': file.filename,
|
||||||
|
'content_type': 'application/octet-stream',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return MultipartParameters(payload=payload, multipart=multipart, files=files)
|
||||||
|
|
||||||
|
|
||||||
class Route:
|
class Route:
|
||||||
BASE: ClassVar[str] = 'https://discord.com/api/v8'
|
BASE: ClassVar[str] = 'https://discord.com/api/v8'
|
||||||
|
|
||||||
@ -417,144 +566,18 @@ class HTTPClient:
|
|||||||
def send_message(
|
def send_message(
|
||||||
self,
|
self,
|
||||||
channel_id: Snowflake,
|
channel_id: Snowflake,
|
||||||
content: Optional[str],
|
|
||||||
*,
|
*,
|
||||||
tts: bool = False,
|
params: MultipartParameters,
|
||||||
embed: Optional[embed.Embed] = None,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
nonce: Optional[str] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
|
||||||
stickers: Optional[List[sticker.StickerItem]] = None,
|
|
||||||
components: Optional[List[components.Component]] = None,
|
|
||||||
) -> Response[message.Message]:
|
) -> Response[message.Message]:
|
||||||
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
||||||
payload = {}
|
if params.files:
|
||||||
|
return self.request(r, files=params.files, form=params.multipart)
|
||||||
if content:
|
else:
|
||||||
payload['content'] = content
|
return self.request(r, json=params.payload)
|
||||||
|
|
||||||
if tts:
|
|
||||||
payload['tts'] = True
|
|
||||||
|
|
||||||
if embed:
|
|
||||||
payload['embeds'] = [embed]
|
|
||||||
|
|
||||||
if embeds:
|
|
||||||
payload['embeds'] = embeds
|
|
||||||
|
|
||||||
if nonce:
|
|
||||||
payload['nonce'] = nonce
|
|
||||||
|
|
||||||
if allowed_mentions:
|
|
||||||
payload['allowed_mentions'] = allowed_mentions
|
|
||||||
|
|
||||||
if message_reference:
|
|
||||||
payload['message_reference'] = message_reference
|
|
||||||
|
|
||||||
if components:
|
|
||||||
payload['components'] = components
|
|
||||||
|
|
||||||
if stickers:
|
|
||||||
payload['sticker_ids'] = stickers
|
|
||||||
|
|
||||||
return self.request(r, json=payload)
|
|
||||||
|
|
||||||
def send_typing(self, channel_id: Snowflake) -> Response[None]:
|
def send_typing(self, channel_id: Snowflake) -> Response[None]:
|
||||||
return self.request(Route('POST', '/channels/{channel_id}/typing', channel_id=channel_id))
|
return self.request(Route('POST', '/channels/{channel_id}/typing', channel_id=channel_id))
|
||||||
|
|
||||||
def send_multipart_helper(
|
|
||||||
self,
|
|
||||||
route: Route,
|
|
||||||
*,
|
|
||||||
files: Sequence[File],
|
|
||||||
content: Optional[str] = None,
|
|
||||||
tts: bool = False,
|
|
||||||
embed: Optional[embed.Embed] = None,
|
|
||||||
embeds: Optional[Iterable[Optional[embed.Embed]]] = None,
|
|
||||||
nonce: Optional[str] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
|
||||||
stickers: Optional[List[sticker.StickerItem]] = None,
|
|
||||||
components: Optional[List[components.Component]] = None,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
form = []
|
|
||||||
|
|
||||||
payload: Dict[str, Any] = {'tts': tts}
|
|
||||||
if content:
|
|
||||||
payload['content'] = content
|
|
||||||
if embed:
|
|
||||||
payload['embeds'] = [embed]
|
|
||||||
if embeds:
|
|
||||||
payload['embeds'] = embeds
|
|
||||||
if nonce:
|
|
||||||
payload['nonce'] = nonce
|
|
||||||
if allowed_mentions:
|
|
||||||
payload['allowed_mentions'] = allowed_mentions
|
|
||||||
if message_reference:
|
|
||||||
payload['message_reference'] = message_reference
|
|
||||||
if components:
|
|
||||||
payload['components'] = components
|
|
||||||
if stickers:
|
|
||||||
payload['sticker_ids'] = stickers
|
|
||||||
if files:
|
|
||||||
attachments = []
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
attachment = {
|
|
||||||
"id": index,
|
|
||||||
"filename": file.filename,
|
|
||||||
}
|
|
||||||
|
|
||||||
if file.description is not None:
|
|
||||||
attachment["description"] = file.description
|
|
||||||
|
|
||||||
attachments.append(attachment)
|
|
||||||
|
|
||||||
payload['attachments'] = attachments
|
|
||||||
|
|
||||||
form.append({'name': 'payload_json', 'value': utils._to_json(payload)})
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
form.append(
|
|
||||||
{
|
|
||||||
'name': f'files[{index}]',
|
|
||||||
'value': file.fp,
|
|
||||||
'filename': file.filename,
|
|
||||||
'content_type': 'image/png',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.request(route, form=form, files=files)
|
|
||||||
|
|
||||||
def send_files(
|
|
||||||
self,
|
|
||||||
channel_id: Snowflake,
|
|
||||||
*,
|
|
||||||
files: Sequence[File],
|
|
||||||
content: Optional[str] = None,
|
|
||||||
tts: bool = False,
|
|
||||||
embed: Optional[embed.Embed] = None,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
nonce: Optional[str] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
|
||||||
stickers: Optional[List[sticker.StickerItem]] = None,
|
|
||||||
components: Optional[List[components.Component]] = None,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
|
||||||
return self.send_multipart_helper(
|
|
||||||
r,
|
|
||||||
files=files,
|
|
||||||
content=content,
|
|
||||||
tts=tts,
|
|
||||||
embed=embed,
|
|
||||||
embeds=embeds,
|
|
||||||
nonce=nonce,
|
|
||||||
allowed_mentions=allowed_mentions,
|
|
||||||
message_reference=message_reference,
|
|
||||||
stickers=stickers,
|
|
||||||
components=components,
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete_message(
|
def delete_message(
|
||||||
self, channel_id: Snowflake, message_id: Snowflake, *, reason: Optional[str] = None
|
self, channel_id: Snowflake, message_id: Snowflake, *, reason: Optional[str] = None
|
||||||
) -> Response[None]:
|
) -> Response[None]:
|
||||||
@ -571,9 +594,9 @@ class HTTPClient:
|
|||||||
|
|
||||||
return self.request(r, json=payload, reason=reason)
|
return self.request(r, json=payload, reason=reason)
|
||||||
|
|
||||||
def edit_message(self, channel_id: Snowflake, message_id: Snowflake, **fields: Any) -> Response[message.Message]:
|
def edit_message(self, channel_id: Snowflake, message_id: Snowflake, *, params: MultipartParameters) -> Response[message.Message]:
|
||||||
r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id)
|
r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id)
|
||||||
return self.request(r, json=fields)
|
return self.request(r, json=params.payload)
|
||||||
|
|
||||||
def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]:
|
def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]:
|
||||||
r = Route(
|
r = Route(
|
||||||
@ -1241,7 +1264,11 @@ class HTTPClient:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def modify_guild_sticker(
|
def modify_guild_sticker(
|
||||||
self, guild_id: Snowflake, sticker_id: Snowflake, payload: sticker.EditGuildSticker, reason: Optional[str],
|
self,
|
||||||
|
guild_id: Snowflake,
|
||||||
|
sticker_id: Snowflake,
|
||||||
|
payload: sticker.EditGuildSticker,
|
||||||
|
reason: Optional[str],
|
||||||
) -> Response[sticker.GuildSticker]:
|
) -> Response[sticker.GuildSticker]:
|
||||||
return self.request(
|
return self.request(
|
||||||
Route('PATCH', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id),
|
Route('PATCH', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id),
|
||||||
@ -1706,9 +1733,7 @@ class HTTPClient:
|
|||||||
def get_global_commands(self, application_id: Snowflake) -> Response[List[command.ApplicationCommand]]:
|
def get_global_commands(self, application_id: Snowflake) -> Response[List[command.ApplicationCommand]]:
|
||||||
return self.request(Route('GET', '/applications/{application_id}/commands', application_id=application_id))
|
return self.request(Route('GET', '/applications/{application_id}/commands', application_id=application_id))
|
||||||
|
|
||||||
def get_global_command(
|
def get_global_command(self, application_id: Snowflake, command_id: Snowflake) -> Response[command.ApplicationCommand]:
|
||||||
self, application_id: Snowflake, command_id: Snowflake
|
|
||||||
) -> Response[command.ApplicationCommand]:
|
|
||||||
r = Route(
|
r = Route(
|
||||||
'GET',
|
'GET',
|
||||||
'/applications/{application_id}/commands/{command_id}',
|
'/applications/{application_id}/commands/{command_id}',
|
||||||
@ -1750,9 +1775,7 @@ class HTTPClient:
|
|||||||
)
|
)
|
||||||
return self.request(r)
|
return self.request(r)
|
||||||
|
|
||||||
def bulk_upsert_global_commands(
|
def bulk_upsert_global_commands(self, application_id: Snowflake, payload) -> Response[List[command.ApplicationCommand]]:
|
||||||
self, application_id: Snowflake, payload
|
|
||||||
) -> Response[List[command.ApplicationCommand]]:
|
|
||||||
r = Route('PUT', '/applications/{application_id}/commands', application_id=application_id)
|
r = Route('PUT', '/applications/{application_id}/commands', application_id=application_id)
|
||||||
return self.request(r, json=payload)
|
return self.request(r, json=payload)
|
||||||
|
|
||||||
@ -1849,160 +1872,6 @@ class HTTPClient:
|
|||||||
)
|
)
|
||||||
return self.request(r, json=payload)
|
return self.request(r, json=payload)
|
||||||
|
|
||||||
# Interaction responses
|
|
||||||
|
|
||||||
def _edit_webhook_helper(
|
|
||||||
self,
|
|
||||||
route: Route,
|
|
||||||
file: Optional[File] = None,
|
|
||||||
content: Optional[str] = None,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
):
|
|
||||||
|
|
||||||
payload: Dict[str, Any] = {}
|
|
||||||
if content:
|
|
||||||
payload['content'] = content
|
|
||||||
if embeds:
|
|
||||||
payload['embeds'] = embeds
|
|
||||||
if allowed_mentions:
|
|
||||||
payload['allowed_mentions'] = allowed_mentions
|
|
||||||
|
|
||||||
form: List[Dict[str, Any]] = [
|
|
||||||
{
|
|
||||||
'name': 'payload_json',
|
|
||||||
'value': utils._to_json(payload),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
if file:
|
|
||||||
form.append(
|
|
||||||
{
|
|
||||||
'name': 'file',
|
|
||||||
'value': file.fp,
|
|
||||||
'filename': file.filename,
|
|
||||||
'content_type': 'application/octet-stream',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.request(route, form=form, files=[file] if file else None)
|
|
||||||
|
|
||||||
def create_interaction_response(
|
|
||||||
self,
|
|
||||||
interaction_id: Snowflake,
|
|
||||||
token: str,
|
|
||||||
*,
|
|
||||||
type: InteractionResponseType,
|
|
||||||
data: Optional[Dict[str, Any]] = None,
|
|
||||||
) -> Response[None]:
|
|
||||||
r = Route(
|
|
||||||
'POST',
|
|
||||||
'/interactions/{interaction_id}/{interaction_token}/callback',
|
|
||||||
interaction_id=interaction_id,
|
|
||||||
interaction_token=token,
|
|
||||||
)
|
|
||||||
payload: Dict[str, Any] = {
|
|
||||||
'type': type,
|
|
||||||
}
|
|
||||||
|
|
||||||
if data is not None:
|
|
||||||
payload['data'] = data
|
|
||||||
|
|
||||||
return self.request(r, json=payload)
|
|
||||||
|
|
||||||
def get_original_interaction_response(
|
|
||||||
self,
|
|
||||||
application_id: Snowflake,
|
|
||||||
token: str,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
r = Route(
|
|
||||||
'GET',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}/messages/@original',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
)
|
|
||||||
return self.request(r)
|
|
||||||
|
|
||||||
def edit_original_interaction_response(
|
|
||||||
self,
|
|
||||||
application_id: Snowflake,
|
|
||||||
token: str,
|
|
||||||
file: Optional[File] = None,
|
|
||||||
content: Optional[str] = None,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
r = Route(
|
|
||||||
'PATCH',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}/messages/@original',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
)
|
|
||||||
return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions)
|
|
||||||
|
|
||||||
def delete_original_interaction_response(self, application_id: Snowflake, token: str) -> Response[None]:
|
|
||||||
r = Route(
|
|
||||||
'DELETE',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}/messages/@original',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
)
|
|
||||||
return self.request(r)
|
|
||||||
|
|
||||||
def create_followup_message(
|
|
||||||
self,
|
|
||||||
application_id: Snowflake,
|
|
||||||
token: str,
|
|
||||||
files: List[File] = [],
|
|
||||||
content: Optional[str] = None,
|
|
||||||
tts: bool = False,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
r = Route(
|
|
||||||
'POST',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
)
|
|
||||||
return self.send_multipart_helper(
|
|
||||||
r,
|
|
||||||
content=content,
|
|
||||||
files=files,
|
|
||||||
tts=tts,
|
|
||||||
embeds=embeds,
|
|
||||||
allowed_mentions=allowed_mentions,
|
|
||||||
)
|
|
||||||
|
|
||||||
def edit_followup_message(
|
|
||||||
self,
|
|
||||||
application_id: Snowflake,
|
|
||||||
token: str,
|
|
||||||
message_id: Snowflake,
|
|
||||||
file: Optional[File] = None,
|
|
||||||
content: Optional[str] = None,
|
|
||||||
embeds: Optional[List[embed.Embed]] = None,
|
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
|
||||||
) -> Response[message.Message]:
|
|
||||||
r = Route(
|
|
||||||
'PATCH',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}/messages/{message_id}',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
message_id=message_id,
|
|
||||||
)
|
|
||||||
return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions)
|
|
||||||
|
|
||||||
def delete_followup_message(self, application_id: Snowflake, token: str, message_id: Snowflake) -> Response[None]:
|
|
||||||
r = Route(
|
|
||||||
'DELETE',
|
|
||||||
'/webhooks/{application_id}/{interaction_token}/messages/{message_id}',
|
|
||||||
application_id=application_id,
|
|
||||||
interaction_token=token,
|
|
||||||
message_id=message_id,
|
|
||||||
)
|
|
||||||
return self.request(r)
|
|
||||||
|
|
||||||
def get_guild_application_command_permissions(
|
def get_guild_application_command_permissions(
|
||||||
self,
|
self,
|
||||||
application_id: Snowflake,
|
application_id: Snowflake,
|
||||||
|
@ -38,7 +38,8 @@ from .member import Member
|
|||||||
from .message import Message, Attachment
|
from .message import Message, Attachment
|
||||||
from .object import Object
|
from .object import Object
|
||||||
from .permissions import Permissions
|
from .permissions import Permissions
|
||||||
from .webhook.async_ import async_context, Webhook, handle_message_parameters
|
from .http import handle_message_parameters
|
||||||
|
from .webhook.async_ import async_context, Webhook
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Interaction',
|
'Interaction',
|
||||||
|
@ -29,7 +29,21 @@ import datetime
|
|||||||
import re
|
import re
|
||||||
import io
|
import io
|
||||||
from os import PathLike
|
from os import PathLike
|
||||||
from typing import Dict, TYPE_CHECKING, Union, List, Optional, Any, Callable, Tuple, ClassVar, Optional, overload, TypeVar, Type
|
from typing import (
|
||||||
|
Dict,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Union,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Tuple,
|
||||||
|
ClassVar,
|
||||||
|
Optional,
|
||||||
|
overload,
|
||||||
|
TypeVar,
|
||||||
|
Type,
|
||||||
|
)
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .reaction import Reaction
|
from .reaction import Reaction
|
||||||
@ -43,6 +57,7 @@ from .member import Member
|
|||||||
from .flags import MessageFlags
|
from .flags import MessageFlags
|
||||||
from .file import File
|
from .file import File
|
||||||
from .utils import escape_mentions, MISSING
|
from .utils import escape_mentions, MISSING
|
||||||
|
from .http import handle_message_parameters
|
||||||
from .guild import Guild
|
from .guild import Guild
|
||||||
from .mixins import Hashable
|
from .mixins import Hashable
|
||||||
from .sticker import StickerItem
|
from .sticker import StickerItem
|
||||||
@ -1217,6 +1232,8 @@ class Message(Hashable):
|
|||||||
attachments: List[:class:`Attachment`]
|
attachments: List[:class:`Attachment`]
|
||||||
A list of attachments to keep in the message. If ``[]`` is passed
|
A list of attachments to keep in the message. If ``[]`` is passed
|
||||||
then all attachments are removed.
|
then all attachments are removed.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
suppress: :class:`bool`
|
suppress: :class:`bool`
|
||||||
Whether to suppress embeds for the message. This removes
|
Whether to suppress embeds for the message. This removes
|
||||||
all the embeds if set to ``True``. If set to ``False``
|
all the embeds if set to ``True``. If set to ``False``
|
||||||
@ -1250,50 +1267,26 @@ class Message(Hashable):
|
|||||||
You specified both ``embed`` and ``embeds``
|
You specified both ``embed`` and ``embeds``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
payload: Dict[str, Any] = {}
|
previous_allowed_mentions = self._state.allowed_mentions
|
||||||
if content is not MISSING:
|
|
||||||
if content is not None:
|
|
||||||
payload['content'] = str(content)
|
|
||||||
else:
|
|
||||||
payload['content'] = None
|
|
||||||
|
|
||||||
if embed is not MISSING and embeds is not MISSING:
|
|
||||||
raise InvalidArgument('cannot pass both embed and embeds parameter to edit()')
|
|
||||||
|
|
||||||
if embed is not MISSING:
|
|
||||||
if embed is None:
|
|
||||||
payload['embeds'] = []
|
|
||||||
else:
|
|
||||||
payload['embeds'] = [embed.to_dict()]
|
|
||||||
elif embeds is not MISSING:
|
|
||||||
payload['embeds'] = [e.to_dict() for e in embeds]
|
|
||||||
|
|
||||||
if suppress is not MISSING:
|
if suppress is not MISSING:
|
||||||
flags = MessageFlags._from_value(self.flags.value)
|
flags = MessageFlags._from_value(self.flags.value)
|
||||||
flags.suppress_embeds = suppress
|
|
||||||
payload['flags'] = flags.value
|
|
||||||
|
|
||||||
if allowed_mentions is MISSING:
|
|
||||||
if self._state.allowed_mentions is not None and self.author.id == self._state.self_id:
|
|
||||||
payload['allowed_mentions'] = self._state.allowed_mentions.to_dict()
|
|
||||||
else:
|
else:
|
||||||
if allowed_mentions is not None:
|
flags = MISSING
|
||||||
if self._state.allowed_mentions is not None:
|
|
||||||
payload['allowed_mentions'] = self._state.allowed_mentions.merge(allowed_mentions).to_dict()
|
|
||||||
else:
|
|
||||||
payload['allowed_mentions'] = allowed_mentions.to_dict()
|
|
||||||
|
|
||||||
if attachments is not MISSING:
|
|
||||||
payload['attachments'] = [a.to_dict() for a in attachments]
|
|
||||||
|
|
||||||
if view is not MISSING:
|
if view is not MISSING:
|
||||||
self._state.prevent_view_updates_for(self.id)
|
self._state.prevent_view_updates_for(self.id)
|
||||||
if view:
|
|
||||||
payload['components'] = view.to_components()
|
|
||||||
else:
|
|
||||||
payload['components'] = []
|
|
||||||
|
|
||||||
data = await self._state.http.edit_message(self.channel.id, self.id, **payload)
|
params = handle_message_parameters(
|
||||||
|
content=content,
|
||||||
|
flags=flags,
|
||||||
|
embed=embed,
|
||||||
|
embeds=embeds,
|
||||||
|
attachments=attachments,
|
||||||
|
view=view,
|
||||||
|
allowed_mentions=allowed_mentions,
|
||||||
|
previous_allowed_mentions=previous_allowed_mentions,
|
||||||
|
)
|
||||||
|
data = await self._state.http.edit_message(self.channel.id, self.id, params=params)
|
||||||
message = Message(state=self._state, channel=self.channel, data=data)
|
message = Message(state=self._state, channel=self.channel, data=data)
|
||||||
|
|
||||||
if view and not view.is_finished():
|
if view and not view.is_finished():
|
||||||
|
@ -41,8 +41,9 @@ from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, Discor
|
|||||||
from ..message import Message
|
from ..message import Message
|
||||||
from ..enums import try_enum, WebhookType
|
from ..enums import try_enum, WebhookType
|
||||||
from ..user import BaseUser, User
|
from ..user import BaseUser, User
|
||||||
|
from ..flags import MessageFlags
|
||||||
from ..asset import Asset
|
from ..asset import Asset
|
||||||
from ..http import Route
|
from ..http import Route, handle_message_parameters
|
||||||
from ..mixins import Hashable
|
from ..mixins import Hashable
|
||||||
from ..channel import PartialMessageable
|
from ..channel import PartialMessageable
|
||||||
|
|
||||||
@ -416,107 +417,6 @@ class AsyncWebhookAdapter:
|
|||||||
return self.request(r, session=session)
|
return self.request(r, session=session)
|
||||||
|
|
||||||
|
|
||||||
class ExecuteWebhookParameters(NamedTuple):
|
|
||||||
payload: Optional[Dict[str, Any]]
|
|
||||||
multipart: Optional[List[Dict[str, Any]]]
|
|
||||||
files: Optional[List[File]]
|
|
||||||
|
|
||||||
|
|
||||||
def handle_message_parameters(
|
|
||||||
content: Optional[str] = MISSING,
|
|
||||||
*,
|
|
||||||
username: str = MISSING,
|
|
||||||
avatar_url: Any = MISSING,
|
|
||||||
tts: bool = False,
|
|
||||||
ephemeral: bool = False,
|
|
||||||
file: File = MISSING,
|
|
||||||
files: List[File] = MISSING,
|
|
||||||
embed: Optional[Embed] = MISSING,
|
|
||||||
embeds: List[Embed] = MISSING,
|
|
||||||
view: Optional[View] = MISSING,
|
|
||||||
allowed_mentions: Optional[AllowedMentions] = MISSING,
|
|
||||||
previous_allowed_mentions: Optional[AllowedMentions] = None,
|
|
||||||
) -> ExecuteWebhookParameters:
|
|
||||||
if files is not MISSING and file is not MISSING:
|
|
||||||
raise TypeError('Cannot mix file and files keyword arguments.')
|
|
||||||
if embeds is not MISSING and embed is not MISSING:
|
|
||||||
raise TypeError('Cannot mix embed and embeds keyword arguments.')
|
|
||||||
|
|
||||||
payload = {}
|
|
||||||
if embeds is not MISSING:
|
|
||||||
if len(embeds) > 10:
|
|
||||||
raise InvalidArgument('embeds has a maximum of 10 elements.')
|
|
||||||
payload['embeds'] = [e.to_dict() for e in embeds]
|
|
||||||
|
|
||||||
if embed is not MISSING:
|
|
||||||
if embed is None:
|
|
||||||
payload['embeds'] = []
|
|
||||||
else:
|
|
||||||
payload['embeds'] = [embed.to_dict()]
|
|
||||||
|
|
||||||
if content is not MISSING:
|
|
||||||
if content is not None:
|
|
||||||
payload['content'] = str(content)
|
|
||||||
else:
|
|
||||||
payload['content'] = None
|
|
||||||
|
|
||||||
if view is not MISSING:
|
|
||||||
if view is not None:
|
|
||||||
payload['components'] = view.to_components()
|
|
||||||
else:
|
|
||||||
payload['components'] = []
|
|
||||||
|
|
||||||
payload['tts'] = tts
|
|
||||||
if avatar_url:
|
|
||||||
payload['avatar_url'] = str(avatar_url)
|
|
||||||
if username:
|
|
||||||
payload['username'] = username
|
|
||||||
if ephemeral:
|
|
||||||
payload['flags'] = 64
|
|
||||||
|
|
||||||
if allowed_mentions:
|
|
||||||
if previous_allowed_mentions is not None:
|
|
||||||
payload['allowed_mentions'] = previous_allowed_mentions.merge(allowed_mentions).to_dict()
|
|
||||||
else:
|
|
||||||
payload['allowed_mentions'] = allowed_mentions.to_dict()
|
|
||||||
elif previous_allowed_mentions is not None:
|
|
||||||
payload['allowed_mentions'] = previous_allowed_mentions.to_dict()
|
|
||||||
|
|
||||||
multipart = []
|
|
||||||
if file is not MISSING:
|
|
||||||
files = [file]
|
|
||||||
|
|
||||||
if files:
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
attachments = []
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
attachment = {
|
|
||||||
"id": index,
|
|
||||||
"filename": file.filename,
|
|
||||||
}
|
|
||||||
|
|
||||||
if file.description is not None:
|
|
||||||
attachment["description"] = file.description
|
|
||||||
|
|
||||||
attachments.append(attachment)
|
|
||||||
|
|
||||||
payload['attachments'] = attachments
|
|
||||||
|
|
||||||
multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
|
|
||||||
payload = None
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
multipart.append(
|
|
||||||
{
|
|
||||||
'name': f'files[{index}]',
|
|
||||||
'value': file.fp,
|
|
||||||
'filename': file.filename,
|
|
||||||
'content_type': 'application/octet-stream',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return ExecuteWebhookParameters(payload=payload, multipart=multipart, files=files)
|
|
||||||
|
|
||||||
|
|
||||||
async_context: ContextVar[AsyncWebhookAdapter] = ContextVar('async_webhook_context', default=AsyncWebhookAdapter())
|
async_context: ContextVar[AsyncWebhookAdapter] = ContextVar('async_webhook_context', default=AsyncWebhookAdapter())
|
||||||
|
|
||||||
|
|
||||||
@ -1356,6 +1256,10 @@ class Webhook(BaseWebhook):
|
|||||||
previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None)
|
previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None)
|
||||||
if content is None:
|
if content is None:
|
||||||
content = MISSING
|
content = MISSING
|
||||||
|
if ephemeral:
|
||||||
|
flags = MessageFlags._from_value(64)
|
||||||
|
else:
|
||||||
|
flags = MISSING
|
||||||
|
|
||||||
application_webhook = self.type is WebhookType.application
|
application_webhook = self.type is WebhookType.application
|
||||||
if ephemeral and not application_webhook:
|
if ephemeral and not application_webhook:
|
||||||
@ -1379,7 +1283,7 @@ class Webhook(BaseWebhook):
|
|||||||
files=files,
|
files=files,
|
||||||
embed=embed,
|
embed=embed,
|
||||||
embeds=embeds,
|
embeds=embeds,
|
||||||
ephemeral=ephemeral,
|
flags=flags,
|
||||||
view=view,
|
view=view,
|
||||||
allowed_mentions=allowed_mentions,
|
allowed_mentions=allowed_mentions,
|
||||||
previous_allowed_mentions=previous_mentions,
|
previous_allowed_mentions=previous_mentions,
|
||||||
|
@ -43,10 +43,10 @@ import weakref
|
|||||||
from .. import utils
|
from .. import utils
|
||||||
from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, DiscordServerError
|
from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, DiscordServerError
|
||||||
from ..message import Message
|
from ..message import Message
|
||||||
from ..http import Route
|
from ..http import Route, handle_message_parameters
|
||||||
from ..channel import PartialMessageable
|
from ..channel import PartialMessageable
|
||||||
|
|
||||||
from .async_ import BaseWebhook, handle_message_parameters, _WebhookState
|
from .async_ import BaseWebhook, _WebhookState
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'SyncWebhook',
|
'SyncWebhook',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user