From 28346402d16d440be318e53e686efecf8f0175a7 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Mon, 12 Jun 2023 02:52:03 -0400 Subject: [PATCH 1/9] fix: show the proper permissions in threads --- disnake/abc.py | 31 ++++++++------- disnake/channel.py | 95 +++++++++++++++++++++------------------------- disnake/threads.py | 20 +++++++++- 3 files changed, 79 insertions(+), 67 deletions(-) diff --git a/disnake/abc.py b/disnake/abc.py index d7a2991297..02daae9d29 100644 --- a/disnake/abc.py +++ b/disnake/abc.py @@ -630,6 +630,23 @@ def jump_url(self) -> str: """ return f"https://discord.com/channels/{self.guild.id}/{self.id}" + def _apply_implict_permissions(self, base: Permissions) -> Permissions: + # if you can't send a message in a channel then you can't have certain + # permissions as well + if not base.send_messages: + base.send_tts_messages = False + base.send_voice_messages = False + base.mention_everyone = False + base.embed_links = False + base.attach_files = False + + # if you can't view a channel then you have no permissions there + if not base.view_channel: + denied = Permissions.all_channel() + base.value &= ~denied.value + + return base + def permissions_for( self, obj: Union[Member, Role], @@ -781,20 +798,6 @@ def permissions_for( base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny) break - # if you can't send a message in a channel then you can't have certain - # permissions as well - if not base.send_messages: - base.send_tts_messages = False - base.send_voice_messages = False - base.mention_everyone = False - base.embed_links = False - base.attach_files = False - - # if you can't view a channel then you have no permissions there - if not base.view_channel: - denied = Permissions.all_channel() - base.value &= ~denied.value - # if you have a timeout then you can't have any permissions # except read messages and read message history if not ignore_timeout and obj.current_timeout: diff --git a/disnake/channel.py b/disnake/channel.py index ea738f235c..9686e6cd71 100644 --- a/disnake/channel.py +++ b/disnake/channel.py @@ -263,6 +263,7 @@ def permissions_for( ignore_timeout: bool = MISSING, ) -> Permissions: base = super().permissions_for(obj, ignore_timeout=ignore_timeout) + self._apply_implict_permissions(base) # text channels do not have voice related permissions denied = Permissions.voice() @@ -1183,6 +1184,35 @@ def voice_states(self) -> Dict[int, VoiceState]: if value.channel and value.channel.id == self.id } + @utils.copy_doc(disnake.abc.GuildChannel.permissions_for) + def permissions_for( + self, + obj: Union[Member, Role], + /, + *, + ignore_timeout: bool = MISSING, + ) -> Permissions: + base = super().permissions_for(obj, ignore_timeout=ignore_timeout) + self._apply_implict_permissions(base) + + # voice channels cannot be edited by people who can't connect to them + # It also implicitly denies all other voice perms + if not base.connect: + denied = Permissions.voice() + # voice channels also deny all text related permissions + denied.value |= Permissions.text().value + # stage channels remove the stage permissions + denied.value |= Permissions.stage().value + + denied.update( + manage_channels=True, + manage_roles=True, + manage_events=True, + manage_webhooks=True, + ) + base.value &= ~denied.value + return base + class VoiceChannel(disnake.abc.Messageable, VocalGuildChannel): """Represents a Discord guild voice channel. @@ -1442,32 +1472,6 @@ def get_partial_message(self, message_id: int, /) -> PartialMessage: return PartialMessage(channel=self, id=message_id) - @utils.copy_doc(disnake.abc.GuildChannel.permissions_for) - def permissions_for( - self, - obj: Union[Member, Role], - /, - *, - ignore_timeout: bool = MISSING, - ) -> Permissions: - base = super().permissions_for(obj, ignore_timeout=ignore_timeout) - - # voice channels cannot be edited by people who can't connect to them - # It also implicitly denies all other voice perms - if not base.connect: - denied = Permissions.voice() - # voice channels also deny all text related permissions - denied.value |= Permissions.text().value - - denied.update( - manage_channels=True, - manage_roles=True, - manage_events=True, - manage_webhooks=True, - ) - base.value &= ~denied.value - return base - # if only these parameters are passed, `_move` is called and no channel will be returned @overload async def edit( @@ -2183,31 +2187,6 @@ def instance(self) -> Optional[StageInstance]: """ return utils.get(self.guild.stage_instances, channel_id=self.id) - @utils.copy_doc(disnake.abc.GuildChannel.permissions_for) - def permissions_for( - self, - obj: Union[Member, Role], - /, - *, - ignore_timeout: bool = MISSING, - ) -> Permissions: - base = super().permissions_for(obj, ignore_timeout=ignore_timeout) - - # voice channels cannot be edited by people who can't connect to them - # It also implicitly denies all other channel permissions. - if not base.connect: - denied = Permissions.voice() - denied.value |= Permissions.text().value - denied.value |= Permissions.stage().value - denied.update( - manage_channels=True, - manage_roles=True, - manage_events=True, - manage_webhooks=True, - ) - base.value &= ~denied.value - return base - async def create_instance( self, *, @@ -2787,6 +2766,19 @@ def type(self) -> Literal[ChannelType.category]: """ return ChannelType.category + @utils.copy_doc(disnake.abc.GuildChannel.permissions_for) + def permissions_for( + self, + obj: Union[Member, Role], + /, + *, + ignore_timeout: bool = MISSING, + ) -> Permissions: + base = super().permissions_for(obj, ignore_timeout=ignore_timeout) + self._apply_implict_permissions(base) + + return base + def is_nsfw(self) -> bool: """Whether the category is marked as NSFW. @@ -3329,6 +3321,7 @@ def permissions_for( ignore_timeout: bool = MISSING, ) -> Permissions: base = super().permissions_for(obj, ignore_timeout=ignore_timeout) + self._apply_implict_permissions(base) # forum channels do not have voice related permissions denied = Permissions.voice() diff --git a/disnake/threads.py b/disnake/threads.py index 56822dbdfb..ad43397b49 100644 --- a/disnake/threads.py +++ b/disnake/threads.py @@ -6,7 +6,7 @@ import time from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Literal, Optional, Sequence, Union -from .abc import Messageable +from .abc import GuildChannel, Messageable from .enums import ChannelType, ThreadArchiveDuration, try_enum, try_enum_to_int from .errors import ClientException from .flags import ChannelFlags @@ -460,7 +460,23 @@ def permissions_for( parent = self.parent if parent is None: raise ClientException("Parent channel not found") - return parent.permissions_for(obj, ignore_timeout=ignore_timeout) + base = GuildChannel.permissions_for(parent, obj, ignore_timeout=ignore_timeout) + + # if you can't send a message in a channel then you can't have certain + # permissions as well + if not base.send_messages_in_threads: + base.send_tts_messages = False + base.send_voice_messages = False + base.mention_everyone = False + base.embed_links = False + base.attach_files = False + + # if you can't view a channel then you have no permissions there + if not base.view_channel: + denied = Permissions.all_channel() + base.value &= ~denied.value + + return base async def delete_messages(self, messages: Iterable[Snowflake]) -> None: """|coro| From 36f2872935403930678ad8732877ed104dfe460c Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Mon, 12 Jun 2023 02:58:27 -0400 Subject: [PATCH 2/9] add changelog entry --- changelog/1047.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/1047.bugfix.rst diff --git a/changelog/1047.bugfix.rst b/changelog/1047.bugfix.rst new file mode 100644 index 0000000000..8e650f0bf5 --- /dev/null +++ b/changelog/1047.bugfix.rst @@ -0,0 +1 @@ +Fix permission resolution for :meth:`.Thread.permissions_for` when :attr:`Permissions.send_messages` is ``False``, but :attr:`Permissions.send_messages_in_threads` is ``True``. From 31a068389e1c461347476eeb1b855fbed4aa2a56 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Wed, 14 Jun 2023 22:50:34 -0400 Subject: [PATCH 3/9] add nb note --- disnake/threads.py | 1 + 1 file changed, 1 insertion(+) diff --git a/disnake/threads.py b/disnake/threads.py index ad43397b49..3e88ccb51b 100644 --- a/disnake/threads.py +++ b/disnake/threads.py @@ -460,6 +460,7 @@ def permissions_for( parent = self.parent if parent is None: raise ClientException("Parent channel not found") + # n.b. GuildChannel is used here so implicit overrides are not applied based on send_messages base = GuildChannel.permissions_for(parent, obj, ignore_timeout=ignore_timeout) # if you can't send a message in a channel then you can't have certain From 136f4b16247e91a59ebbcd7e4696e9546345083b Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sun, 18 Jun 2023 16:39:45 -0400 Subject: [PATCH 4/9] fix: don't return and mutate --- disnake/abc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/disnake/abc.py b/disnake/abc.py index 02daae9d29..74d51ebf67 100644 --- a/disnake/abc.py +++ b/disnake/abc.py @@ -630,7 +630,7 @@ def jump_url(self) -> str: """ return f"https://discord.com/channels/{self.guild.id}/{self.id}" - def _apply_implict_permissions(self, base: Permissions) -> Permissions: + def _apply_implict_permissions(self, base: Permissions) -> None: # if you can't send a message in a channel then you can't have certain # permissions as well if not base.send_messages: @@ -645,8 +645,6 @@ def _apply_implict_permissions(self, base: Permissions) -> Permissions: denied = Permissions.all_channel() base.value &= ~denied.value - return base - def permissions_for( self, obj: Union[Member, Role], From b87c8542e3a22cbdf7880873f524df39d9ef1858 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sun, 18 Jun 2023 19:53:41 -0400 Subject: [PATCH 5/9] chore(docs): update description for accuracy --- disnake/threads.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/disnake/threads.py b/disnake/threads.py index 3e88ccb51b..91a8ed53c3 100644 --- a/disnake/threads.py +++ b/disnake/threads.py @@ -422,10 +422,14 @@ def permissions_for( """Handles permission resolution for the :class:`~disnake.Member` or :class:`~disnake.Role`. - Since threads do not have their own permissions, they inherit them - from the parent channel. This is a convenience method for - calling :meth:`~disnake.TextChannel.permissions_for` on the - parent channel. + While threads cannot have permissions set on them directly, + the permission context is different than an full fledged channel, + and so this method has different behavior than calling + the parent's :attr:`GuildChannel.permissions_for <.abc.GuildChannel.permissions_for>` method directly. + + .. versionchanged:: 2.9 + Properly takes :attr:`Permissions.send_messages_in_threads` + into consideration. Parameters ---------- From 682226105a5b432a5a8096b8eeb2a9f274ee00e1 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sun, 18 Jun 2023 19:55:24 -0400 Subject: [PATCH 6/9] reword changelog --- changelog/1047.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/1047.bugfix.rst b/changelog/1047.bugfix.rst index 8e650f0bf5..d0357f64e8 100644 --- a/changelog/1047.bugfix.rst +++ b/changelog/1047.bugfix.rst @@ -1 +1 @@ -Fix permission resolution for :meth:`.Thread.permissions_for` when :attr:`Permissions.send_messages` is ``False``, but :attr:`Permissions.send_messages_in_threads` is ``True``. +Fix permission resolution for :meth:`.Thread.permissions_for` to use :attr:`Permissions.send_messages_in_threads` instead of :attr:`Permissions.send_messages` for calculating implicit permissions. From b97c59e3dff325c2b2ecb4942f8acc2474a1ff62 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sun, 18 Jun 2023 20:01:45 -0400 Subject: [PATCH 7/9] readd line for threads having their own permissions --- disnake/threads.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/disnake/threads.py b/disnake/threads.py index 91a8ed53c3..2947df104f 100644 --- a/disnake/threads.py +++ b/disnake/threads.py @@ -422,10 +422,12 @@ def permissions_for( """Handles permission resolution for the :class:`~disnake.Member` or :class:`~disnake.Role`. - While threads cannot have permissions set on them directly, - the permission context is different than an full fledged channel, - and so this method has different behavior than calling - the parent's :attr:`GuildChannel.permissions_for <.abc.GuildChannel.permissions_for>` method directly. + Since threads do not have their own permissions, they inherit them + from the parent channel. + However, the permission context is different than an full fledged channel, + and so this method has different behavior than calling the parent's + :attr:`GuildChannel.permissions_for <.abc.GuildChannel.permissions_for>` + method directly. .. versionchanged:: 2.9 Properly takes :attr:`Permissions.send_messages_in_threads` From 582955cdabae128581b84848212a93ed64ccd1b9 Mon Sep 17 00:00:00 2001 From: arl Date: Mon, 19 Jun 2023 16:39:54 -0400 Subject: [PATCH 8/9] Update disnake/threads.py Co-authored-by: shiftinv <8530778+shiftinv@users.noreply.github.com> Signed-off-by: arl --- disnake/threads.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disnake/threads.py b/disnake/threads.py index 2947df104f..2126e85605 100644 --- a/disnake/threads.py +++ b/disnake/threads.py @@ -424,8 +424,8 @@ def permissions_for( Since threads do not have their own permissions, they inherit them from the parent channel. - However, the permission context is different than an full fledged channel, - and so this method has different behavior than calling the parent's + However, the permission context is different compared to a normal channel, + so this method has different behavior than calling the parent's :attr:`GuildChannel.permissions_for <.abc.GuildChannel.permissions_for>` method directly. From bc10cd9915ffa38eb1e1cd4de9356eb9cfbff5a0 Mon Sep 17 00:00:00 2001 From: arl Date: Mon, 19 Jun 2023 18:39:13 -0400 Subject: [PATCH 9/9] Update changelog/1047.bugfix.rst Co-authored-by: shiftinv <8530778+shiftinv@users.noreply.github.com> Signed-off-by: arl --- changelog/1047.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/1047.bugfix.rst b/changelog/1047.bugfix.rst index d0357f64e8..e8a25b5829 100644 --- a/changelog/1047.bugfix.rst +++ b/changelog/1047.bugfix.rst @@ -1 +1 @@ -Fix permission resolution for :meth:`.Thread.permissions_for` to use :attr:`Permissions.send_messages_in_threads` instead of :attr:`Permissions.send_messages` for calculating implicit permissions. +Fix permission resolution for :class:`Thread`\s to use :attr:`Permissions.send_messages_in_threads` instead of :attr:`Permissions.send_messages` for calculating implicit permissions.