diff --git a/CHANGELOG.md b/CHANGELOG.md index 02294de6da..6928a6bac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,11 @@ These changes are available on the `master` branch, but have not yet been releas ([#2153](https://github.com/Pycord-Development/pycord/pull/2153)) - Added `VoiceChannel.slowmode_delay`. ([#2112](https://github.com/Pycord-Development/pycord/pull/2112)) +- Added `ForumChannel.default_reaction_emoji` attribute. + ([#2178](https://github.com/Pycord-Development/pycord/pull/2178)) +- Added `default_reaction_emoji` parameter to `Guild.create_forum_channel()` and + `ForumChannel.edit()` methods. + ([#2178](https://github.com/Pycord-Development/pycord/pull/2178)) ### Changed diff --git a/discord/abc.py b/discord/abc.py index a7aba7ecc3..ce811492bc 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -50,6 +50,7 @@ from .invite import Invite from .iterators import HistoryIterator from .mentions import AllowedMentions +from .partial_emoji import PartialEmoji, _EmojiTag from .permissions import PermissionOverwrite, Permissions from .role import Role from .scheduled_events import ScheduledEvent @@ -507,6 +508,28 @@ async def _edit( raise InvalidArgument("type field must be of type ChannelType") options["type"] = ch_type.value + try: + default_reaction_emoji = options["default_reaction_emoji"] + except KeyError: + pass + else: + if isinstance(default_reaction_emoji, _EmojiTag): # Emoji, PartialEmoji + default_reaction_emoji = default_reaction_emoji._to_partial() + elif isinstance(default_reaction_emoji, int): + default_reaction_emoji = PartialEmoji( + name=None, id=default_reaction_emoji + ) + elif isinstance(default_reaction_emoji, str): + default_reaction_emoji = PartialEmoji.from_str(default_reaction_emoji) + else: + raise InvalidArgument( + "default_reaction_emoji must be of type: Emoji | int | str" + ) + + options[ + "default_reaction_emoji" + ] = default_reaction_emoji._to_forum_reaction_payload() + if options: return await self._state.http.edit_channel( self.id, reason=reason, **options diff --git a/discord/channel.py b/discord/channel.py index 5cd70f52f7..93925b29a9 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -32,6 +32,7 @@ from . import utils from .asset import Asset +from .emoji import Emoji from .enums import ( ChannelType, EmbeddedActivity, @@ -171,7 +172,7 @@ def to_dict(self) -> dict[str, Any]: payload: dict[str, Any] = { "name": self.name, "moderated": self.moderated, - } | self.emoji._to_forum_tag_payload() + } | self.emoji._to_forum_reaction_payload() if self.id: payload["id"] = self.id @@ -195,6 +196,7 @@ class _TextChannel(discord.abc.GuildChannel, Hashable): "last_message_id", "default_auto_archive_duration", "default_thread_slowmode_delay", + "default_reaction_emoji", "default_sort_order", "available_tags", "flags", @@ -228,7 +230,6 @@ def _update( self.name: str = data["name"] self.category_id: int | None = utils._get_as_snowflake(data, "parent_id") self._type: int = data["type"] - # This data may be missing depending on how this object is being created/updated if not data.pop("_invoke_flag", False): self.topic: str | None = data.get("topic") @@ -1008,6 +1009,10 @@ class ForumChannel(_TextChannel): The initial slowmode delay to set on newly created threads in this channel. .. versionadded:: 2.3 + default_reaction_emoji: Optional[:class:`str` | :class:`discord.Emoji`] + The default forum reaction emoji. + + .. versionadded:: 2.5 """ def __init__( @@ -1022,6 +1027,15 @@ def _update(self, guild: Guild, data: ForumChannelPayload) -> None: for tag in (data.get("available_tags") or []) ] self.default_sort_order: SortOrder | None = data.get("default_sort_order", None) + reaction_emoji_ctx: dict = data.get("default_reaction_emoji") + if reaction_emoji_ctx is not None: + emoji_name = reaction_emoji_ctx.get("emoji_name") + if emoji_name is not None: + self.default_reaction_emoji = reaction_emoji_ctx["emoji_name"] + else: + self.default_reaction_emoji = self._state.get_emoji( + utils._get_as_snowflake(reaction_emoji_ctx, "emoji_id") + ) @property def guidelines(self) -> str | None: @@ -1061,6 +1075,7 @@ async def edit( default_auto_archive_duration: ThreadArchiveDuration = ..., default_thread_slowmode_delay: int = ..., default_sort_order: SortOrder = ..., + default_reaction_emoji: Emoji | int | str | None = ..., available_tags: list[ForumTag] = ..., require_tag: bool = ..., overwrites: Mapping[Role | Member | Snowflake, PermissionOverwrite] = ..., @@ -1113,6 +1128,12 @@ async def edit(self, *, reason=None, **options): The default sort order type to use to order posts in this channel. .. versionadded:: 2.3 + default_reaction_emoji: Optional[:class:`discord.Emoji` | :class:`int` | :class:`str`] + The default reaction emoji. + Can be a unicode emoji or a custom emoji in the forms: + :class:`Emoji`, snowflake ID, string representation (eg. ''). + + .. versionadded:: 2.5 available_tags: List[:class:`ForumTag`] The set of tags that can be used in this channel. Must be less than `20`. diff --git a/discord/guild.py b/discord/guild.py index 2f449beb60..f2ef9aa8a0 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -47,7 +47,7 @@ from .channel import * from .channel import _guild_channel_factory, _threaded_guild_channel_factory from .colour import Colour -from .emoji import Emoji +from .emoji import Emoji, PartialEmoji, _EmojiTag from .enums import ( AuditLogAction, AutoModEventType, @@ -1395,6 +1395,7 @@ async def create_forum_channel( slowmode_delay: int = MISSING, nsfw: bool = MISSING, overwrites: dict[Role | Member, PermissionOverwrite] = MISSING, + default_reaction_emoji: Emoji | int | str = MISSING, ) -> ForumChannel: """|coro| @@ -1436,6 +1437,12 @@ async def create_forum_channel( To mark the channel as NSFW or not. reason: Optional[:class:`str`] The reason for creating this channel. Shows up on the audit log. + default_reaction_emoji: Optional[:class:`Emoji` | :class:`int` | :class:`str`] + The default reaction emoji. + Can be a unicode emoji or a custom emoji in the forms: + :class:`Emoji`, snowflake ID, string representation (eg. ''). + + .. versionadded:: v2.5 Returns ------- @@ -1449,7 +1456,7 @@ async def create_forum_channel( HTTPException Creating the channel failed. InvalidArgument - The permission overwrite information is not in proper form. + The argument is not in proper form. Examples -------- @@ -1485,6 +1492,24 @@ async def create_forum_channel( if nsfw is not MISSING: options["nsfw"] = nsfw + if default_reaction_emoji is not MISSING: + if isinstance(default_reaction_emoji, _EmojiTag): # Emoji, PartialEmoji + default_reaction_emoji = default_reaction_emoji._to_partial() + elif isinstance(default_reaction_emoji, int): + default_reaction_emoji = PartialEmoji( + name=None, id=default_reaction_emoji + ) + elif isinstance(default_reaction_emoji, str): + default_reaction_emoji = PartialEmoji.from_str(default_reaction_emoji) + else: + raise InvalidArgument( + "default_reaction_emoji must be of type: Emoji | int | str" + ) + + options[ + "default_reaction_emoji" + ] = default_reaction_emoji._to_forum_reaction_payload() + data = await self._create_channel( name, overwrites=overwrites, diff --git a/discord/http.py b/discord/http.py index 40d9ebd928..30184b665a 100644 --- a/discord/http.py +++ b/discord/http.py @@ -1096,6 +1096,7 @@ def create_channel( "rtc_region", "video_quality_mode", "auto_archive_duration", + "default_reaction_emoji", ) payload.update( {k: v for k, v in options.items() if k in valid_keys and v is not None} diff --git a/discord/partial_emoji.py b/discord/partial_emoji.py index ec5495c7af..171d6390c5 100644 --- a/discord/partial_emoji.py +++ b/discord/partial_emoji.py @@ -160,11 +160,11 @@ def to_dict(self) -> dict[str, Any]: def _to_partial(self) -> PartialEmoji: return self - def _to_forum_tag_payload( + def _to_forum_reaction_payload( self, - ) -> TypedDict("TagPayload", {"emoji_id": int, "emoji_name": None}) | TypedDict( - "TagPayload", {"emoji_id": None, "emoji_name": str} - ): + ) -> TypedDict( + "ReactionPayload", {"emoji_id": int, "emoji_name": None} + ) | TypedDict("ReactionPayload", {"emoji_id": None, "emoji_name": str}): if self.id is None: return {"emoji_id": None, "emoji_name": self.name} else: