Skip to content
This repository was archived by the owner on Dec 26, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e631007
:bulb: Remove misleading comments
beastmatser Jan 10, 2022
a78c570
:sparkles: Add Permissions object
beastmatser Jan 10, 2022
707ef31
:sparkles: Add permisson property on Overwrite
beastmatser Jan 10, 2022
93a97bf
:recycle: Update init's
beastmatser Jan 10, 2022
97cb5b6
:art: Codacity fixes
beastmatser Jan 10, 2022
eeae339
:rewind: Undo removal
beastmatser Jan 10, 2022
b3b0064
:pencil2: Fix typo
beastmatser Jan 10, 2022
d58c694
:page_facing_up: Add compressed license
beastmatser Jan 10, 2022
4633104
:sparkles: Add equality datamodel
beastmatser Jan 10, 2022
282a0dd
Merge branch 'add-permission-handler' of https://github.com/beastmats…
beastmatser Jan 10, 2022
b47c2c0
:test_tube: Add tests for permissions
beastmatser Jan 10, 2022
d42f827
:recycle: Alphabetize dunder all
beastmatser Jan 11, 2022
5f67b5f
:bug: Fix Dunder eq
beastmatser Jan 11, 2022
0a0d2f2
:white_check_mark: Fix tests
beastmatser Jan 11, 2022
80cd31b
:sparkles: Add properties allow and deny
beastmatser Jan 11, 2022
7c3fe1e
:art: Codacity changes
beastmatser Jan 11, 2022
cec9822
:art: Codacity changes
beastmatser Jan 11, 2022
1a343f1
:recycle: Change bool checking
beastmatser Jan 11, 2022
cbd4c96
:rewind: Undo commit
beastmatser Jan 11, 2022
250fdda
:recycle: Refactor
beastmatser Jan 11, 2022
4e19416
:art: Automatic sorting
Jan 11, 2022
ddd5286
:recycle: Refactor
beastmatser Jan 11, 2022
441a117
:recycle: Code refactor
beastmatser Jan 11, 2022
3d3606e
:recycle: Use normal dataclass
beastmatser Jan 11, 2022
4d7d0b4
:memo: Document permissions
beastmatser Jan 11, 2022
629a185
:art: Codacity changes
beastmatser Jan 11, 2022
2dd75d9
:art: Codacity changes
beastmatser Jan 11, 2022
dd2a853
📝 Update documentation
Sigmanificient Jan 11, 2022
30e7887
Update pincer/objects/guild/permissions.py
Sigmanificient Jan 12, 2022
9a73186
Update pincer/objects/guild/permissions.py
Sigmanificient Jan 12, 2022
fba1cde
:memo: Fix docs
beastmatser Jan 12, 2022
7bffe0c
:coffin: Remove unused imports
beastmatser Jan 12, 2022
88beab7
:truck: Rename permission classes
beastmatser Jan 12, 2022
2ed13e9
:fire: Remove unneeded eq
beastmatser Jan 12, 2022
5e79113
Merge branch 'add-permission-handler' of https://github.com/beastmats…
beastmatser Jan 12, 2022
57734d7
:recycle: :memo: Small refactor and doc changes
beastmatser Jan 12, 2022
ef49bfa
:bug: Fix settings wrong attr
beastmatser Jan 12, 2022
1171921
:recycle: Small code refactors
beastmatser Jan 13, 2022
eb974ec
:truck: Rename from_int -> from_ints
beastmatser Jan 13, 2022
b9688c6
:truck: Rename to_tuple -> to_ints
beastmatser Jan 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions pincer/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
)
from .guild.member import GuildMember, PartialGuildMember, BaseMember
from .guild.overwrite import Overwrite
from .guild.permissions import Permission
from .guild.role import RoleTags, Role
from .guild.stage import PrivacyLevel, StageInstance
from .guild.template import GuildTemplate
Expand Down Expand Up @@ -134,12 +135,12 @@
"MessageReactionAddEvent", "MessageReactionRemoveAllEvent",
"MessageReactionRemoveEmojiEvent", "MessageReactionRemoveEvent",
"MessageReference", "MessageType", "NewsChannel", "Overwrite",
"PartialGuildMember", "PremiumTier", "PremiumTypes", "PresenceUpdateEvent",
"PrivacyLevel", "Reaction", "ReadyEvent", "RequestGuildMembers",
"ResolvedData", "Resume", "Role", "RoleTags", "SessionStartLimit",
"StageInstance", "StatusType", "Sticker", "StickerFormatType",
"StickerItem", "StickerPack", "StickerType", "SystemChannelFlags",
"TextChannel", "ThreadListSyncEvent", "ThreadMember",
"PartialGuildMember", "Permission", "PremiumTier", "PremiumTypes",
"PresenceUpdateEvent", "PrivacyLevel", "Reaction", "ReadyEvent",
"RequestGuildMembers", "ResolvedData", "Resume", "Role", "RoleTags",
"SessionStartLimit", "StageInstance", "StatusType", "Sticker",
"StickerFormatType", "StickerItem", "StickerPack", "StickerType",
"SystemChannelFlags", "TextChannel", "ThreadListSyncEvent", "ThreadMember",
"ThreadMembersUpdateEvent", "ThreadMetadata", "ThrottleInterface",
"ThrottleScope", "TypingStartEvent", "UpdatePresence", "UpdateVoiceState",
"User", "UserMessage", "VerificationLevel", "VisibilityType",
Expand Down
5 changes: 3 additions & 2 deletions pincer/objects/guild/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
)
from .member import GuildMember, PartialGuildMember, BaseMember
from .overwrite import Overwrite
from .permissions import Permission
from .role import RoleTags, Role
from .scheduled_events import GuildScheduledEventEntityType, EventStatus, ScheduledEvent
from .stage import PrivacyLevel, StageInstance
Expand All @@ -39,8 +40,8 @@
"GuildFeature", "GuildMember", "GuildNSFWLevel",
"GuildScheduledEventEntityType", "GuildTemplate", "GuildWidget", "Invite",
"InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel",
"Overwrite", "PartialGuildMember", "PremiumTier", "PrivacyLevel", "Role",
"RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags",
"Overwrite", "PartialGuildMember", "Permission", "PremiumTier", "PrivacyLevel",
"Role", "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags",
"TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild",
"VerificationLevel", "VoiceChannel", "Webhook", "WebhookType",
"WelcomeScreen", "WelcomeScreenChannel"
Expand Down
6 changes: 6 additions & 0 deletions pincer/objects/guild/overwrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

