From 24118d0e8136174039865dc0901d157789aa085f Mon Sep 17 00:00:00 2001 From: Rapptz Date: Tue, 10 Jan 2023 16:43:18 -0500 Subject: [PATCH] Add support for ForumChannel.default_layout --- discord/channel.py | 49 ++++++++++++++++++++++++++++++++++++---- discord/enums.py | 7 ++++++ discord/http.py | 1 + discord/types/channel.py | 4 ++++ docs/api.rst | 20 ++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/discord/channel.py b/discord/channel.py index ef67da6f5..dbfdde328 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -47,7 +47,7 @@ import datetime import discord.abc from .scheduled_event import ScheduledEvent from .permissions import PermissionOverwrite, Permissions -from .enums import ChannelType, PrivacyLevel, try_enum, VideoQualityMode +from .enums import ChannelType, EntityType, ForumLayoutType, PrivacyLevel, try_enum, VideoQualityMode from .calls import PrivateCall, GroupCall from .mixins import Hashable from . import utils @@ -223,6 +223,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): def _sorting_bucket(self) -> int: return ChannelType.text.value + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return None + @utils.copy_doc(discord.abc.GuildChannel.permissions_for) def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: base = super().permissions_for(obj) @@ -1024,7 +1028,7 @@ class VoiceChannel(discord.abc.Messageable, VocalGuildChannel): Bots and users with :attr:`~Permissions.manage_channels` or :attr:`~Permissions.manage_messages` bypass slowmode. - .. versionadded:: 2.2 + .. versionadded:: 2.0 """ __slots__ = () @@ -1046,6 +1050,10 @@ class VoiceChannel(discord.abc.Messageable, VocalGuildChannel): async def _get_channel(self) -> Self: return self + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return EntityType.voice + @property def type(self) -> ChannelType: """:class:`ChannelType`: The channel's Discord type.""" @@ -1440,7 +1448,7 @@ class StageChannel(VocalGuildChannel): Bots and users with :attr:`~Permissions.manage_channels` or :attr:`~Permissions.manage_messages` bypass slowmode. - .. versionadded:: 2.2 + .. versionadded:: 2.0 """ __slots__ = ('topic',) @@ -1464,6 +1472,10 @@ class StageChannel(VocalGuildChannel): super()._update(guild, data) self.topic: Optional[str] = data.get('topic') + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return EntityType.stage_instance + @property def requesting_to_speak(self) -> List[Member]: """List[:class:`Member`]: A list of members who are requesting to speak in the stage channel.""" @@ -1743,6 +1755,10 @@ class CategoryChannel(discord.abc.GuildChannel, Hashable): def _sorting_bucket(self) -> int: return ChannelType.category.value + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return None + @property def type(self) -> ChannelType: """:class:`ChannelType`: The channel's Discord type.""" @@ -2075,6 +2091,11 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): The default reaction emoji for threads created in this forum to show in the add reaction button. + .. versionadded:: 2.0 + default_layout: :class:`ForumLayoutType` + The default layout for posts in this forum channel. + Defaults to :attr:`ForumLayoutType.not_set`. + .. versionadded:: 2.0 """ @@ -2094,6 +2115,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): 'default_auto_archive_duration', 'default_thread_slowmode_delay', 'default_reaction_emoji', + 'default_layout', '_available_tags', '_flags', ) @@ -2127,6 +2149,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): # This takes advantage of the fact that dicts are ordered since Python 3.7 tags = [ForumTag.from_data(state=self._state, data=tag) for tag in data.get('available_tags', [])] self.default_thread_slowmode_delay: int = data.get('default_thread_rate_limit_per_user', 0) + self.default_layout: ForumLayoutType = try_enum(ForumLayoutType, data.get('default_forum_layout', 0)) self._available_tags: Dict[int, ForumTag] = {tag.id: tag for tag in tags} self.default_reaction_emoji: Optional[PartialEmoji] = None @@ -2168,7 +2191,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): This does not always retrieve archived threads, as they are not retained in the internal cache. Use :func:`Guild.fetch_channel` instead. - .. versionadded:: 2.2 + .. versionadded:: 2.0 Parameters ----------- @@ -2259,6 +2282,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): available_tags: Sequence[ForumTag] = ..., default_thread_slowmode_delay: int = ..., default_reaction_emoji: Optional[EmojiInputType] = ..., + default_layout: ForumLayoutType = ..., require_tag: bool = ..., ) -> ForumChannel: ... @@ -2312,6 +2336,10 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): default_reaction_emoji: Optional[Union[:class:`Emoji`, :class:`PartialEmoji`, :class:`str`]] The new default reaction emoji for threads in this channel. + .. versionadded:: 2.0 + default_layout: :class:`ForumLayoutType` + The new default layout for posts in this forum. + .. versionadded:: 2.0 require_tag: :class:`bool` Whether to require a tag for threads in this channel or not. @@ -2323,7 +2351,8 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): ValueError The new ``position`` is less than 0 or greater than the number of channels. TypeError - The permission overwrite information is not in proper form. + The permission overwrite information is not in proper form or a type + is not the expected type. Forbidden You do not have permissions to edit the forum. HTTPException @@ -2364,6 +2393,16 @@ class ForumChannel(discord.abc.GuildChannel, Hashable): flags.require_tag = require_tag options['flags'] = flags.value + try: + layout = options.pop('default_layout') + except KeyError: + pass + else: + if not isinstance(layout, ForumLayoutType): + raise TypeError(f'default_layout parameter must be a ForumLayoutType not {layout.__class__.__name__}') + + options['default_forum_layout'] = layout.value + payload = await self._edit(options, reason=reason) if payload is not None: # the payload will always be the proper channel payload diff --git a/discord/enums.py b/discord/enums.py index 398941431..49d82c7cd 100644 --- a/discord/enums.py +++ b/discord/enums.py @@ -111,6 +111,7 @@ __all__ = ( 'AutoModRuleTriggerType', 'AutoModRuleEventType', 'AutoModRuleActionType', + 'ForumLayoutType', ) if TYPE_CHECKING: @@ -1474,6 +1475,12 @@ class AutoModRuleActionType(Enum): timeout = 3 +class ForumLayoutType(Enum): + not_set = 0 + list_view = 1 + gallery_view = 2 + + 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 3410e0178..13066d111 100644 --- a/discord/http.py +++ b/discord/http.py @@ -1378,6 +1378,7 @@ class HTTPClient: 'default_reaction_emoji', 'available_tags', 'applied_tags', + 'default_forum_layout', ) payload = {k: v for k, v in options.items() if k in valid_keys} diff --git a/discord/types/channel.py b/discord/types/channel.py index 448ab8e71..b385aab72 100644 --- a/discord/types/channel.py +++ b/discord/types/channel.py @@ -140,10 +140,14 @@ class ForumTag(TypedDict): emoji_name: Optional[str] +ForumLayoutType = Literal[0, 1, 2] + + class ForumChannel(_BaseTextChannel): type: Literal[15] available_tags: List[ForumTag] default_reaction_emoji: Optional[DefaultReaction] + default_forum_layout: NotRequired[ForumLayoutType] flags: NotRequired[int] diff --git a/docs/api.rst b/docs/api.rst index bb605e8a7..03c14a51a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -5369,6 +5369,26 @@ of :class:`enum.Enum`. The rule will timeout a user. + +.. class:: ForumLayoutType + + Represents how a forum's posts are layed out in the client. + + .. versionadded:: 2.2 + + .. attribute:: not_set + + No default has been set, so it is up to the client to know how to lay it out. + + .. attribute:: list_view + + Displays posts as a list. + + .. attribute:: gallery_view + + Displays posts as a collection of tiles. + + .. _discord-api-audit-logs: Audit Log Data