Skip to content

Commit

Permalink
Add guildmember permission calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
4Kaylum committed Apr 24, 2024
1 parent be8fca7 commit 8085ac8
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 5 deletions.
32 changes: 32 additions & 0 deletions novus/models/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,38 @@ def _add_channel(self, channel: Channel) -> None:
def _remove_channel(self, id: int | str) -> None:
self._channels.pop(try_snowflake(id), None)

def permissions_for(self, user: GuildMember) -> Permissions:
"""
Get the permissions for a given user in this channel.
.. note::
Permissions are only properly calculated when the guild and its
roles are cached (ie when the bot is connected to the gateway).
Parameters
----------
user : novus.GuildMember
The user whose permissions you want to get.
Returns
-------
novus.Permissions
The calculated permissions for that user in this channel.
"""

all = Permissions.all().value
permissions: int = user.permissions.value
for overwrite in self.overwrites or []:
if overwrite.type == PermissionOverwriteType.ROLE:
if overwrite.id in user.role_ids or overwrite.id == self.guild_id:
permissions |= overwrite.allow.value
permissions &= (all ^ overwrite.deny.value)
elif overwrite.type == PermissionOverwriteType.MEMBER:
if overwrite.id == user.id:
permissions |= overwrite.allow.value
permissions &= (all ^ overwrite.deny.value)
return Permissions(permissions)

# API methods

Expand Down
59 changes: 55 additions & 4 deletions novus/models/guild_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class GuildMember(Hashable, Messageable):
'deaf',
'mute',
'pending',
'permissions',
'_permissions', # calculated
'timeout_until',
'guild',
'_cs_guild_avatar',
Expand Down Expand Up @@ -195,7 +195,6 @@ class GuildMember(Hashable, Messageable):
deaf: bool
mute: bool
pending: bool
permissions: Permissions
timeout_until: DiscordDatetime | None
guild: BaseGuild

Expand Down Expand Up @@ -249,9 +248,9 @@ def __init__(
self.deaf = data.get('deaf', False)
self.mute = data.get('mute', False)
self.pending = data.get('pending', False)
self.permissions = Permissions.none()
self._permissions = None
if "permissions" in data:
self.permissions = Permissions(int(data["permissions"]))
self._permissions = Permissions(int(data["permissions"]))
self.timeout_until = None
if "communication_disabled_until" in data:
self.timeout_until = parse_timestamp(data["communication_disabled_until"])
Expand Down Expand Up @@ -318,6 +317,58 @@ def _update(self, data: payloads.GuildMember) -> Self:
self.timeout_until = parse_timestamp(data.get("communication_disabled_until"))
return self

@property
def permissions(self) -> Permissions:
"""
The calculated permissions for the user based on their roles and the
cached guild.
If permissions were provided (ie this member was created as part of an
interaction payload) then they will not be re-calculated.
.. note::
Permissions are only properly calculated when the guild and its
roles are cached (ie when the bot is connected to the gateway).
"""

if self._permissions is not None:
return self._permissions

permissions = Permissions()

from .guild import Guild
if not isinstance(self.guild, Guild):
return permissions

for role_id in [self.guild.id] + self.role_ids:
role = self.guild.get_role(role_id)
if role is None:
continue
permissions = Permissions(permissions.value | role.permissions.value)
return permissions

def permissions_in(self, channel: Channel) -> Permissions:
"""
Get the permissions for this guild member inside of a channel.
.. note::
Permissions are only properly calculated when the guild and its
roles are cached (ie when the bot is connected to the gateway).
Parameters
----------
channel : novus.Channel
The channel that you want to get the user's permissions for.
Returns
-------
novus.Permissions
The calculated permissions for this user in that channel.
"""

return channel.permissions_for(self)

# API methods

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion novus/payloads/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

class ChannelOverwrite(TypedDict):
id: Snowflake
type: Literal[0, 1, "role", "channel"]
type: int
allow: str
deny: str

Expand Down

0 comments on commit 8085ac8

Please sign in to comment.