from .permissions import Permission
from ...utils import APIObject

if TYPE_CHECKING:
Expand All @@ -31,3 +32,8 @@ class Overwrite(APIObject):
type: int
allow: str
deny: str

@property
def permissions(self) -> Permission:
"""Returns the permissions for this overwrite"""
return Permission.from_int(int(self.allow), int(self.deny))
121 changes: 121 additions & 0 deletions pincer/objects/guild/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Copyright Pincer 2021-Present
# Full MIT License can be found in `LICENSE` at the project root.

from __future__ import annotations

from enum import Enum
from typing import Tuple, Optional


class PermissionEnums(Enum):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class PermissionEnums(Enum):
class Permissions(Enum):

CREATE_INSTANT_INVITE = 1 << 0
KICK_MEMBERS = 1 << 1
BAN_MEMBERS = 1 << 2
ADMINISTRATOR = 1 << 3
MANAGE_CHANNELS = 1 << 4
MANAGE_GUIlD = 1 << 5
ADD_REACTIONS = 1 << 6
VIEW_AUDIT_LOG = 1 << 7
PRIORITY_SPEAKER = 1 << 8
STREAM = 1 << 9
VIEW_CHANNEL = 1 << 10
SEND_MESSAGES = 1 << 11
SEND_TTS_MESSAGES = 1 << 12
MANAGE_MESSAGES = 1 << 13
EMBED_LINKS = 1 << 14
ATTACH_FILES = 1 << 15
READ_MESSAGE_HISTORY = 1 << 16
MENTION_EVERYONE = 1 << 17
USE_EXTERNAL_EMOJIS = 1 << 18
VIEW_GUILD_INSIGHTS = 1 << 19
CONNECT = 1 << 20
SPEAK = 1 << 21
MUTE_MEMBERS = 1 << 22
DEAFEN_MEMBERS = 1 << 23
MOVE_MEMBERS = 1 << 24
USE_VAD = 1 << 25
CHANGE_NICKNAME = 1 << 26
MANAGE_NICKNAMES = 1 << 27
MANAGE_ROLES = 1 << 28
MANAGE_WEBHOOKS = 1 << 29
MANAGE_EMOJIS_AND_STICKERS = 1 << 30
USE_APPLICATION_COMMANDS = 1 << 31
REQUEST_TO_SPEAK = 1 << 32
MANAGE_EVENTS = 1 << 33
MANAGE_THREADS = 1 << 34
CREATE_PUBLIC_THREADS = 1 << 35
CREATE_PRIVATE_THREADS = 1 << 36
USE_EXTERNAL_STICKERS = 1 << 37
SEND_MESSAGES_IN_THREADS = 1 << 38
START_EMBEDDED_ACTIVITIES = 1 << 39
MODERATE_MEMBERS = 1 << 40


