Browse Source

Fix implicit permission resolution for Thread

Fix #9153
pull/9165/head
Rapptz 2 years ago
parent
commit
887ddbb4b6
  1. 28
      discord/abc.py
  2. 3
      discord/channel.py
  3. 29
      discord/threads.py

28
discord/abc.py

@ -639,6 +639,20 @@ class GuildChannel:
category = self.guild.get_channel(self.category_id) category = self.guild.get_channel(self.category_id)
return bool(category and category.overwrites == self.overwrites) return bool(category and category.overwrites == self.overwrites)
def _apply_implicit_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:
base.send_tts_messages = False
base.mention_everyone = False
base.embed_links = False
base.attach_files = False
# if you can't read a channel then you have no permissions there
if not base.read_messages:
denied = Permissions.all_channel()
base.value &= ~denied.value
def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: def permissions_for(self, obj: Union[Member, Role], /) -> Permissions:
"""Handles permission resolution for the :class:`~discord.Member` """Handles permission resolution for the :class:`~discord.Member`
or :class:`~discord.Role`. or :class:`~discord.Role`.
@ -649,6 +663,7 @@ class GuildChannel:
- Guild roles - Guild roles
- Channel overrides - Channel overrides
- Member overrides - Member overrides
- Implicit permissions
- Member timeout - Member timeout
If a :class:`~discord.Role` is passed, then it checks the permissions If a :class:`~discord.Role` is passed, then it checks the permissions
@ -764,19 +779,6 @@ class GuildChannel:
base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny) base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny)
break 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.mention_everyone = False
base.embed_links = False
base.attach_files = False
# if you can't read a channel then you have no permissions there
if not base.read_messages:
denied = Permissions.all_channel()
base.value &= ~denied.value
if obj.is_timed_out(): if obj.is_timed_out():
# Timeout leads to every permission except VIEW_CHANNEL and READ_MESSAGE_HISTORY # Timeout leads to every permission except VIEW_CHANNEL and READ_MESSAGE_HISTORY
# being explicitly denied # being explicitly denied

3
discord/channel.py

@ -231,6 +231,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
@utils.copy_doc(discord.abc.GuildChannel.permissions_for) @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: def permissions_for(self, obj: Union[Member, Role], /) -> Permissions:
base = super().permissions_for(obj) base = super().permissions_for(obj)
self._apply_implicit_permissions(base)
# text channels do not have voice related permissions # text channels do not have voice related permissions
denied = Permissions.voice() denied = Permissions.voice()
@ -975,6 +976,7 @@ class VocalGuildChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hasha
@utils.copy_doc(discord.abc.GuildChannel.permissions_for) @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: def permissions_for(self, obj: Union[Member, Role], /) -> Permissions:
base = super().permissions_for(obj) base = super().permissions_for(obj)
self._apply_implicit_permissions(base)
# voice channels cannot be edited by people who can't connect to them # voice channels cannot be edited by people who can't connect to them
# It also implicitly denies all other voice perms # It also implicitly denies all other voice perms
@ -2219,6 +2221,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable):
@utils.copy_doc(discord.abc.GuildChannel.permissions_for) @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: def permissions_for(self, obj: Union[Member, Role], /) -> Permissions:
base = super().permissions_for(obj) base = super().permissions_for(obj)
self._apply_implicit_permissions(base)
# text channels do not have voice related permissions # text channels do not have voice related permissions
denied = Permissions.voice() denied = Permissions.voice()

29
discord/threads.py

@ -29,10 +29,11 @@ from datetime import datetime
import array import array
from .mixins import Hashable from .mixins import Hashable
from .abc import Messageable, _purge_helper from .abc import Messageable, GuildChannel, _purge_helper
from .enums import ChannelType, try_enum from .enums import ChannelType, try_enum
from .errors import ClientException from .errors import ClientException
from .flags import ChannelFlags from .flags import ChannelFlags
from .permissions import Permissions
from .utils import MISSING, parse_time, _get_as_snowflake, _unique from .utils import MISSING, parse_time, _get_as_snowflake, _unique
__all__ = ( __all__ = (
@ -56,7 +57,6 @@ if TYPE_CHECKING:
from .message import Message, PartialMessage from .message import Message, PartialMessage
from .abc import Snowflake, SnowflakeTime from .abc import Snowflake, SnowflakeTime
from .role import Role from .role import Role
from .permissions import Permissions
from .state import ConnectionState from .state import ConnectionState
ThreadChannelType = Literal[ChannelType.news_thread, ChannelType.public_thread, ChannelType.private_thread] ThreadChannelType = Literal[ChannelType.news_thread, ChannelType.public_thread, ChannelType.private_thread]
@ -394,10 +394,9 @@ class Thread(Messageable, Hashable):
"""Handles permission resolution for the :class:`~discord.Member` """Handles permission resolution for the :class:`~discord.Member`
or :class:`~discord.Role`. or :class:`~discord.Role`.
Since threads do not have their own permissions, they inherit them Since threads do not have their own permissions, they mostly
from the parent channel. This is a convenience method for inherit them from the parent channel with some implicit
calling :meth:`~discord.TextChannel.permissions_for` on the permissions changed.
parent channel.
Parameters Parameters
---------- ----------
@ -420,7 +419,23 @@ class Thread(Messageable, Hashable):
parent = self.parent parent = self.parent
if parent is None: if parent is None:
raise ClientException('Parent channel not found') raise ClientException('Parent channel not found')
return parent.permissions_for(obj)
base = GuildChannel.permissions_for(parent, obj)
# 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.mention_everyone = False
base.embed_links = False
base.attach_files = False
# if you can't read a channel then you have no permissions there
if not base.read_messages:
denied = Permissions.all_channel()
base.value &= ~denied.value
return base
async def delete_messages(self, messages: Iterable[Snowflake], /, *, reason: Optional[str] = None) -> None: async def delete_messages(self, messages: Iterable[Snowflake], /, *, reason: Optional[str] = None) -> None:
"""|coro| """|coro|

Loading…
Cancel
Save