mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-11 04:17:58 +00:00
Add support for sending views in stateless webhooks
This commit is contained in:
parent
8edf433255
commit
6ab747f9e5
@ -214,6 +214,11 @@ class View:
|
|||||||
# Wait N seconds to see if timeout data has been refreshed
|
# Wait N seconds to see if timeout data has been refreshed
|
||||||
await asyncio.sleep(self.__timeout_expiry - now)
|
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
|
||||||
|
return any(item.is_dispatchable() for item in self.children)
|
||||||
|
|
||||||
def to_components(self) -> List[Dict[str, Any]]:
|
def to_components(self) -> List[Dict[str, Any]]:
|
||||||
def key(item: Item) -> int:
|
def key(item: Item) -> int:
|
||||||
return item._rendered_row or 0
|
return item._rendered_row or 0
|
||||||
|
@ -310,8 +310,9 @@ class AsyncWebhookAdapter:
|
|||||||
files: Optional[Sequence[File]] = None,
|
files: Optional[Sequence[File]] = None,
|
||||||
thread_id: Optional[int] = None,
|
thread_id: Optional[int] = None,
|
||||||
wait: bool = False,
|
wait: bool = False,
|
||||||
|
with_components: bool = False,
|
||||||
) -> Response[Optional[MessagePayload]]:
|
) -> Response[Optional[MessagePayload]]:
|
||||||
params = {'wait': int(wait)}
|
params = {'wait': int(wait), 'with_components': int(with_components)}
|
||||||
if thread_id:
|
if thread_id:
|
||||||
params['thread_id'] = thread_id
|
params['thread_id'] = thread_id
|
||||||
route = Route('POST', '/webhooks/{webhook_id}/{webhook_token}', webhook_id=webhook_id, webhook_token=token)
|
route = Route('POST', '/webhooks/{webhook_id}/{webhook_token}', webhook_id=webhook_id, webhook_token=token)
|
||||||
@ -1715,10 +1716,9 @@ class Webhook(BaseWebhook):
|
|||||||
|
|
||||||
.. versionadded:: 1.4
|
.. versionadded:: 1.4
|
||||||
view: :class:`discord.ui.View`
|
view: :class:`discord.ui.View`
|
||||||
The view to send with the message. You can only send a view
|
The view to send with the message. If the webhook is partial or
|
||||||
if this webhook is not partial and has state attached. A
|
is not managed by the library, then you can only send URL buttons.
|
||||||
webhook has state attached if the webhook is managed by the
|
Otherwise, you can send views with any type of components.
|
||||||
library.
|
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
thread: :class:`~discord.abc.Snowflake`
|
thread: :class:`~discord.abc.Snowflake`
|
||||||
@ -1770,7 +1770,8 @@ class Webhook(BaseWebhook):
|
|||||||
The length of ``embeds`` was invalid, there was no token
|
The length of ``embeds`` was invalid, there was no token
|
||||||
associated with this webhook or ``ephemeral`` was passed
|
associated with this webhook or ``ephemeral`` was passed
|
||||||
with the improper webhook type or there was no state
|
with the improper webhook type or there was no state
|
||||||
attached with this webhook when giving it a view.
|
attached with this webhook when giving it a view that had
|
||||||
|
components other than URL buttons.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
---------
|
---------
|
||||||
@ -1800,13 +1801,15 @@ class Webhook(BaseWebhook):
|
|||||||
wait = True
|
wait = True
|
||||||
|
|
||||||
if view is not MISSING:
|
if view is not MISSING:
|
||||||
if isinstance(self._state, _WebhookState):
|
|
||||||
raise ValueError('Webhook views require an associated state with the webhook')
|
|
||||||
|
|
||||||
if not hasattr(view, '__discord_ui_view__'):
|
if not hasattr(view, '__discord_ui_view__'):
|
||||||
raise TypeError(f'expected view parameter to be of type View not {view.__class__.__name__}')
|
raise TypeError(f'expected view parameter to be of type View not {view.__class__.__name__}')
|
||||||
|
|
||||||
if ephemeral is True and view.timeout is None:
|
if isinstance(self._state, _WebhookState) and view.is_dispatchable():
|
||||||
|
raise ValueError(
|
||||||
|
'Webhook views with any component other than URL buttons require an associated state with the webhook'
|
||||||
|
)
|
||||||
|
|
||||||
|
if ephemeral is True and view.timeout is None and view.is_dispatchable():
|
||||||
view.timeout = 15 * 60.0
|
view.timeout = 15 * 60.0
|
||||||
|
|
||||||
if thread_name is not MISSING and thread is not MISSING:
|
if thread_name is not MISSING and thread is not MISSING:
|
||||||
@ -1850,6 +1853,7 @@ class Webhook(BaseWebhook):
|
|||||||
files=params.files,
|
files=params.files,
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
wait=wait,
|
wait=wait,
|
||||||
|
with_components=view is not MISSING,
|
||||||
)
|
)
|
||||||
|
|
||||||
msg = None
|
msg = None
|
||||||
|
@ -66,6 +66,7 @@ if TYPE_CHECKING:
|
|||||||
from ..message import Attachment
|
from ..message import Attachment
|
||||||
from ..abc import Snowflake
|
from ..abc import Snowflake
|
||||||
from ..state import ConnectionState
|
from ..state import ConnectionState
|
||||||
|
from ..ui import View
|
||||||
from ..types.webhook import (
|
from ..types.webhook import (
|
||||||
Webhook as WebhookPayload,
|
Webhook as WebhookPayload,
|
||||||
)
|
)
|
||||||
@ -290,8 +291,9 @@ class WebhookAdapter:
|
|||||||
files: Optional[Sequence[File]] = None,
|
files: Optional[Sequence[File]] = None,
|
||||||
thread_id: Optional[int] = None,
|
thread_id: Optional[int] = None,
|
||||||
wait: bool = False,
|
wait: bool = False,
|
||||||
|
with_components: bool = False,
|
||||||
) -> MessagePayload:
|
) -> MessagePayload:
|
||||||
params = {'wait': int(wait)}
|
params = {'wait': int(wait), 'with_components': int(with_components)}
|
||||||
if thread_id:
|
if thread_id:
|
||||||
params['thread_id'] = thread_id
|
params['thread_id'] = thread_id
|
||||||
route = Route('POST', '/webhooks/{webhook_id}/{webhook_token}', webhook_id=webhook_id, webhook_token=token)
|
route = Route('POST', '/webhooks/{webhook_id}/{webhook_token}', webhook_id=webhook_id, webhook_token=token)
|
||||||
@ -919,6 +921,7 @@ class SyncWebhook(BaseWebhook):
|
|||||||
silent: bool = False,
|
silent: bool = False,
|
||||||
applied_tags: List[ForumTag] = MISSING,
|
applied_tags: List[ForumTag] = MISSING,
|
||||||
poll: Poll = MISSING,
|
poll: Poll = MISSING,
|
||||||
|
view: View = MISSING,
|
||||||
) -> Optional[SyncWebhookMessage]:
|
) -> Optional[SyncWebhookMessage]:
|
||||||
"""Sends a message using the webhook.
|
"""Sends a message using the webhook.
|
||||||
|
|
||||||
@ -991,6 +994,13 @@ class SyncWebhook(BaseWebhook):
|
|||||||
When sending a Poll via webhook, you cannot manually end it.
|
When sending a Poll via webhook, you cannot manually end it.
|
||||||
|
|
||||||
.. versionadded:: 2.4
|
.. versionadded:: 2.4
|
||||||
|
view: :class:`~discord.ui.View`
|
||||||
|
The view to send with the message. This can only have URL buttons, which donnot
|
||||||
|
require a state to be attached to it.
|
||||||
|
|
||||||
|
If you want to send a view with any component attached to it, check :meth:`Webhook.send`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
--------
|
--------
|
||||||
@ -1004,8 +1014,9 @@ class SyncWebhook(BaseWebhook):
|
|||||||
You specified both ``embed`` and ``embeds`` or ``file`` and ``files``
|
You specified both ``embed`` and ``embeds`` or ``file`` and ``files``
|
||||||
or ``thread`` and ``thread_name``.
|
or ``thread`` and ``thread_name``.
|
||||||
ValueError
|
ValueError
|
||||||
The length of ``embeds`` was invalid or
|
The length of ``embeds`` was invalid, there was no token
|
||||||
there was no token associated with this webhook.
|
associated with this webhook or you tried to send a view
|
||||||
|
with components other than URL buttons.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
---------
|
---------
|
||||||
@ -1027,6 +1038,13 @@ class SyncWebhook(BaseWebhook):
|
|||||||
else:
|
else:
|
||||||
flags = MISSING
|
flags = MISSING
|
||||||
|
|
||||||
|
if view is not MISSING:
|
||||||
|
if not hasattr(view, '__discord_ui_view__'):
|
||||||
|
raise TypeError(f'expected view parameter to be of type View not {view.__class__.__name__}')
|
||||||
|
|
||||||
|
if view.is_dispatchable():
|
||||||
|
raise ValueError('SyncWebhook views can only contain URL buttons')
|
||||||
|
|
||||||
if thread_name is not MISSING and thread is not MISSING:
|
if thread_name is not MISSING and thread is not MISSING:
|
||||||
raise TypeError('Cannot mix thread_name and thread keyword arguments.')
|
raise TypeError('Cannot mix thread_name and thread keyword arguments.')
|
||||||
|
|
||||||
@ -1050,6 +1068,7 @@ class SyncWebhook(BaseWebhook):
|
|||||||
flags=flags,
|
flags=flags,
|
||||||
applied_tags=applied_tag_ids,
|
applied_tags=applied_tag_ids,
|
||||||
poll=poll,
|
poll=poll,
|
||||||
|
view=view,
|
||||||
) as params:
|
) as params:
|
||||||
adapter: WebhookAdapter = _get_webhook_adapter()
|
adapter: WebhookAdapter = _get_webhook_adapter()
|
||||||
thread_id: Optional[int] = None
|
thread_id: Optional[int] = None
|
||||||
@ -1065,6 +1084,7 @@ class SyncWebhook(BaseWebhook):
|
|||||||
files=params.files,
|
files=params.files,
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
wait=wait,
|
wait=wait,
|
||||||
|
with_components=view is not MISSING,
|
||||||
)
|
)
|
||||||
|
|
||||||
msg = None
|
msg = None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user