Skip to content
This repository was archived by the owner on Mar 8, 2022. It is now read-only.

Commit 7d7e120

Browse files
committed
fixed #94 + added on_component event
1 parent 01599fb commit 7d7e120

File tree

7 files changed

+112
-49
lines changed

7 files changed

+112
-49
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,38 @@ You can find more (and better) examples [here](https://github.com/discord-py-ui/
175175

176176
# Changelog
177177

178+
- <details>
179+
<summary>4.2.7<summary>
180+
181+
## **Added**
182+
183+
- `on_component`
184+
> There is now an event with the name `component` that will be dispatched whenever a component was received
185+
> If you use `Message.wait_for`, there is now a new event choice with the name `component` (`message.wait_for("component", client)`)
186+
187+
188+
## **Fixed**
189+
190+
- #94
191+
> DM issue with deleting messages
192+
193+
## **Changed**
194+
195+
- `edit`
196+
> Edit now takes "content" as not positional (`.edit("the content")` works now)
197+
- component lenght
198+
> You are now able to set component values with the right max lenght
199+
200+
</details>
201+
178202
- <details>
179203
<summary>4.2.6</summary>
180204

181205
## **Fixed**
182206

183207
- emebds
184208
> there was an issue with sending embeds
185-
209+
186210
</details>
187211

188212
- <details>

discord_ui/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
from .slash.tools import ParseMethod
3838
from .tools import components_to_dict
3939
from .slash.tools import create_choice
40-
from .receive import Interaction, InteractionType, Message, WebhookMessage, PressedButton, SelectedMenu, SlashedCommand, SlashedSubCommand, EphemeralMessage, EphemeralResponseMessage
40+
from .receive import Interaction, InteractionType, Message, WebhookMessage, PressedButton, SelectedMenu, ComponentContext, SlashedCommand, SlashedSubCommand, EphemeralMessage, EphemeralResponseMessage
4141

4242
from .override import override_dpy, override_dpy2_client
4343
override_dpy2_client()
4444

4545

4646
__title__ = "discord-ui"
47-
__version__ = "4.2.6"
47+
__version__ = "4.2.7"

discord_ui/client.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
from discord.channel import TextChannel
12
from .cogs import BaseCallable, CogCommand, CogMessageCommand, CogSubCommandGroup, ListeningComponent
23
from .components import Component, ComponentType
34
from .slash.errors import NoAsyncCallback
45
from .errors import MissingListenedComponentParameters, WrongType
56
from .slash.tools import ParseMethod, cache_data, format_name, handle_options, handle_thing
67
from .slash.http import create_global_command, create_guild_command, delete_global_command, delete_guild_command, delete_guild_commands, edit_global_command, edit_guild_command, get_command, get_command_permissions, get_global_commands, get_guild_commands, delete_global_commands, get_id, update_command_permissions
78
from .slash.types import AdditionalType, CommandType, ContextCommand, MessageCommand, OptionType, SlashCommand, SlashOption, SlashSubcommand, UserCommand
8-
from .tools import MISSING, _or, get_index, setup_logger
9+
from .tools import MISSING, _none, _or, get_index, setup_logger
910
from .http import jsonifyMessage, BetterRoute, send_files
10-
from .receive import Interaction, Message, PressedButton, SelectedMenu, SlashedContext, WebhookMessage, SlashedCommand, SlashedSubCommand, getMessage
11+
from .receive import ComponentContext, Interaction, Message, PressedButton, SelectedMenu, SlashedContext, WebhookMessage, SlashedCommand, SlashedSubCommand, getMessage
1112
from .override import override_dpy as override_it
1213

1314
import discord
@@ -172,6 +173,7 @@ async def _on_response(self, msg):
172173
await interaction.defer(self.auto_defer[1])
173174
self._discord.dispatch("interaction_received", interaction)
174175

176+
175177
#region basic commands
176178
if data["data"]["type"] == CommandType.SLASH and not (data["data"].get("options") and data["data"]["options"][0]["type"] in [OptionType.SUB_COMMAND, OptionType.SUB_COMMAND_GROUP]):
177179
x = self.commands.get(data["data"]["name"])
@@ -1190,6 +1192,8 @@ async def _on_response(self, msg):
11901192
await interaction.defer(self.auto_defer[1])
11911193
self._discord.dispatch("interaction_received", interaction)
11921194

1195+
self._discord.dispatch("component", ComponentContext(self._discord._connection, data, user, msg))
1196+
11931197
# Handle auto_defer
11941198
if int(data["data"]["component_type"]) == 2:
11951199
for x in msg.buttons:
@@ -1254,10 +1258,20 @@ async def send(self, channel, content=MISSING, *, tts=False, embed=MISSING, embe
12541258
:type: :class:`~Message`
12551259
"""
12561260

1257-
if not isinstance(channel, (discord.TextChannel, int, str)):
1258-
raise WrongType("channel", channel, "discord.TextChannel")
1261+
if not isinstance(channel, (discord.TextChannel, int, str, discord.User)):
1262+
raise WrongType("channel", channel, ["discord.TextChannel", "discord.User"])
12591263

1260-
channel_id = channel.id if isinstance(channel, discord.TextChannel) else channel
1264+
channel_id = None
1265+
if isinstance(channel, discord.User):
1266+
if channel.dm_channel is None:
1267+
channel = await channel.create_dm()
1268+
channel_id = channel.id
1269+
else:
1270+
channel_id = channel.dm_channel
1271+
elif isinstance(channel, discord.TextChannel):
1272+
channel_id = channel.id
1273+
else:
1274+
channel_id = channel
12611275
payload = jsonifyMessage(content=content, tts=tts, embed=embed, embeds=embeds, nonce=nonce, allowed_mentions=allowed_mentions, reference=reference, mention_author=mention_author, components=components)
12621276

12631277
route = BetterRoute("POST", f"/channels/{channel_id}/messages")
@@ -1268,9 +1282,9 @@ async def send(self, channel, content=MISSING, *, tts=False, embed=MISSING, embe
12681282
else:
12691283
r = await send_files(route, files=_or(files, [file]), payload=payload, http=self._discord.http)
12701284

1271-
msg = Message(state=self._discord._get_state(), channel=channel, data=r)
1272-
1273-
if delete_after is not None:
1285+
msg = Message(state=self._discord._connection, channel=channel, data=r)
1286+
1287+
if not _none(delete_after):
12741288
await msg.delete(delay=delete_after)
12751289

12761290
return msg

discord_ui/components.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ def value(self) -> Any:
8181
def value(self, value):
8282
if inspect.isclass(value):
8383
raise WrongType("value", value, ["int", "str", "bool", "float"])
84+
if isinstance(value, str):
85+
if len(value) > 100 or len(value) < 1:
86+
raise InvalidLength("value", _min=1, _max=100)
8487
self._json["value"] = value
8588

8689
@property
@@ -95,8 +98,8 @@ def description(self) -> str:
9598
def description(self, value):
9699
if value is not MISSING and not isinstance(value, str):
97100
raise WrongType("description", "str")
98-
if value is not MISSING and len(value) > 50:
99-
raise InvalidLength("description", 50, 0)
101+
if value is not MISSING and len(value) > 100:
102+
raise InvalidLength("description", 100, 0)
100103
self._json["description"] = value
101104

102105
@property
@@ -288,7 +291,7 @@ def options(self) -> List[SelectOption]:
288291
def options(self, value: List[SelectOption]):
289292
if isinstance(value, list):
290293
if len(value) > 25 or len(value) == 0:
291-
raise OutOfValidRange("options", 1, 25)
294+
raise OutOfValidRange("length of options", 1, 25)
292295
if all(isinstance(x, SelectOption) for x in value):
293296
self._json["options"] = [x.to_dict() for x in value]
294297
elif all(isinstance(x, dict) for x in value):
@@ -465,8 +468,8 @@ def label(self, val: str):
465468
val = ""
466469
elif val is not None and not isinstance(val, str):
467470
raise WrongType("label", val, "str")
468-
elif val is not None and len(val) > 80:
469-
raise InvalidLength("label", _max=80)
471+
elif val is not None and len(val) > 100:
472+
raise InvalidLength("label", _max=100)
470473
elif val is not None and len(val) < 1:
471474
raise InvalidLength("label", _min=0)
472475

discord_ui/override.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ def override_dpy():
4141
async def send(self: discord.TextChannel, content=None, **kwargs) -> Message:
4242
channel_id = self.id if not isinstance(self, commands.Context) else self.channel.id
4343

44+
channel = None
4445
if isinstance(self, (discord.Member, discord.User)) and self.dm_channel is None:
45-
channel_id = (await self.create_dm()).id
46+
channel = await self.create_dm()
47+
channel_id = channel.id
4648

4749
route = BetterRoute("POST", f"/channels/{channel_id}/messages")
4850

@@ -58,7 +60,9 @@ async def send(self: discord.TextChannel, content=None, **kwargs) -> Message:
5860
payload = jsonifyMessage(content=content, **kwargs)
5961
r = await send_files(route, files=files, payload=payload, http=self._state.http)
6062

61-
msg = Message(state=self._state, channel=self if not isinstance(self, commands.Context) else self.channel, data=r)
63+
if channel is None:
64+
channel = self if not isinstance(self, commands.Context) else self.channel
65+
msg = Message(state=self._state, channel=channel, data=r)
6266
if kwargs.get("delete_after") is not None:
6367
await msg.delete(delay=kwargs.get("delete_after"))
6468

discord_ui/receive.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .slash.types import ContextCommand, SlashCommand, SlashPermission, SlashSubcommand
44
from .tools import MISSING, setup_logger, _none
55
from .http import BetterRoute, jsonifyMessage, send_files
6-
from .components import ActionRow, Button, LinkButton, SelectMenu, SelectOption, make_component
6+
from .components import ActionRow, Button, Component, LinkButton, SelectMenu, SelectOption, make_component
77

88
import discord
99
from discord.ext.commands import Bot
@@ -167,7 +167,7 @@ async def respond(self, content=MISSING, *, tts=False, embed=MISSING, embeds=MIS
167167

168168

169169
r = None
170-
if delete_after is not MISSING and hide_message is True:
170+
if not _none(delete_after) and hide_message is True:
171171
raise EphemeralDeletion()
172172

173173
if hide_message:
@@ -199,7 +199,7 @@ async def respond(self, content=MISSING, *, tts=False, embed=MISSING, embeds=MIS
199199
if not hide_message:
200200
responseMSG = await self._state.http.request(BetterRoute("GET", f"/webhooks/{self.application_id}/{self.token}/messages/@original"))
201201
msg = await getMessage(self._state, data=responseMSG, response=False)
202-
if delete_after is not MISSING:
202+
if not _none(delete_after):
203203
await msg.delete(delete_after)
204204
return msg
205205

@@ -263,6 +263,12 @@ def _handle_auto_defer(self, auto_defer):
263263
self.deferred = auto_defer[0]
264264
self._deferred_hidden = auto_defer[1]
265265

266+
class ComponentContext(Interaction, Component):
267+
"""A received component"""
268+
def __init__(self, state, data, user, message) -> None:
269+
Interaction.__init__(self, state, data, user=user, message=message)
270+
Component.__init__(self, data["data"]["component_type"])
271+
266272
class SelectedMenu(Interaction, SelectMenu):
267273
"""A :class:`~SelectMenu` object in which an item was selected"""
268274
def __init__(self, data, user, s, msg, client) -> None:
@@ -349,7 +355,7 @@ async def getMessage(state: ConnectionState, data, response = True):
349355
:class:`~Message` | :class:`~EphemeralMessage`
350356
The sent message
351357
"""
352-
channel = state.get_channel(int(data["channel_id"]))
358+
channel = state.get_channel(int(data["channel_id"])) or state._get_private_channel_by_user(data["message"]["author"]["id"])
353359
if response:
354360
if data.get("message") is not None and data.get("message", data)["flags"] == 64:
355361
return EphemeralResponseMessage(state=state, channel=channel, data=data.get("message", data))
@@ -423,7 +429,7 @@ def _update(self, data):
423429
super()._update(data)
424430
self._update_components(data)
425431

426-
async def edit(self, *, content=MISSING, embed=MISSING, embeds=MISSING, attachments=MISSING, suppress=MISSING,
432+
async def edit(self, content=MISSING, *, embed=MISSING, embeds=MISSING, attachments=MISSING, suppress=MISSING,
427433
delete_after=MISSING, allowed_mentions=MISSING, components=MISSING):
428434
"""Edits the message and updates its properties
429435
@@ -454,7 +460,7 @@ async def edit(self, *, content=MISSING, embed=MISSING, embeds=MISSING, attachme
454460
data = await self._state.http.edit_message(self.channel.id, self.id, **payload)
455461
self._update(data)
456462

457-
if delete_after is not MISSING:
463+
if not _none(delete_after):
458464
await self.delete(delay=delete_after)
459465

460466
async def disable_action_row(self, row, disable = True):
@@ -528,17 +534,17 @@ def action_rows(self):
528534
rows.append(c_row)
529535
return rows
530536

531-
async def wait_for(self, event_name: Literal["select", "button"], client, custom_id=MISSING, by=MISSING, check=lambda component: True, timeout=None) -> Union[PressedButton, SelectedMenu]:
537+
async def wait_for(self, event_name: Literal["select", "button", "component"], client, custom_id=MISSING, by=MISSING, check=lambda component: True, timeout=None) -> Union[PressedButton, SelectedMenu]:
532538
"""Waits for a message component to be invoked in this message
533539
534540
Parameters
535541
-----------
536542
event_name: :class:`str`
537-
The name of the event which will be awaited [``"select"`` | ``"button"``]
543+
The name of the event which will be awaited [``"select"`` | ``"button"`` | ``"component"``]
538544
539545
.. note::
540546
541-
``event_name`` must be ``select`` for a select menu selection and ``button`` for a button press
547+
``event_name`` must be ``select`` for a select menu selection, ``button`` for a button press and ``component`` for any component
542548
543549
client: :class:`discord.ext.commands.Bot`
544550
The discord client
@@ -577,7 +583,7 @@ async def wait_for(self, event_name: Literal["select", "button"], client, custom
577583
except asyncio.TimeoutError:
578584
# no button press was received in 20 seconds timespan
579585
"""
580-
if event_name.lower() in ["button", "select"]:
586+
if event_name.lower() in ["button", "select", "component"]:
581587
def _check(com):
582588
if com.message.id == self.id:
583589
statements = []
@@ -591,23 +597,15 @@ def _check(com):
591597
return False
592598
if not isinstance(client, Bot):
593599
raise WrongType("client", client, "discord.ext.commands.Bot")
594-
return (await client.wait_for('button_press' if event_name.lower() == "button" else "menu_select", check=_check, timeout=timeout))
600+
return (await client.wait_for('button_press' if event_name.lower() == "button" else ("menu_select" if event_name.lower() == "menu" else "component"), check=_check, timeout=timeout))
595601

596-
raise InvalidEvent(event_name, ["button", "select"])
597-
598-
class ResponseMessage(Message):
599-
r"""A message Object which extends the `Message` Object optimized for an interaction component"""
600-
def __init__(self, *, state, channel, data, user, interaction_component = None):
601-
Message.__init__(self, state=state, channel=channel, data=data["message"])
602-
self.interaction = Interaction(state, data, user, self)
603-
self.interaction_component = interaction_component
604-
602+
raise InvalidEvent(event_name, ["button", "select", "component"])
605603

606604
class WebhookMessage(Message, discord.WebhookMessage):
607605
def __init__(self, *, state, channel, data):
608606
Message.__init__(self, state=state, channel=channel, data=data)
609607
discord.WebhookMessage.__init__(self, state=state, channel=channel, data=data)
610-
async def edit(self, **fields):
608+
async def edit(self, *args, **fields):
611609
"""Edits the message
612610
613611
content: :class:`str`, Optional
@@ -621,7 +619,7 @@ async def edit(self, **fields):
621619
allowed_mentions: :class`discord.AllowedMentions`
622620
Controls the mentions being processed in this message. See `discord.abc.Messageable.send` for more information.
623621
"""
624-
return await self._state._webhook._adapter.edit_webhook_message(message_id=self.id, payload=jsonifyMessage(**fields))
622+
return await self._state._webhook._adapter.edit_webhook_message(message_id=self.id, payload=jsonifyMessage(*args, **fields))
625623

626624

627625
class EphemeralComponent(Interaction):
@@ -651,9 +649,9 @@ def __init__(self, state, channel, data, application_id=MISSING, token=MISSING):
651649
Message.__init__(self, state=state, channel=channel, data=data)
652650
self._application_id = application_id
653651
self._interaction_token = token
654-
async def edit(self, **fields):
652+
async def edit(self, *args, **fields):
655653
r = BetterRoute("PATCH", f"/webhooks/{self._application_id}/{self._interaction_token}/messages/{self.id}")
656-
self._update(await self._state.http.request(r, json=jsonifyMessage(**fields)))
654+
self._update(await self._state.http.request(r, json=jsonifyMessage(*args, **fields)))
657655
async def delete(self):
658656
"""Override for delete function that will throw an exception"""
659657
raise EphemeralDeletion()
@@ -668,7 +666,7 @@ class EphemeralResponseMessage(Message):
668666
def __init__(self, *, state, channel, data):
669667
Message.__init__(self, state=state, channel=channel, data=data)
670668

671-
async def edit(self, token, **fields):
669+
async def edit(self, token, *args, **fields):
672670
"""Edits the message
673671
674672
Parameters
@@ -689,7 +687,7 @@ async def testing(ctx):
689687
690688
"""
691689
route = BetterRoute("PATCH", f"/webhooks/{self.interaction.application_id}/{token}/messages/{self.id}")
692-
self._update(await self._state.http.request(route, json=jsonifyMessage(**fields)))
690+
self._update(await self._state.http.request(route, json=jsonifyMessage(*args, **fields)))
693691
async def delete(self):
694692
"""Override for delete function that will throw an exception"""
695693
raise EphemeralDeletion()

0 commit comments

Comments
 (0)