Browse Source

chore: prevent storing non-interactable views and various fixes

pull/10166/head
DA-344 1 month ago
parent
commit
3697a9b96c
  1. 2
      discord/abc.py
  2. 2
      discord/channel.py
  3. 4
      discord/interactions.py
  4. 6
      discord/message.py
  5. 21
      discord/ui/view.py
  6. 4
      discord/webhook/async_.py

2
discord/abc.py

@ -1678,7 +1678,7 @@ class Messageable:
data = await state.http.send_message(channel.id, params=params)
ret = state.create_message(channel=channel, data=data)
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
state.store_view(view, ret.id)
if poll:

2
discord/channel.py

@ -3027,7 +3027,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable):
data = await state.http.start_thread_in_forum(self.id, params=params, reason=reason)
thread = Thread(guild=self.guild, state=self._state, data=data)
message = Message(state=self._state, channel=thread, data=data['message'])
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
self._state.store_view(view, message.id)
return ThreadWithMessage(thread=thread, message=message)

4
discord/interactions.py

@ -592,7 +592,7 @@ class Interaction(Generic[ClientT]):
# The message channel types should always match
state = _InteractionMessageState(self, self._state)
message = InteractionMessage(state=state, channel=self.channel, data=data) # type: ignore
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
self._state.store_view(view, message.id, interaction_id=self.id)
return message
@ -1252,7 +1252,7 @@ class InteractionResponse(Generic[ClientT]):
params=params,
)
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
state.store_view(view, message_id, interaction_id=original_interaction_id)
self._response_type = InteractionResponseType.message_update

6
discord/message.py

@ -1443,8 +1443,8 @@ class PartialMessage(Hashable):
data = await self._state.http.edit_message(self.channel.id, self.id, params=params)
message = Message(state=self._state, channel=self.channel, data=data)
if view and not view.is_finished():
interaction: Optional[MessageInteraction] = getattr(self, 'interaction', None)
if view and not view.is_finished() and view.is_dispatchable():
interaction: Optional[MessageInteractionMetadata] = getattr(self, 'interaction_metadata', None)
if interaction is not None:
self._state.store_view(view, self.id, interaction_id=interaction.id)
else:
@ -3033,7 +3033,7 @@ class Message(PartialMessage, Hashable):
data = await self._state.http.edit_message(self.channel.id, self.id, params=params)
message = Message(state=self._state, channel=self.channel, data=data)
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
self._state.store_view(view, self.id)
if delete_after is not None:

21
discord/ui/view.py

@ -70,7 +70,7 @@ from ..components import (
SelectOption,
Container as ContainerComponent,
)
from ..utils import get as _utils_get, _get_as_snowflake
from ..utils import get as _utils_get, _get_as_snowflake, find as _utils_find
from ..enums import SeparatorSpacing, TextStyle, try_enum, ButtonStyle
from ..emoji import PartialEmoji
@ -412,8 +412,9 @@ class BaseView:
await asyncio.sleep(self.__timeout_expiry - now)
def is_dispatchable(self) -> bool:
# this is used by webhooks to check whether a view requires a state attached
# or not, this simply is, whether a view has a component other than a url button
# checks whether any interactable items (buttons or selects) are present
# in this view, and check whether this requires a state attached in case
# of webhooks and if the view should be stored in the view store
return any(item.is_dispatchable() for item in self.children)
def has_components_v2(self) -> bool:
@ -1102,13 +1103,13 @@ class ViewStore:
view_cls = View if not interaction.message.flags.components_v2 else LayoutView
view = view_cls.from_message(interaction.message, timeout=None)
try:
base_item = next(
child
for child in view.walk_children()
if child.type.value == component_type and getattr(child, 'custom_id', None) == custom_id
base_item = _utils_find(
lambda i: i.type.value == component_type and getattr(i, 'custom_id', None) == custom_id,
view.walk_children(),
)
except StopIteration:
# if the item is not found then return
if not base_item:
return
try:
@ -1124,7 +1125,7 @@ class ViewStore:
try:
child_index = parent._children.index(base_item) # type: ignore
except ValueError:
# handle cases in which the item is a section accesory
# handle cases in which the item is a section accessory
if getattr(base_item._parent, '__discord_ui_section__', False):
if (
base_item._parent.accessory.type.value == component_type # type: ignore

4
discord/webhook/async_.py

@ -1921,7 +1921,7 @@ class Webhook(BaseWebhook):
if wait:
msg = self._create_message(data, thread=thread)
if view is not MISSING and not view.is_finished():
if view is not MISSING and not view.is_finished() and view.is_dispatchable():
message_id = None if msg is None else msg.id
self._state.store_view(view, message_id)
@ -2124,7 +2124,7 @@ class Webhook(BaseWebhook):
)
message = self._create_message(data, thread=thread)
if view and not view.is_finished():
if view and not view.is_finished() and view.is_dispatchable():
self._state.store_view(view, message_id)
return message

Loading…
Cancel
Save