Skip to content

Commit

Permalink
feat: add TeamMember.role (#1094)
Browse files Browse the repository at this point in the history
  • Loading branch information
shiftinv authored Nov 17, 2023
1 parent 4bd0d25 commit cd48c92
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog/1094.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add inherited attributes to :class:`TeamMember`, and fix :attr:`TeamMember.avatar` documentation.
1 change: 1 addition & 0 deletions changelog/1094.feature.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :attr:`TeamMember.role`.
1 change: 1 addition & 0 deletions changelog/1094.feature.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Update :meth:`Bot.is_owner <ext.commands.Bot.is_owner>` to take team member roles into account.
10 changes: 10 additions & 0 deletions disnake/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"ActivityType",
"NotificationLevel",
"TeamMembershipState",
"TeamMemberRole",
"WebhookType",
"ExpireBehaviour",
"ExpireBehavior",
Expand Down Expand Up @@ -551,6 +552,15 @@ class TeamMembershipState(Enum):
accepted = 2


class TeamMemberRole(Enum):
admin = "admin"
developer = "developer"
read_only = "read_only"

def __str__(self) -> str:
return self.name


class WebhookType(Enum):
incoming = 1
channel_follower = 2
Expand Down
4 changes: 2 additions & 2 deletions disnake/ext/commands/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class Bot(BotBase, InteractionBotBase, disnake.Client):
owner_ids: Optional[Collection[:class:`int`]]
The IDs of the users that own the bot. This is similar to :attr:`owner_id`.
If this is not set and the application is team based, then it is
fetched automatically using :meth:`~.Bot.application_info`.
fetched automatically using :meth:`~.Bot.application_info` (taking team roles into account).
For performance reasons it is recommended to use a :class:`set`
for the collection. You cannot set both ``owner_id`` and ``owner_ids``.
Expand Down Expand Up @@ -403,7 +403,7 @@ class InteractionBot(InteractionBotBase, disnake.Client):
owner_ids: Optional[Collection[:class:`int`]]
The IDs of the users that own the bot. This is similar to :attr:`owner_id`.
If this is not set and the application is team based, then it is
fetched automatically using :meth:`~.Bot.application_info`.
fetched automatically using :meth:`~.Bot.application_info` (taking team roles into account).
For performance reasons it is recommended to use a :class:`set`
for the collection. You cannot set both ``owner_id`` and ``owner_ids``.
Expand Down
13 changes: 11 additions & 2 deletions disnake/ext/commands/common_bot_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@ async def _fill_owners(self) -> None:

app: disnake.AppInfo = await self.application_info() # type: ignore
if app.team:
self.owners = set(app.team.members)
self.owner_ids = {m.id for m in app.team.members}
self.owners = owners = {
member
for member in app.team.members
# these roles can access the bot token, consider them bot owners
if member.role in (disnake.TeamMemberRole.admin, disnake.TeamMemberRole.developer)
}
self.owner_ids = {m.id for m in owners}
else:
self.owner = app.owner
self.owner_id = app.owner.id
Expand Down Expand Up @@ -130,6 +135,10 @@ async def is_owner(self, user: Union[disnake.User, disnake.Member]) -> bool:
The function also checks if the application is team-owned if
:attr:`owner_ids` is not set.
.. versionchanged:: 2.10
Also takes team roles into account; only team members with the :attr:`~disnake.TeamMemberRole.admin`
or :attr:`~disnake.TeamMemberRole.developer` roles are considered bot owners.
Parameters
----------
user: :class:`.abc.User`
Expand Down
23 changes: 11 additions & 12 deletions disnake/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from . import utils
from .asset import Asset
from .enums import TeamMembershipState, try_enum
from .enums import TeamMemberRole, TeamMembershipState, try_enum
from .user import BaseUser

if TYPE_CHECKING:
Expand All @@ -21,7 +21,8 @@


class Team:
"""Represents an application team for a bot provided by Discord.
"""Represents an application team.
Teams are groups of users who share access to an application's configuration.
Attributes
----------
Expand All @@ -30,7 +31,7 @@ class Team:
name: :class:`str`
The team name.
owner_id: :class:`int`
The team's owner ID.
The team owner's ID.
members: List[:class:`TeamMember`]
A list of the members in the team.
Expand All @@ -44,7 +45,7 @@ def __init__(self, state: ConnectionState, data: TeamPayload) -> None:

self.id: int = int(data["id"])
self.name: str = data["name"]
self._icon: Optional[str] = data["icon"]
self._icon: Optional[str] = data.get("icon")
self.owner_id: Optional[int] = utils._get_as_snowflake(data, "owner_user_id")
self.members: List[TeamMember] = [
TeamMember(self, self._state, member) for member in data["members"]
Expand Down Expand Up @@ -113,29 +114,27 @@ class TeamMember(BaseUser):
See the `help article <https://dis.gd/app-usernames>`__ for details.
global_name: Optional[:class:`str`]
The team members's global display name, if set.
The team member's global display name, if set.
This takes precedence over :attr:`.name` when shown.
.. versionadded:: 2.9
avatar: Optional[:class:`str`]
The avatar hash the team member has. Could be None.
bot: :class:`bool`
Specifies if the user is a bot account.
team: :class:`Team`
The team that the member is from.
membership_state: :class:`TeamMembershipState`
The membership state of the member (e.g. invited or accepted)
The membership state of the member (e.g. invited or accepted).
role: :class:`TeamMemberRole`
The role of the team member in the team.
"""

__slots__ = ("team", "membership_state", "permissions")
__slots__ = ("team", "membership_state", "role")

def __init__(self, team: Team, state: ConnectionState, data: TeamMemberPayload) -> None:
self.team: Team = team
self.membership_state: TeamMembershipState = try_enum(
TeamMembershipState, data["membership_state"]
)
self.permissions: List[str] = data["permissions"]
self.role: TeamMemberRole = try_enum(TeamMemberRole, data.get("role"))
super().__init__(state=state, data=data["user"])

def __repr__(self) -> str:
Expand Down
5 changes: 3 additions & 2 deletions disnake/types/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from .user import PartialUser

TeamMembershipState = Literal[1, 2]
TeamMemberRole = Literal["admin", "developer", "read_only"]


class TeamMember(TypedDict):
user: PartialUser
membership_state: TeamMembershipState
permissions: List[str]
team_id: Snowflake
user: PartialUser
role: TeamMemberRole


class Team(TypedDict):
Expand Down
22 changes: 22 additions & 0 deletions docs/api/app_info.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ TeamMember

.. autoclass:: TeamMember()
:members:
:inherited-members:

Data Classes
------------
Expand Down Expand Up @@ -89,6 +90,27 @@ TeamMembershipState

Represents a member currently in the team.

TeamMemberRole
~~~~~~~~~~~~~~

.. class:: TeamMemberRole

Represents the role of a team member retrieved through :func:`Client.application_info`.

.. versionadded:: 2.10

.. attribute:: admin

Admins have the most permissions. An admin can only take destructive actions on the team or team-owned apps if they are the team owner.

.. attribute:: developer

Developers can access information about a team and team-owned applications, and take limited actions on them, like configuring interaction endpoints or resetting the bot token.

.. attribute:: read_only

Read-only members can access information about a team and team-owned applications.

ApplicationRoleConnectionMetadataType
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down

0 comments on commit cd48c92

Please sign in to comment.