class Permission:
def __init__(self, **kwargs: Optional[bool]) -> None:
valid_perms = (enum.name.lower() for enum in PermissionEnums)
for perm in valid_perms:
setattr(self, perm, kwargs.pop(perm, None))

if kwargs:
invalid_perms = ', '.join(kwargs.keys())
raise ValueError(f"Invalid permissions were passed in: {invalid_perms}")

def __setattr__(self, name: str, value: Optional[bool]) -> None:
if not (value is None or isinstance(value, bool)):
raise ValueError(f"Permission {name!r} must be a boolean or None")
return super().__setattr__(name, value)

def __eq__(self, object) -> bool:
"""
Permission equality is determined by comparing the integer values of the permissions
"""
if isinstance(object, Permission):
return self.to_int() == object.to_int()
elif isinstance(object, tuple):
return self.to_int() == object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I not sure there is any scenario where int can be equal to tuple.

Suggested change
elif isinstance(object, tuple):
return self.to_int() == object

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns a tuple of ints. Maybe the function name should be changed because I was confused by this too.

Copy link
Contributor Author

@beastmatser beastmatser Jan 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few ideas:

  • to_ints
  • to_tuple
  • convert

I changed it to_tuple for now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should do to_ints since it matches with from_ints

My other idea is to_permission_tuple but thats kinda long.


return False

@classmethod
def from_int(cls, allow: int, deny: int) -> Permission:
clsobj = cls()

for enum in PermissionEnums:
if bool(enum.value & allow):
setattr(clsobj, enum.name.lower(), True)
elif bool(enum.value & deny):
setattr(clsobj, enum.name.lower(), False)
else:
setattr(clsobj, enum.name.lower(), None)

return clsobj

def to_int(self) -> Tuple[int]:
allow = 0
deny = 0
for enum in PermissionEnums:
if getattr(self, enum.name.lower()):
allow |= enum.value
elif getattr(self, enum.name.lower()) is False:
deny |= enum.value

return allow, deny

@property
def allow(self) -> int:
allow = 0
for enum in PermissionEnums:
if getattr(self, enum.name.lower()):
allow |= enum.value

return allow

@property
def deny(self) -> int:
deny = 0
for enum in PermissionEnums:
if getattr(self, enum.name.lower()) is False:
deny |= enum.value

return deny
103 changes: 103 additions & 0 deletions tests/objects/guild/test_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Copyright Pincer 2021-Present
# Full MIT License can be found in `LICENSE` at the project root.
import pytest
from pincer.objects.guild.permissions import Permission, PermissionEnums


class TestPermission:
@staticmethod
def test_invalid_permissions():
with pytest.raises(ValueError):
Permission(this_permisison_does_not_exist=True)

with pytest.raises(ValueError):
Permission(
manage_channels="True",
)

@staticmethod
def test_valid_permissions():
valid_perms = (
"create_instant_invite",
"kick_members",
"ban_members",
"administrator",
"manage_channels",
"manage_guild",
"add_reactions",
"view_audit_log",
"priority_speaker",
"stream",
"view_channel",
"send_messages",
"send_tts_messages",
"manage_messages",
"embed_links",
"attach_files",
"read_message_history",
"mention_everyone",
"use_external_emojis",
"view_guild_insights",
"connect",
"speak",
"mute_members",
"deafen_members",
"move_members",
"use_vad",
"change_nickname",
"manage_nicknames",
"manage_roles",
"manage_webhooks",
"manage_emojis_and_stickers",
"use_application_commands",
"request_to_speak",
"manage_events",
"manage_threads",
"create_public_threads",
"create_private_threads",
"use_external_stickers",
"send_messages_in_threads",
"start_embedded_activities",
"moderate_members",
)

for perm in valid_perms:
assert hasattr(Permission(), perm)

@staticmethod
def test_from_int():
assert Permission.from_int(1025, 268435472) == Permission(
view_channel=True,
manage_channels=False,
create_instant_invite=True,
manage_roles=False,
)

assert Permission.from_int(0, 0) == Permission()

@staticmethod
def test_to_int():
allow, deny = Permission.to_int(Permission())
assert allow == 0
assert deny == 0

permission = Permission()
for enum in PermissionEnums:
if getattr(permission, enum.name.lower()):
allow |= enum.value
elif getattr(permission, enum.name.lower()) is False:
deny |= enum.value

assert Permission.to_int(Permission()) == (0, 0)

@staticmethod
def test_allow():
permission = Permission(
view_channel=True,
manage_channels=False,
create_instant_invite=True,
manage_roles=False,
)

assert permission.allow == 1025
assert permission.deny == 268435472