diff --git a/discord/enums.py b/discord/enums.py index 26547679d..3a472a050 100644 --- a/discord/enums.py +++ b/discord/enums.py @@ -1685,6 +1685,11 @@ class PollLayoutType(Enum): image_only_answers = 2 +class ReactionType(Enum): + normal = 0 + burst = 1 + + def create_unknown_value(cls: Type[E], val: Any) -> E: value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below name = f'unknown_{val}' diff --git a/discord/http.py b/discord/http.py index 0abd8c295..24b201469 100644 --- a/discord/http.py +++ b/discord/http.py @@ -1318,9 +1318,11 @@ class HTTPClient: emoji: str, limit: int, after: Optional[Snowflake] = None, + type: message.ReactionType = 0, ) -> Response[List[user.User]]: params: Dict[str, Any] = { 'limit': limit, + 'type': type, } if after: params['after'] = after diff --git a/discord/raw_models.py b/discord/raw_models.py index 893e3a615..a873f439f 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -27,7 +27,7 @@ from __future__ import annotations from typing import TYPE_CHECKING, List, Literal, Optional, Set, Tuple, Union from .colour import Colour -from .enums import ChannelType, ReadStateType, try_enum +from .enums import ChannelType, ReactionType, ReadStateType, try_enum from .utils import _get_as_snowflake if TYPE_CHECKING: @@ -216,6 +216,10 @@ class RawReactionActionEvent(_RawReprMixin): and if ``event_type`` is ``REACTION_ADD``. .. versionadded:: 2.0 + type: :class:`ReactionType` + The type of the reaction. + + .. versionadded:: 2.4 """ __slots__ = ( @@ -229,6 +233,7 @@ class RawReactionActionEvent(_RawReprMixin): 'message_author_id', 'burst', 'burst_colours', + 'type', ) def __init__(self, data: ReactionActionEvent, emoji: PartialEmoji, event_type: ReactionActionType) -> None: @@ -241,6 +246,7 @@ class RawReactionActionEvent(_RawReprMixin): self.message_author_id: Optional[int] = _get_as_snowflake(data, 'message_author_id') self.burst: bool = data.get('burst', False) self.burst_colours: List[Colour] = [Colour.from_str(c) for c in data.get('burst_colours', [])] + self.type: ReactionType = try_enum(ReactionType, data['type']) try: self.guild_id: Optional[int] = int(data['guild_id']) diff --git a/discord/reaction.py b/discord/reaction.py index f72bf216c..d2e19e1a5 100644 --- a/discord/reaction.py +++ b/discord/reaction.py @@ -27,6 +27,7 @@ from typing import TYPE_CHECKING, AsyncIterator, Union, Optional from .user import User from .object import Object +from .enums import ReactionType # fmt: off __all__ = ( @@ -186,7 +187,7 @@ class Reaction: await self.message.clear_reaction(self.emoji) async def users( - self, *, limit: Optional[int] = None, after: Optional[Snowflake] = None + self, *, limit: Optional[int] = None, after: Optional[Snowflake] = None, type: Optional[ReactionType] = None ) -> AsyncIterator[Union[Member, User]]: """Returns an :term:`asynchronous iterator` representing the users that have reacted to the message. @@ -221,6 +222,11 @@ class Reaction: reacted to the message. after: Optional[:class:`abc.Snowflake`] For pagination, reactions are sorted by member. + type: Optional[:class:`ReactionType`] + The type of reaction to return users from. + Defaults to :attr:`ReactionType.normal`. + + .. versionadded:: 2.4 Raises -------- @@ -252,7 +258,14 @@ class Reaction: state = message._state after_id = after.id if after else None - data = await state.http.get_reaction_users(message.channel.id, message.id, emoji, retrieve, after=after_id) + data = await state.http.get_reaction_users( + message.channel.id, + message.id, + emoji, + retrieve, + after=after_id, + type=type.value if type else 0, + ) if data: limit -= len(data) diff --git a/discord/types/gateway.py b/discord/types/gateway.py index ee9902e7f..58671237a 100644 --- a/discord/types/gateway.py +++ b/discord/types/gateway.py @@ -41,7 +41,7 @@ from .interactions import Modal from .invite import _InviteTargetType from .library import LibraryApplication from .member import MemberWithPresence, MemberWithUser -from .message import Message +from .message import Message, ReactionType from .payments import Payment from .read_state import ReadState, ReadStateType from .role import Role @@ -192,6 +192,7 @@ class MessageReactionAddEvent(TypedDict): message_author_id: NotRequired[Snowflake] burst: bool burst_colors: NotRequired[List[str]] + type: ReactionType class MessageReactionRemoveEvent(TypedDict): @@ -201,6 +202,7 @@ class MessageReactionRemoveEvent(TypedDict): emoji: PartialEmoji guild_id: NotRequired[Snowflake] burst: bool + type: ReactionType class MessageReactionRemoveAllEvent(TypedDict): diff --git a/discord/types/message.py b/discord/types/message.py index 008a24dfe..6b9a9e8cc 100644 --- a/discord/types/message.py +++ b/discord/types/message.py @@ -58,6 +58,9 @@ class ReactionCountDetails(TypedDict): normal: int +ReactionType = Literal[0, 1] + + class Reaction(TypedDict): count: int me: bool diff --git a/docs/api.rst b/docs/api.rst index 1459c1059..0e22d1e41 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -6053,6 +6053,21 @@ of :class:`enum.Enum`. The default layout. +.. class:: ReactionType + + Represents the type of a reaction. + + .. versionadded:: 2.4 + + .. attribute:: normal + + A normal reaction. + + .. attribute:: burst + + A burst reaction, also known as a "super reaction". + + .. _discord-api-audit-logs: Audit Log Data