Skip to content

Commit 56ccd14

Browse files
authored
Add files via upload
1 parent 5c9dd6a commit 56ccd14

File tree

6 files changed

+141
-34
lines changed

6 files changed

+141
-34
lines changed

discord/abc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,8 @@ async def send(self, content=None, *, tts=False, embed=None, components=None, fi
961961
Indicates if the message should be sent using text-to-speech.
962962
embed: :class:`~discord.Embed`
963963
The rich embed for the content.
964+
components: List[:class:`discord.ActionRow`]
965+
A list of :type:`discord.Actionrow`'s
964966
file: :class:`~discord.File`
965967
The file to upload.
966968
files: List[:class:`~discord.File`]
@@ -1032,7 +1034,6 @@ async def send(self, content=None, *, tts=False, embed=None, components=None, fi
10321034
components = components_list
10331035

10341036

1035-
10361037
if allowed_mentions is not None:
10371038
if state.allowed_mentions is not None:
10381039
allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()

discord/components.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
DEALINGS IN THE SOFTWARE.
2727
"""
2828

29-
3029
import re
3130
import typing
3231
from .emoji import Emoji
@@ -282,13 +281,17 @@ def __init__(self, *args, **kwargs):
282281
self.components.append(obj)
283282
elif isinstance(obj, dict):
284283
if not obj.get('type', None) in [2, 3]:
285-
raise InvalidData('if you use an Dict instead of Button, DropdownMenue you have to pass an type')
284+
raise InvalidData('if you use an Dict instead of Button, DropdownMenue you have to pass an type betwean 2 or 3')
286285
self.components.append({1: Button.from_dict(obj), 2: DropdownMenue.from_dict(obj)}.get(obj.get('type')))
287286

288287
def sendable(self) -> Union[dict, EmptyActionRow]:
289-
base = {'type': 1, 'components': [obj.to_dict() for obj in self.components]}
290-
if not len(base['components']) >= 1 and self.force is False:
288+
base = []
289+
base.extend([{'type': 1, 'components': [obj.to_dict() for obj in self.components[five:5:]]} for five in range(0, len(self.components), 5)])
290+
objects = len([i['components'] for i in base])
291+
if any(len(ar['components']) < 1 for ar in base) and self.force is False:
291292
raise EmptyActionRow()
293+
elif len(base) > 5 or objects > 5*5 :
294+
raise InvalidArgument(f"The maximum number of ActionRow's per message is 5 and they can only contain 5 buttons each; you have {len(base)} ActionRow's passed with {objects} objects")
292295
return base
293296

294297
def edit_obj(self, index: int, **kwargs):
@@ -303,7 +306,7 @@ def disable_all_buttons(self):
303306

304307
@property
305308
def raw(self) -> dict:
306-
return {'type': 1, 'components': [obj.to_dict() for obj in self.components]}
309+
yield (o for o in self.components)
307310

308311
@classmethod
309312
def from_dict(cls, data):
@@ -365,6 +368,8 @@ def __init__(self, value):
365368
self._other_elements.append(ActionRow.from_dict(obj))
366369
except InvalidData:
367370
self._other_elements.append(obj)
371+
if self._other_elements:
372+
raise InvalidArgument(f"Invalid Type(s): {[o for o in self._other_elements]} are/is of type(s) {[type(o) for o in self._other_elements]} but has to bee an discord.ActionRow.")
368373

369374
@property
370375
def action_rows(self):

discord/http.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
66
Copyright (c) 2015-present Rapptz
77
8+
Implementing of the Discord-Message-components made by mccoderpy (Discord-User mccuber04#2960)
9+
810
Permission is hereby granted, free of charge, to any person obtaining a
911
copy of this software and associated documentation files (the "Software"),
1012
to deal in the Software without restriction, including without limitation
@@ -96,6 +98,9 @@ class HTTPClient:
9698
SUCCESS_LOG = '{method} {url} has received {text}'
9799
REQUEST_LOG = '{method} {url} with {json} has returned {status}'
98100

101+
# we have to overwride that beacuse interactions are using v8
102+
V8BASE = 'https://discord.com/api/v8'
103+
99104
def __init__(self, connector=None, *, proxy=None, proxy_auth=None, loop=None, unsync_clock=True):
100105
self.loop = asyncio.get_event_loop() if loop is None else loop
101106
self.connector = connector
@@ -443,13 +448,16 @@ def edit_message(self, channel_id, message_id, **fields):
443448

444449
def post_initial_response(self, use_webhook, _resp, interaction_id, token, application_id):
445450
r_url = f"/webhooks/{application_id}/{token}" if use_webhook is True else f"/interactions/{interaction_id}/{token}/callback"
446-
r = Route("POST", r_url, base='https://discord.com/api/v8')
447-
try:
448-
request = self.request(r, json=_resp)
449-
except NotFound:
450-
raise HTTPException("You have already responded to this Interaction!")
451+
r = Route("POST", r_url, self.V8BASE)
452+
return self.request(r, json=_resp )
453+
454+
def edit_interaction_response(self, use_webhook, interaction_id, token, application_id, fields):
455+
r_url = f"/webhooks/{application_id}/{token}" if use_webhook is True else f"/interactions/{interaction_id}/{token}/callback"
456+
if fields.get('type', None) == 7:
457+
r = Route("POST", r_url, self.V8BASE)
451458
else:
452-
return request
459+
r = Route('PATCH', f"/webhooks/{application_id}/{token}/messages/@original" if use_webhook is True else f"/interactions/{application_id}/{token}/messages/@original", self.V8BASE)
460+
return self.request(r, json=fields)
453461

454462
def add_reaction(self, channel_id, message_id, emoji):
455463
r = Route('PUT', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me',

discord/message.py

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
from .partial_emoji import PartialEmoji
4141
from .calls import CallMessage
4242
from .enums import MessageType, ChannelType, try_enum
43-
from .errors import InvalidArgument, ClientException, HTTPException
43+
from .errors import InvalidArgument, ClientException, HTTPException, NotFound
4444
from .embeds import Embed
45-
from .components import DecodeMessageComponents
45+
from .components import DecodeMessageComponents, Button, DropdownMenue, ActionRow
4646
from .member import Member
4747
from .flags import MessageFlags
4848
from .file import File
@@ -557,7 +557,7 @@ def __init__(self, *, state, channel, data):
557557
self.reactions = [Reaction(message=self, data=d) for d in data.get('reactions', [])]
558558
self.attachments = [Attachment(data=a, state=self._state) for a in data['attachments']]
559559
self.embeds = [Embed.from_dict(a) for a in data['embeds']]
560-
self.components = data.get('components', None)
560+
self.components = data.get('components', [])
561561
self.application = data.get('application')
562562
self.activity = data.get('activity')
563563
self.channel = channel
@@ -842,7 +842,7 @@ def clean_content(self):
842842
.. note::
843843
844844
This *does not* affect markdown. If you want to escape
845-
or remove markdown then use :func:`utils.escape_markdown` or :func:`utils.remove_markdown`
845+
or remove markdown then use :func:`utils.escape_markdown` or :func:`utils.remove_markdown`
846846
respectively, along with this function.
847847
"""
848848

@@ -1053,6 +1053,8 @@ async def edit(self, **fields):
10531053
embed: Optional[:class:`Embed`]
10541054
The new embed to replace the original with.
10551055
Could be ``None`` to remove the embed.
1056+
components: List[:class:`discord.ActionRow`]
1057+
A list of :type:`discord.Actionrow`'s
10561058
suppress: :class:`bool`
10571059
Whether to suppress embeds for the message. This removes
10581060
all the embeds if set to ``True``. If set to ``False``
@@ -1090,15 +1092,23 @@ async def edit(self, **fields):
10901092
fields['content'] = str(content)
10911093

10921094
try:
1093-
embed = fields['embed']
1095+
embed = fields.pop('embed')
10941096
except KeyError:
10951097
pass
10961098
else:
10971099
if embed is not None:
1098-
fields['embed'] = embed.to_dict()
1100+
fields['embeds'] = [embed.to_dict()]
10991101

11001102
try:
1101-
components = fields.get('components')
1103+
embeds = fields['embeds']
1104+
except KeyError:
1105+
pass
1106+
else:
1107+
if embeds is not None and not embed:
1108+
fields['embeds'] = [e.to_dict() for e in embeds]
1109+
1110+
try:
1111+
components = fields['components']
11021112
except KeyError:
11031113
pass
11041114
else:
@@ -1111,7 +1121,7 @@ async def edit(self, **fields):
11111121
elif isinstance(component, DropdownMenue):
11121122
components_list.append(component.to_dict())
11131123
elif isinstance(component, ActionRow):
1114-
components_list.append(component.sendable())
1124+
components_list.extend(component.sendable())
11151125
fields['components'] = components_list
11161126
try:
11171127
suppress = fields.pop('suppress')
@@ -1136,10 +1146,31 @@ async def edit(self, **fields):
11361146
allowed_mentions = allowed_mentions.to_dict()
11371147
fields['allowed_mentions'] = allowed_mentions
11381148

1139-
if fields:
1140-
data = await self._state.http.edit_message(self.channel.id, self.id, **fields)
1141-
self._update(data)
1149+
is_interaction_responce = fields.pop('__is_interaction_responce', None)
1150+
if is_interaction_responce is True:
1151+
deffered = fields.pop('__deffered', False)
1152+
use_webhook = fields.pop('__use_webhook', False)
1153+
interaction_id = fields.pop('__interaction_id', None)
1154+
interaction_token = fields.pop('__interaction_token', None)
1155+
application_id = fields.pop('__application_id', None)
1156+
payload = {'data': fields}
1157+
if not deffered is True:
1158+
payload['type'] = 7
1159+
if payload:
1160+
try:
1161+
data = await self._state.http.edit_interaction_response(use_webhook=use_webhook,
1162+
interaction_id=interaction_id,
1163+
token=interaction_token,
1164+
application_id=application_id,
1165+
fields=payload)
1166+
except NotFound:
1167+
raise NotFound("You have already responded to this Interaction!")
1168+
else:
1169+
self._update(dict(data))
11421170

1171+
elif is_interaction_responce is None:
1172+
payload = await self._state.http.edit_message(self.channel.id, self.id, **fields)
1173+
self._update(payload)
11431174
if delete_after is not None:
11441175
await self.delete(delay=delete_after)
11451176

@@ -1548,6 +1579,8 @@ async def edit(self, **fields):
15481579
embed: Optional[:class:`Embed`]
15491580
The new embed to replace the original with.
15501581
Could be ``None`` to remove the embed.
1582+
components: List[:class:`discord.ActionRow`]
1583+
A list of :type:`discord.Actionrow`'s
15511584
suppress: :class:`bool`
15521585
Whether to suppress embeds for the message. This removes
15531586
all the embeds if set to ``True``. If set to ``False``
@@ -1590,21 +1623,36 @@ async def edit(self, **fields):
15901623
fields['content'] = str(content)
15911624

15921625
try:
1593-
embed = fields['embed']
1626+
embed = fields.pop('embed')
15941627
except KeyError:
15951628
pass
15961629
else:
15971630
if embed is not None:
1598-
fields['embed'] = embed.to_dict()
1631+
fields['embeds'] = [embed.to_dict()]
1632+
1633+
try:
1634+
embeds = fields['embeds']
1635+
except KeyError:
1636+
pass
1637+
else:
1638+
if embeds is not None and not embed:
1639+
fields['embeds'] = [e.to_dict() for e in embeds]
15991640

16001641
try:
16011642
components = fields['components']
16021643
except KeyError:
16031644
pass
16041645
else:
1646+
_components = []
16051647
if components is not None:
1606-
#print(components)
1607-
fields['components'] = components.to_dict()
1648+
for component in ([components] if not type(components) == list else components):
1649+
if isinstance(component, Button):
1650+
_components.append(component.to_dict())
1651+
elif isinstance(component, DropdownMenue):
1652+
_components.append(component.to_dict())
1653+
elif isinstance(component, ActionRow):
1654+
_components.extend(component.sendable())
1655+
fields['components'] = _components
16081656

16091657
try:
16101658
suppress = fields.pop('suppress')
@@ -1629,8 +1677,31 @@ async def edit(self, **fields):
16291677
allowed_mentions = allowed_mentions.to_dict()
16301678
fields['allowed_mentions'] = allowed_mentions
16311679

1632-
if fields:
1633-
data = await self._state.http.edit_message(self.channel.id, self.id, **fields)
1680+
is_interaction_responce = fields.pop('__is_interaction_responce', None)
1681+
if is_interaction_responce is True:
1682+
deffered = fields.pop('__deffered', False)
1683+
use_webhook = fields.pop('__use_webhook', False)
1684+
interaction_id = fields.pop('__interaction_id', None)
1685+
interaction_token = fields.pop('__interaction_token', None)
1686+
application_id = fields.pop('__application_id', None)
1687+
payload = {'data': fields}
1688+
if not deffered is True:
1689+
payload['type'] = 7
1690+
if payload:
1691+
try:
1692+
r = await self._state.http.edit_interaction_response(use_webhook=use_webhook,
1693+
interaction_id=interaction_id,
1694+
token=interaction_token,
1695+
application_id=application_id,
1696+
fields=payload)
1697+
except NotFound:
1698+
raise NotFound(r, "You have already responded to this Interaction!")
1699+
else:
1700+
self._update(payload['data'])
1701+
1702+
elif is_interaction_responce is None:
1703+
payload = await self._state.http.edit_message(self.channel.id, self.id, **fields)
1704+
self._update(payload)
16341705

16351706
if delete_after is not None:
16361707
await self.delete(delay=delete_after)

discord/raw_models.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
66
Copyright (c) 2015-present Rapptz
77
8+
Implementing of the Discord-Message-components made by mccoderpy (Discord-User mccuber04#2960)
9+
810
Permission is hereby granted, free of charge, to any person obtaining a
911
copy of this software and associated documentation files (the "Software"),
1012
to deal in the Software without restriction, including without limitation
@@ -247,6 +249,7 @@ def __init__(self, data, http=None):
247249
self._version = data.get('version', None)
248250
self._type = data.get('type', None)
249251
self.__token = data.get('token', None)
252+
self._raw = data
250253
self._message_id = data.get('message').get('id', None)
251254
self._data = data.get('data', None)
252255
self._member = data.get('member', None)
@@ -268,13 +271,28 @@ async def defer(self):
268271
'Defers' the response, showing a loading state to the user
269272
"""
270273
if self._deferred:
271-
raise Exception("You have already responded to this Interaction!")
274+
return print("\033[91You have already responded to this Interaction!\033[0m")
272275
base = {"type": 6}
273276
try:
274277
await self.http.post_initial_response(_resp=base, use_webhook=False, interaction_id=self.__interaction_id, token=self.__token, application_id=self.__application_id)
275278
except NotFound:
276279
pass
277-
self._deferred = True
280+
else:
281+
self._deferred = True
282+
283+
async def edit(self, **fields):
284+
"""
285+
'Defers' if it isn't yet and edit the message
286+
"""
287+
if not self.message:
288+
self.message: Message = await self.channel.fetch_message(self._message_id)
289+
290+
try:
291+
await self.message.edit(__is_interaction_responce=True, __deffered=self._deferred, __use_webhook=False, __interaction_id=self.__interaction_id, __interaction_token=self.__token, __application_id=self.__application_id, **fields)
292+
except NotFound:
293+
pass
294+
else:
295+
self._deferred = True
278296

279297
@property
280298
def deffered(self):

discord/state.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,10 @@ def parse_message_update(self, data):
535535
self.dispatch('raw_message_edit', raw)
536536

537537
def parse_interaction_create(self, data):
538+
538539
if data.get('type', data.get('t', None)) != 3:
540+
#to make sure that other-libraries like `discord-py-slash-command` still work
541+
self.dispatch('socket_responce', data)
539542
return
540543
raw = RawInteractionCreateEvent(data=data, http=self.http)
541544
raw.message = self._get_message(raw.message_id)
@@ -545,10 +548,11 @@ def parse_interaction_create(self, data):
545548
raw.member: Member = Member(guild=raw.guild, data=raw._member, state=self)
546549
else:
547550
raw.channel = self._get_private_channel(raw.channel_id)
548-
raw.user = User(data=raw._user, state=self)
549-
if raw.message:
550-
self.dispatch('raw_interaction_create', raw)
551+
if raw._user is not None:
552+
raw.user = self.get_user(raw._user.get('id', None))
553+
if raw.message is not None:
551554
self.dispatch('interaction_create', raw)
555+
self.dispatch('raw_interaction_create', raw)
552556
else:
553557
self.dispatch('raw_interaction_create', raw)
554558

0 commit comments

Comments
 (0)