Skip to content

Add support for role icons #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 15 additions & 5 deletions pyvolt/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -6226,6 +6226,7 @@ async def edit_role(
*,
http_overrides: typing.Optional[HTTPOverrideOptions] = None,
name: UndefinedOr[str] = UNDEFINED,
icon: UndefinedOr[typing.Optional[ResolvableResource]] = UNDEFINED,
color: UndefinedOr[typing.Optional[str]] = UNDEFINED,
hoist: UndefinedOr[bool] = UNDEFINED,
rank: UndefinedOr[int] = UNDEFINED,
Expand All @@ -6248,6 +6249,10 @@ async def edit_role(
The HTTP request overrides.
name: UndefinedOr[:class:`str`]
The new role name. Must be between 1 and 32 characters long.
icon: UndefinedOr[Optional[:class:`.ResolvableResource`]]
The new role icon.

.. versionadded:: 1.2
color: UndefinedOr[Optional[:class:`str`]]
The new role color. Must be a valid CSS color.
hoist: UndefinedOr[:class:`bool`]
Expand Down Expand Up @@ -6285,11 +6290,11 @@ async def edit_role(
:class:`NotFound`
Possible values for :attr:`~HTTPException.type`:

+--------------+--------------------------------+
| Value | Reason |
+--------------+--------------------------------+
| ``NotFound`` | The server/role was not found. |
+--------------+--------------------------------+
+--------------+-------------------------------------+
| Value | Reason |
+--------------+-------------------------------------+
| ``NotFound`` | The server/role/file was not found. |
+--------------+-------------------------------------+
:class:`InternalServerError`
Possible values for :attr:`~HTTPException.type`:

Expand All @@ -6309,6 +6314,11 @@ async def edit_role(

if name is not UNDEFINED:
payload['name'] = name
if icon is not UNDEFINED:
if icon is None:
remove.append('Icon')
else:
payload['icon'] = await resolve_resource(self.state, icon, tag='icons')
if color is not UNDEFINED:
if color is None:
remove.append('Colour')
Expand Down
6 changes: 5 additions & 1 deletion pyvolt/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3231,16 +3231,18 @@ def parse_role(self, payload: raw.Role, role_id: str, server_id: str, /) -> Role
server_id: :class:`str`
The server's ID the role belongs to.


Returns
-------
:class:`Role`
The parsed role object.
"""
icon = payload.get('icon')

return Role(
state=self.state,
id=role_id,
name=payload['name'],
internal_icon=None if icon is None else self.parse_asset(icon),
permissions=self.parse_permission_override_field(payload['permissions']),
color=payload.get('colour'),
hoist=payload.get('hoist', False),
Expand Down Expand Up @@ -3667,6 +3669,7 @@ def parse_server_role_update_event(
data = payload['data']
clear = payload['clear']

icon = data.get('icon')
permissions = data.get('permissions')

return RawServerRoleUpdateEvent(
Expand All @@ -3676,6 +3679,7 @@ def parse_server_role_update_event(
id=payload['role_id'],
server_id=payload['id'],
name=data.get('name', UNDEFINED),
internal_icon=None if 'Icon' in clear else UNDEFINED if icon is None else self.parse_asset(icon),
permissions=UNDEFINED if permissions is None else self.parse_permission_override_field(permissions),
color=None if 'Colour' in clear else data.get('colour', UNDEFINED),
hoist=data.get('hoist', UNDEFINED),
Expand Down
5 changes: 4 additions & 1 deletion pyvolt/raw/servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class PartialServer(typing.TypedDict):

class Role(typing.TypedDict):
name: str
icon: typing_extensions.NotRequired[File]
permissions: OverrideField
colour: typing_extensions.NotRequired[str]
hoist: typing_extensions.NotRequired[bool]
Expand All @@ -57,14 +58,15 @@ class Role(typing.TypedDict):

class PartialRole(typing.TypedDict):
name: typing_extensions.NotRequired[str]
icon: typing_extensions.NotRequired[File]
permissions: typing_extensions.NotRequired[OverrideField]
colour: typing_extensions.NotRequired[str]
hoist: typing_extensions.NotRequired[bool]
rank: typing_extensions.NotRequired[int]


FieldsServer = typing.Literal['Description', 'Categories', 'SystemMessages', 'Icon', 'Banner']
FieldsRole = typing.Literal['Colour']
FieldsRole = typing.Literal['Colour', 'Icon']


class Category(typing.TypedDict):
Expand Down Expand Up @@ -128,6 +130,7 @@ class DataEditServer(typing.TypedDict):

class DataEditRole(typing.TypedDict):
name: typing_extensions.NotRequired[str]
icon: typing_extensions.NotRequired[str]
colour: typing_extensions.NotRequired[str]
hoist: typing_extensions.NotRequired[bool]
rank: typing_extensions.NotRequired[int]
Expand Down
69 changes: 53 additions & 16 deletions pyvolt/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ async def edit(
*,
http_overrides: typing.Optional[HTTPOverrideOptions] = None,
name: UndefinedOr[str] = UNDEFINED,
icon: UndefinedOr[typing.Optional[ResolvableResource]] = UNDEFINED,
color: UndefinedOr[typing.Optional[str]] = UNDEFINED,
hoist: UndefinedOr[bool] = UNDEFINED,
rank: UndefinedOr[int] = UNDEFINED,
Expand All @@ -402,6 +403,10 @@ async def edit(
The HTTP request overrides.
name: UndefinedOr[:class:`str`]
The new role name. Must be between 1 and 32 characters long.
icon: UndefinedOr[Optional[:class:`.ResolvableResource`]]
The new role icon.

.. versionadded:: 1.2
color: UndefinedOr[Optional[:class:`str`]]
The new role color. Must be a valid CSS color.
hoist: UndefinedOr[:class:`bool`]
Expand Down Expand Up @@ -439,11 +444,11 @@ async def edit(
:class:`NotFound`
Possible values for :attr:`~HTTPException.type`:

+--------------+--------------------------------+
| Value | Reason |
+--------------+--------------------------------+
| ``NotFound`` | The server/role was not found. |
+--------------+--------------------------------+
+--------------+-------------------------------------+
| Value | Reason |
+--------------+-------------------------------------+
| ``NotFound`` | The server/role/file was not found. |
+--------------+-------------------------------------+
:class:`InternalServerError`
Possible values for :attr:`~HTTPException.type`:

Expand All @@ -463,6 +468,7 @@ async def edit(
self.id,
http_overrides=http_overrides,
name=name,
icon=icon,
color=color,
hoist=hoist,
rank=rank,
Expand Down Expand Up @@ -554,6 +560,12 @@ class PartialRole(BaseRole):
name: UndefinedOr[str] = field(repr=True, kw_only=True)
"""UndefinedOr[:class:`str`]: The new role's name."""

internal_icon: UndefinedOr[typing.Optional[StatelessAsset]] = field(repr=True, kw_only=True)
"""UndefinedOr[Optional[:class:`.StatelessAsset`]]: The new role's icon, if any.

.. versionadded:: 1.2
"""

permissions: UndefinedOr[PermissionOverride] = field(repr=True, kw_only=True)
"""UndefinedOr[:class:`.PermissionOverride`]: The new role's permissions."""

Expand All @@ -570,6 +582,7 @@ def into_full(self) -> typing.Optional[Role]:
"""Optional[:class:`.Role`]: Tries transform this partial role into full object. This is useful when caching role."""
if (
self.name is not UNDEFINED
and self.internal_icon is not UNDEFINED
and self.permissions is not UNDEFINED
and self.hoist is not UNDEFINED
and self.rank is not UNDEFINED
Expand All @@ -580,12 +593,21 @@ def into_full(self) -> typing.Optional[Role]:
id=self.id,
server_id=self.server_id,
name=self.name,
internal_icon=self.internal_icon,
permissions=self.permissions,
color=color,
hoist=self.hoist,
rank=self.rank,
)

@property
def icon(self) -> UndefinedOr[typing.Optional[Asset]]:
"""UndefinedOr[Optional[:class:`.Asset`]]: The stateful role icon.

.. versionadded:: 1.2
"""
return self.internal_icon and self.internal_icon.attach_state(self.state, 'icons')


@define(slots=True)
class Role(BaseRole):
Expand All @@ -597,6 +619,12 @@ class Role(BaseRole):
name: str = field(repr=True, kw_only=True)
""":class:`str`: The role's name."""

internal_icon: typing.Optional[StatelessAsset] = field(repr=True, kw_only=True)
"""Optional[:class:`.StatelessAsset`]: The new server's icon, if any.

.. versionadded:: 1.2
"""

permissions: PermissionOverride = field(repr=True, kw_only=True)
""":class:`.PermissionOverride`: Permissions available to this role."""

Expand All @@ -617,6 +645,8 @@ def locally_update(self, data: PartialRole, /) -> None:
"""
if data.name is not UNDEFINED:
self.name = data.name
if data.internal_icon is not UNDEFINED:
self.internal_icon = data.internal_icon
if data.permissions is not UNDEFINED:
self.permissions = data.permissions
if data.color is not UNDEFINED:
Expand All @@ -626,20 +656,27 @@ def locally_update(self, data: PartialRole, /) -> None:
if data.rank is not UNDEFINED:
self.rank = data.rank

@property
def icon(self) -> UndefinedOr[typing.Optional[Asset]]:
"""UndefinedOr[Optional[:class:`.Asset`]]: The stateful role icon.

.. versionadded:: 1.2
"""
return self.internal_icon and self.internal_icon.attach_state(self.state, 'icons')

def to_dict(self) -> raw.Role:
""":class:`dict`: Convert role to raw data."""

if self.color is None:
payload = {
'name': self.name,
'permissions': self.permissions.to_field_dict(),
}
else:
payload = {
'name': self.name,
'permissions': self.permissions.to_field_dict(),
'colour': self.color,
}
payload: dict[str, typing.Any] = {
'name': self.name,
}
if self.internal_icon is not None:
payload['icon'] = self.internal_icon.to_dict('icons')

payload['permissions'] = self.permissions.to_field_dict()

if self.color is not None:
payload['colour'] = self.color

if self.hoist:
payload['hoist'] = self.hoist
Expand Down