Skip to content

Commit 51d824c

Browse files
authored
refactor: allow file sending in all send and editing methods (except context) (#706)
* refactor: allow file sending in all send and editing methods (except context) * refactor: update headers * refactor: update headers
1 parent 639574e commit 51d824c

File tree

8 files changed

+96
-129
lines changed

8 files changed

+96
-129
lines changed

interactions/api/http/message.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,35 @@ async def delete_messages(
143143

144144
return await self._req.request(r, json=payload, reason=reason)
145145

146-
async def edit_message(self, channel_id: int, message_id: int, payload: dict) -> dict:
146+
async def edit_message(
147+
self, channel_id: int, message_id: int, payload: dict, files: Optional[List[File]] = MISSING
148+
) -> dict:
147149
"""
148150
Edits a message that already exists.
149151
150152
:param channel_id: Channel snowflake ID.
151153
:param message_id: Message snowflake ID.
152154
:param payload: Any new data that needs to be changed.
155+
:param files: An optional list of files to send attached to the message.
153156
:type payload: dict
154157
:return: A message object with edited attributes.
155158
"""
159+
data = None
160+
if files is not MISSING and len(files) > 0:
161+
162+
data = MultipartWriter("form-data")
163+
part = data.append_json(payload)
164+
part.set_content_disposition("form-data", name="payload_json")
165+
payload = None
166+
167+
for id, file in enumerate(files):
168+
part = data.append(
169+
file._fp,
170+
)
171+
part.set_content_disposition(
172+
"form-data", name="files[" + str(id) + "]", filename=file._filename
173+
)
174+
156175
return await self._req.request(
157176
Route(
158177
"PATCH",
@@ -161,6 +180,7 @@ async def edit_message(self, channel_id: int, message_id: int, payload: dict) ->
161180
message_id=message_id,
162181
),
163182
json=payload,
183+
data=data,
164184
)
165185

166186
async def pin_message(self, channel_id: int, message_id: int) -> None:

interactions/api/http/message.pyi

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from typing import List, Optional, Union
22

33
from ...api.cache import Cache
44
from ..models.message import Embed, Message
5-
from ..models.misc import Snowflake, File
5+
from ..models.misc import Snowflake, File, MISSING
66
from .request import _Request
77

88

@@ -29,9 +29,11 @@ class _MessageRequest:
2929
self, channel_id: int, message_id: int, reason: Optional[str] = None
3030
) -> None: ...
3131
async def delete_messages(
32-
self, channel_id: int, message_ids: List[int], reason: Optional[str] = None
32+
self, channel_id: int, message_ids: List[int], reason: Optional[str] = None
3333
) -> None: ...
34-
async def edit_message(self, channel_id: int, message_id: int, payload: dict) -> dict: ...
34+
async def edit_message(
35+
self, channel_id: int, message_id: int, payload: dict, files: Optional[List[File]] = MISSING
36+
) -> dict: ...
3537
async def pin_message(self, channel_id: int, message_id: int) -> None: ...
3638
async def unpin_message(self, channel_id: int, message_id: int) -> None: ...
3739
async def publish_message(self, channel_id: int, message_id: int) -> dict: ...

interactions/api/models/gw.py

Lines changed: 19 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from datetime import datetime
22
from typing import List, Optional, Union
33

4-
from ...client.models.component import ActionRow, Button, SelectMenu
4+
from ...client.models.component import ActionRow, Button, SelectMenu, _build_components
55
from .channel import Channel, ThreadMember
66
from .member import Member
77
from .message import Embed, Emoji, Message, MessageInteraction, Sticker
8-
from .misc import MISSING, ClientStatus, DictSerializerMixin, Snowflake
8+
from .misc import MISSING, ClientStatus, DictSerializerMixin, File, Snowflake
99
from .presence import PresenceActivity
1010
from .role import Role
1111
from .user import User
@@ -347,7 +347,7 @@ async def send(
347347
]
348348
] = MISSING,
349349
tts: Optional[bool] = MISSING,
350-
# attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type.
350+
files: Optional[Union[File, List[File]]] = MISSING,
351351
embeds: Optional[Union[Embed, List[Embed]]] = MISSING,
352352
allowed_mentions: Optional[MessageInteraction] = MISSING,
353353
) -> Message:
@@ -360,6 +360,8 @@ async def send(
360360
:type components: Optional[Union[ActionRow, Button, SelectMenu, List[Actionrow], List[Button], List[SelectMenu]]]
361361
:param tts?: Whether the message utilizes the text-to-speech Discord programme or not.
362362
:type tts: Optional[bool]
363+
:param files?: A file or list of files to be attached to the message.
364+
:type files: Optional[Union[File, List[File]]]
363365
:param embeds?: An embed, or list of embeds for the message.
364366
:type embeds: Optional[Union[Embed, List[Embed]]]
365367
:param allowed_mentions?: The message interactions/mention limits that the message can refer to.
@@ -383,117 +385,30 @@ async def send(
383385

384386
if not components or components is MISSING:
385387
_components = []
386-
# TODO: Break this obfuscation pattern down to a "builder" method.
387388
else:
388-
_components: List[dict] = [{"type": 1, "components": []}]
389-
if isinstance(components, list) and all(
390-
isinstance(action_row, ActionRow) for action_row in components
391-
):
392-
_components = [
393-
{
394-
"type": 1,
395-
"components": [
396-
(
397-
component._json
398-
if component._json.get("custom_id") or component._json.get("url")
399-
else []
400-
)
401-
for component in action_row.components
402-
],
403-
}
404-
for action_row in components
405-
]
406-
elif isinstance(components, list) and all(
407-
isinstance(component, (Button, SelectMenu)) for component in components
408-
):
409-
for component in components:
410-
if isinstance(component, SelectMenu):
411-
component._json["options"] = [
412-
options._json if not isinstance(options, dict) else options
413-
for options in component._json["options"]
414-
]
415-
_components = [
416-
{
417-
"type": 1,
418-
"components": [
419-
(
420-
component._json
421-
if component._json.get("custom_id") or component._json.get("url")
422-
else []
423-
)
424-
for component in components
425-
],
426-
}
427-
]
428-
elif isinstance(components, list) and all(
429-
isinstance(action_row, (list, ActionRow)) for action_row in components
430-
):
431-
_components = []
432-
for action_row in components:
433-
for component in (
434-
action_row if isinstance(action_row, list) else action_row.components
435-
):
436-
if isinstance(component, SelectMenu):
437-
component._json["options"] = [
438-
option._json for option in component.options
439-
]
440-
_components.append(
441-
{
442-
"type": 1,
443-
"components": [
444-
(
445-
component._json
446-
if component._json.get("custom_id")
447-
or component._json.get("url")
448-
else []
449-
)
450-
for component in (
451-
action_row
452-
if isinstance(action_row, list)
453-
else action_row.components
454-
)
455-
],
456-
}
457-
)
458-
elif isinstance(components, ActionRow):
459-
_components[0]["components"] = [
460-
(
461-
component._json
462-
if component._json.get("custom_id") or component._json.get("url")
463-
else []
464-
)
465-
for component in components.components
466-
]
467-
elif isinstance(components, Button):
468-
_components[0]["components"] = (
469-
[components._json]
470-
if components._json.get("custom_id") or components._json.get("url")
471-
else []
472-
)
473-
elif isinstance(components, SelectMenu):
474-
components._json["options"] = [
475-
options._json if not isinstance(options, dict) else options
476-
for options in components._json["options"]
477-
]
478-
_components[0]["components"] = (
479-
[components._json]
480-
if components._json.get("custom_id") or components._json.get("url")
481-
else []
482-
)
483-
484-
# TODO: post-v4: Add attachments into Message obj.
389+
_components = _build_components(components=components)
390+
391+
if not files or files is MISSING:
392+
_files = []
393+
elif isinstance(files, list):
394+
_files = [file._json_payload(id) for id, file in enumerate(files)]
395+
else:
396+
_files = [files._json_payload(0)]
397+
files = [files]
398+
485399
payload = Message(
486400
content=_content,
487401
tts=_tts,
488-
# file=file,
489-
# attachments=_attachments,
402+
attachments=_files,
490403
embeds=_embeds,
491404
components=_components,
492405
allowed_mentions=_allowed_mentions,
493406
)
494407

495408
channel = Channel(**await self._client.create_dm(recipient_id=int(self.user.id)))
496-
res = await self._client.create_message(channel_id=int(channel.id), payload=payload._json)
409+
res = await self._client.create_message(
410+
channel_id=int(channel.id), payload=payload._json, files=files
411+
)
497412

498413
return Message(**res, _client=self._client)
499414

interactions/api/models/gw.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ from ...models.component import ActionRow, Button, SelectMenu
55
from .channel import Channel, ThreadMember
66
from .member import Member
77
from .message import Embed, Emoji, Message, MessageInteraction, Sticker
8-
from .misc import MISSING, ClientStatus, DictSerializerMixin, Snowflake
8+
from .misc import MISSING, ClientStatus, DictSerializerMixin, Snowflake, File
99
from .presence import PresenceActivity
1010
from .role import Role
1111
from .user import User
@@ -114,7 +114,7 @@ class GuildMember(DictSerializerMixin):
114114
]
115115
] = MISSING,
116116
tts: Optional[bool] = MISSING,
117-
# attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type.
117+
files: Optional[Union[File, List[File]]] = MISSING,
118118
embeds: Optional[Union[Embed, List["Embed"]]] = MISSING,
119119
allowed_mentions: Optional[MessageInteraction] = MISSING,
120120
) -> Message: ...

