Browse Source

Add support for role icons

* Document ROLE_ICONS guild feature
https://github.com/discord/discord-api-docs/pull/3847

* Add support for role icons
https://github.com/discord/discord-api-docs/pull/3847

* Add support for role icon/emoji changes in audit log
https://github.com/discord/discord-api-docs/pull/3847
pull/7494/head
jack1142 3 years ago
committed by GitHub
parent
commit
783513726f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      discord/audit_logs.py
  2. 18
      discord/guild.py
  3. 2
      discord/http.py
  4. 61
      discord/role.py
  5. 12
      discord/types/audit_log.py
  6. 1
      discord/types/guild.py
  7. 2
      discord/types/role.py
  8. 17
      docs/api.rst

5
discord/audit_logs.py

@ -119,7 +119,10 @@ def _transform_overwrites(
def _transform_icon(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: def _transform_icon(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]:
if data is None: if data is None:
return None return None
return Asset._from_guild_icon(entry._state, entry.guild.id, data) if entry.action is enums.AuditLogAction.guild_update:
return Asset._from_guild_icon(entry._state, entry.guild.id, data)
else:
return Asset._from_icon(entry._state, entry._target_id, data, path='role')
def _transform_avatar(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: def _transform_avatar(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]:

18
discord/guild.py

@ -212,6 +212,7 @@ class Guild(Hashable):
- ``PARTNERED``: Guild is a partnered server. - ``PARTNERED``: Guild is a partnered server.
- ``PREVIEW_ENABLED``: Guild can be viewed before being accepted via Membership Screening. - ``PREVIEW_ENABLED``: Guild can be viewed before being accepted via Membership Screening.
- ``PRIVATE_THREADS``: Guild has access to create private threads. - ``PRIVATE_THREADS``: Guild has access to create private threads.
- ``ROLE_ICONS``: Guild is able to set role icons.
- ``SEVEN_DAY_THREAD_ARCHIVE``: Guild has access to the seven day archive time for threads. - ``SEVEN_DAY_THREAD_ARCHIVE``: Guild has access to the seven day archive time for threads.
- ``THREE_DAY_THREAD_ARCHIVE``: Guild has access to the three day archive time for threads. - ``THREE_DAY_THREAD_ARCHIVE``: Guild has access to the three day archive time for threads.
- ``TICKETED_EVENTS_ENABLED``: Guild has enabled ticketed events. - ``TICKETED_EVENTS_ENABLED``: Guild has enabled ticketed events.
@ -2394,6 +2395,7 @@ class Guild(Hashable):
permissions: Permissions = ..., permissions: Permissions = ...,
colour: Union[Colour, int] = ..., colour: Union[Colour, int] = ...,
hoist: bool = ..., hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ..., mentionable: bool = ...,
) -> Role: ) -> Role:
... ...
@ -2407,6 +2409,7 @@ class Guild(Hashable):
permissions: Permissions = ..., permissions: Permissions = ...,
color: Union[Colour, int] = ..., color: Union[Colour, int] = ...,
hoist: bool = ..., hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ..., mentionable: bool = ...,
) -> Role: ) -> Role:
... ...
@ -2419,6 +2422,7 @@ class Guild(Hashable):
color: Union[Colour, int] = MISSING, color: Union[Colour, int] = MISSING,
colour: Union[Colour, int] = MISSING, colour: Union[Colour, int] = MISSING,
hoist: bool = MISSING, hoist: bool = MISSING,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = MISSING, mentionable: bool = MISSING,
reason: Optional[str] = None, reason: Optional[str] = None,
) -> Role: ) -> Role:
@ -2434,6 +2438,9 @@ class Guild(Hashable):
.. versionchanged:: 1.6 .. versionchanged:: 1.6
Can now pass ``int`` to ``colour`` keyword-only parameter. Can now pass ``int`` to ``colour`` keyword-only parameter.
.. versionadded:: 2.0
The ``display_icon`` keyword-only parameter was added.
Parameters Parameters
----------- -----------
name: :class:`str` name: :class:`str`
@ -2446,6 +2453,11 @@ class Guild(Hashable):
hoist: :class:`bool` hoist: :class:`bool`
Indicates if the role should be shown separately in the member list. Indicates if the role should be shown separately in the member list.
Defaults to ``False``. Defaults to ``False``.
display_icon: Union[:class:`bytes`, :class:`str`]
A :term:`py:bytes-like object` representing the icon
or :class:`str` representing unicode emoji that should be used as a role icon.
Only PNG/JPEG is supported.
This is only available to guilds that contain ``ROLE_ICONS`` in :attr:`features`.
mentionable: :class:`bool` mentionable: :class:`bool`
Indicates if the role should be mentionable by others. Indicates if the role should be mentionable by others.
Defaults to ``False``. Defaults to ``False``.
@ -2481,6 +2493,12 @@ class Guild(Hashable):
if hoist is not MISSING: if hoist is not MISSING:
fields['hoist'] = hoist fields['hoist'] = hoist
if display_icon is not MISSING:
if isinstance(display_icon, bytes):
fields['icon'] = utils._bytes_to_base64_data(display_icon)
else:
fields['unicode_emoji'] = display_icon
if mentionable is not MISSING: if mentionable is not MISSING:
fields['mentionable'] = mentionable fields['mentionable'] = mentionable