interactions/api/models/member.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from .channel import Channel
55
from .flags import Permissions
6-
from .misc import MISSING, DictSerializerMixin, Snowflake
6+
from .misc import MISSING, DictSerializerMixin, File, Snowflake
77
from .role import Role
88
from .user import User
99

@@ -230,7 +230,7 @@ async def send(
230230
]
231231
] = MISSING,
232232
tts: Optional[bool] = MISSING,
233-
# attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type.
233+
files: Optional[Union[File, List[File]]] = MISSING,
234234
embeds: Optional[Union["Embed", List["Embed"]]] = MISSING, # noqa
235235
allowed_mentions: Optional["MessageInteraction"] = MISSING, # noqa
236236
) -> "Message": # noqa
@@ -243,6 +243,8 @@ async def send(
243243
:type components: Optional[Union[ActionRow, Button, SelectMenu, List[Actionrow], List[Button], List[SelectMenu]]]
244244
:param tts?: Whether the message utilizes the text-to-speech Discord programme or not.
245245
:type tts: Optional[bool]
246+
:param files?: A file or list of files to be attached to the message.
247+
:type files: Optional[Union[File, List[File]]]
246248
:param embeds?: An embed, or list of embeds for the message.
247249
:type embeds: Optional[Union[Embed, List[Embed]]]
248250
:param allowed_mentions?: The message interactions/mention limits that the message can refer to.
@@ -271,19 +273,28 @@ async def send(
271273
else:
272274
_components = _build_components(components=components)
273275

276+
if not files or files is MISSING:
277+
_files = []
278+
elif isinstance(files, list):
279+
_files = [file._json_payload(id) for id, file in enumerate(files)]
280+
else:
281+
_files = [files._json_payload(0)]
282+
files = [files]
283+
274284
# TODO: post-v4: Add attachments into Message obj.
275285
payload = Message(
276286
content=_content,
277287
tts=_tts,
278-
# file=file,
279-
# attachments=_attachments,
288+
attachments=_files,
280289
embeds=_embeds,
281290
components=_components,
282291
allowed_mentions=_allowed_mentions,
283292
)
284293

285294
channel = Channel(**await self._client.create_dm(recipient_id=int(self.user.id)))
286-
res = await self._client.create_message(channel_id=int(channel.id), payload=payload._json)
295+
res = await self._client.create_message(
296+
channel_id=int(channel.id), payload=payload._json, files=files
297+
)
287298

288299
return Message(**res, _client=self._client)
289300

interactions/api/models/member.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import datetime
22
from typing import Any, List, Optional, Union
33

4-
from .misc import DictSerializerMixin, MISSING, Snowflake
4+
from .misc import DictSerializerMixin, MISSING, Snowflake, File
55
from .role import Role
66
from .user import User
77
from .flags import Permissions
@@ -71,7 +71,7 @@ class Member(DictSerializerMixin):
7171
]
7272
] = MISSING,
7373
tts: Optional[bool] = MISSING,
74-
# attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type.
74+
files: Optional[Union[File, List[File]]] = MISSING,
7575
embeds: Optional[Union[Embed, List["Embed"]]] = MISSING,
7676
allowed_mentions: Optional[MessageInteraction] = MISSING,
7777
) -> Message: ...

0 commit comments

Comments
 (0)