2
discord/http.py

@ -1422,7 +1422,7 @@ class HTTPClient:
self, guild_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None, **fields: Any self, guild_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None, **fields: Any
) -> Response[role.Role]: ) -> Response[role.Role]:
r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id)
valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable') valid_keys = ('name', 'permissions', 'color', 'hoist', 'icon', 'unicode_emoji', 'mentionable')
payload = {k: v for k, v in fields.items() if k in valid_keys} payload = {k: v for k, v in fields.items() if k in valid_keys}
return self.request(r, json=payload, reason=reason) return self.request(r, json=payload, reason=reason)

61
discord/role.py

@ -25,11 +25,12 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict, List, Optional, TypeVar, Union, overload, TYPE_CHECKING from typing import Any, Dict, List, Optional, TypeVar, Union, overload, TYPE_CHECKING
from .asset import Asset
from .permissions import Permissions from .permissions import Permissions
from .errors import InvalidArgument from .errors import InvalidArgument
from .colour import Colour from .colour import Colour
from .mixins import Hashable from .mixins import Hashable
from .utils import snowflake_time, _get_as_snowflake, MISSING from .utils import snowflake_time, _bytes_to_base64_data, _get_as_snowflake, MISSING
__all__ = ( __all__ = (
'RoleTags', 'RoleTags',
@ -163,6 +164,18 @@ class Role(Hashable):
compare for roles in the hierarchy is using the comparison compare for roles in the hierarchy is using the comparison
operators on the role objects themselves. operators on the role objects themselves.
unicode_emoji: Optional[:class:`str`]
The role's unicode emoji, if available.
.. note::
If :attr:`icon` is not ``None``, it is displayed as role icon
instead of the unicode emoji under this attribute.
If you want the icon that a role has displayed, consider using :attr:`display_icon`.
.. versionadded:: 2.0
managed: :class:`bool` managed: :class:`bool`
Indicates if the role is managed by the guild through some form of Indicates if the role is managed by the guild through some form of
integrations such as Twitch. integrations such as Twitch.
@ -178,6 +191,8 @@ class Role(Hashable):
'_permissions', '_permissions',
'_colour', '_colour',
'position', 'position',
'_icon',
'unicode_emoji',
'managed', 'managed',
'mentionable', 'mentionable',
'hoist', 'hoist',
@ -240,6 +255,8 @@ class Role(Hashable):
self.position: int = data.get('position', 0) self.position: int = data.get('position', 0)
self._colour: int = data.get('color', 0) self._colour: int = data.get('color', 0)
self.hoist: bool = data.get('hoist', False) self.hoist: bool = data.get('hoist', False)
self._icon: Optional[str] = data.get('icon')
self.unicode_emoji: Optional[str] = data.get('unicode_emoji')
self.managed: bool = data.get('managed', False) self.managed: bool = data.get('managed', False)
self.mentionable: bool = data.get('mentionable', False) self.mentionable: bool = data.get('mentionable', False)
self.tags: Optional[RoleTags] self.tags: Optional[RoleTags]
@ -297,6 +314,30 @@ class Role(Hashable):
""":class:`Colour`: Returns the role color. An alias exists under ``colour``.""" """:class:`Colour`: Returns the role color. An alias exists under ``colour``."""
return self.colour return self.colour
@property
def icon(self) -> Optional[Asset]:
"""Optional[:class:`.Asset`]: Returns the role's icon asset, if available.
.. note::
If this is ``None``, the role might instead have unicode emoji as its icon
if :attr:`unicode_emoji` is not ``None``.
If you want the icon that a role has displayed, consider using :attr:`display_icon`.
.. versionadded:: 2.0
"""
if self._icon is None:
return None
return Asset._from_icon(self._state, self.id, self._icon, path='role')
@property
def display_icon(self) -> Optional[Union[Asset, str]]:
"""Optional[Union[:class:`.Asset`, :class:`str`]]: Returns the role's display icon, if available.
.. versionadded:: 2.0
"""
return self.icon or self.unicode_emoji
@property @property
def created_at(self) -> datetime.datetime: def created_at(self) -> datetime.datetime:
""":class:`datetime.datetime`: Returns the role's creation time in UTC.""" """:class:`datetime.datetime`: Returns the role's creation time in UTC."""
@ -348,6 +389,7 @@ class Role(Hashable):
colour: Union[Colour, int] = MISSING, colour: Union[Colour, int] = MISSING,
color: Union[Colour, int] = MISSING, color: Union[Colour, int] = MISSING,
hoist: bool = MISSING, hoist: bool = MISSING,
display_icon: Optional[Union[bytes, str]] = MISSING,
mentionable: bool = MISSING, mentionable: bool = MISSING,
position: int = MISSING, position: int = MISSING,
reason: Optional[str] = MISSING, reason: Optional[str] = MISSING,
@ -367,6 +409,9 @@ class Role(Hashable):
.. versionchanged:: 2.0 .. versionchanged:: 2.0
Edits are no longer in-place, the newly edited role is returned instead. Edits are no longer in-place, the newly edited role is returned instead.
.. versionadded:: 2.0
The ``display_icon`` keyword-only parameter was added.
Parameters Parameters
----------- -----------
name: :class:`str` name: :class:`str`
@ -377,6 +422,12 @@ class Role(Hashable):
The new colour to change to. (aliased to color as well) The new colour to change to. (aliased to color as well)
hoist: :class:`bool` hoist: :class:`bool`
Indicates if the role should be shown separately in the member list. Indicates if the role should be shown separately in the member list.
display_icon: Optional[Union[:class:`bytes`, :class:`str`]]
A :term:`py:bytes-like object` representing the icon
or :class:`str` representing unicode emoji that should be used as a role icon.
Could be ``None`` to denote removal of the icon.
Only PNG/JPEG is supported.
This is only available to guilds that contain ``ROLE_ICONS`` in :attr:`features`.
mentionable: :class:`bool` mentionable: :class:`bool`
Indicates if the role should be mentionable by others. Indicates if the role should be mentionable by others.
position: :class:`int` position: :class:`int`
@ -422,6 +473,14 @@ class Role(Hashable):
if hoist is not MISSING: if hoist is not MISSING:
payload['hoist'] = hoist payload['hoist'] = hoist
if display_icon is not MISSING:
payload['icon'] = None
payload['unicode_emoji'] = None
if isinstance(display_icon, bytes):
payload['icon'] = _bytes_to_base64_data(display_icon)
else:
payload['unicode_emoji'] = display_icon
if mentionable is not MISSING: if mentionable is not MISSING:
payload['mentionable'] = mentionable payload['mentionable'] = mentionable

12
discord/types/audit_log.py

@ -84,7 +84,17 @@ AuditLogEvent = Literal[
class _AuditLogChange_Str(TypedDict): class _AuditLogChange_Str(TypedDict):
key: Literal[ key: Literal[
'name', 'description', 'preferred_locale', 'vanity_url_code', 'topic', 'code', 'allow', 'deny', 'permissions', 'tags' 'name',
'description',
'preferred_locale',
'vanity_url_code',
'topic',
'code',
'allow',
'deny',
'permissions',
'tags',
'unicode_emoji',
] ]
new_value: str new_value: str
old_value: str old_value: str

1
discord/types/guild.py

@ -90,6 +90,7 @@ GuildFeature = Literal[
'PARTNERED', 'PARTNERED',
'PREVIEW_ENABLED', 'PREVIEW_ENABLED',
'PRIVATE_THREADS', 'PRIVATE_THREADS',
'ROLE_ICONS',
'SEVEN_DAY_THREAD_ARCHIVE', 'SEVEN_DAY_THREAD_ARCHIVE',
'THREE_DAY_THREAD_ARCHIVE', 'THREE_DAY_THREAD_ARCHIVE',
'TICKETED_EVENTS_ENABLED', 'TICKETED_EVENTS_ENABLED',

2
discord/types/role.py

@ -29,6 +29,8 @@ from .snowflake import Snowflake
class _RoleOptional(TypedDict, total=False): class _RoleOptional(TypedDict, total=False):
icon: Optional[str]
unicode_emoji: Optional[str]
tags: RoleTags tags: RoleTags

17
docs/api.rst

@ -1994,6 +1994,8 @@ of :class:`enum.Enum`.
- :attr:`~AuditLogDiff.colour` - :attr:`~AuditLogDiff.colour`
- :attr:`~AuditLogDiff.mentionable` - :attr:`~AuditLogDiff.mentionable`
- :attr:`~AuditLogDiff.hoist` - :attr:`~AuditLogDiff.hoist`
- :attr:`~AuditLogDiff.icon`
- :attr:`~AuditLogDiff.unicode_emoji`
- :attr:`~AuditLogDiff.name` - :attr:`~AuditLogDiff.name`
- :attr:`~AuditLogDiff.permissions` - :attr:`~AuditLogDiff.permissions`
@ -2004,6 +2006,7 @@ of :class:`enum.Enum`.
- The name has changed - The name has changed
- The permissions have changed - The permissions have changed
- The colour has changed - The colour has changed
- The role icon (or unicode emoji) has changed
- Its hoist/mentionable state has changed - Its hoist/mentionable state has changed
When this is the action, the type of :attr:`~AuditLogEntry.target` is When this is the action, the type of :attr:`~AuditLogEntry.target` is
@ -2014,6 +2017,8 @@ of :class:`enum.Enum`.
- :attr:`~AuditLogDiff.colour` - :attr:`~AuditLogDiff.colour`
- :attr:`~AuditLogDiff.mentionable` - :attr:`~AuditLogDiff.mentionable`
- :attr:`~AuditLogDiff.hoist` - :attr:`~AuditLogDiff.hoist`
- :attr:`~AuditLogDiff.icon`
- :attr:`~AuditLogDiff.unicode_emoji`
- :attr:`~AuditLogDiff.name` - :attr:`~AuditLogDiff.name`
- :attr:`~AuditLogDiff.permissions` - :attr:`~AuditLogDiff.permissions`
@ -2828,7 +2833,7 @@ AuditLogDiff
.. attribute:: icon .. attribute:: icon
A guild's icon. See also :attr:`Guild.icon`. A guild's or role's icon. See also :attr:`Guild.icon` or :attr:`Role.icon`.
:type: :class:`Asset` :type: :class:`Asset`
@ -3202,7 +3207,15 @@ AuditLogDiff
The name of the emoji that represents a sticker being changed. The name of the emoji that represents a sticker being changed.
See also :attr:`GuildSticker.emoji` See also :attr:`GuildSticker.emoji`.
:type: :class:`str`
.. attribute:: unicode_emoji
The unicode emoji that is used as an icon for the role being changed.
See also :attr:`Role.unicode_emoji`.
:type: :class:`str` :type: :class:`str`

Loading…
Cancel
Save