Skip to content

Commit 7724764

Browse files
blord0blord0DA-344dolfies
authored
Add ability to use primary guild (clan) data for users
Co-authored-by: blord0 <[email protected]> Co-authored-by: DA344 <[email protected]> Co-authored-by: dolfies <[email protected]>
1 parent 13dc9c9 commit 7724764

File tree

7 files changed

+150
-2
lines changed

7 files changed

+150
-2
lines changed

discord/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
from .soundboard import *
7474
from .subscription import *
7575
from .presences import *
76+
from .primary_guild import *
7677

7778

7879
class VersionInfo(NamedTuple):

discord/asset.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,15 @@ def _from_user_banner(cls, state: _State, user_id: int, banner_hash: str) -> Sel
346346
animated=animated,
347347
)
348348

349+
@classmethod
350+
def _from_primary_guild(cls, state: _State, guild_id: int, icon_hash: str) -> Self:
351+
return cls(
352+
state,
353+
url=f'{cls.BASE}/guild-tag-badges/{guild_id}/{icon_hash}.png?size=64',
354+
key=icon_hash,
355+
animated=False,
356+
)
357+
349358
def __str__(self) -> str:
350359
return self._url
351360

discord/member.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
GuildVoiceState as GuildVoiceStatePayload,
7575
VoiceState as VoiceStatePayload,
7676
)
77+
from .primary_guild import PrimaryGuild
7778

7879
VocalGuildChannel = Union[VoiceChannel, StageChannel]
7980

@@ -309,6 +310,7 @@ class Member(discord.abc.Messageable, _UserTag):
309310
accent_colour: Optional[Colour]
310311
avatar_decoration: Optional[Asset]
311312
avatar_decoration_sku_id: Optional[int]
313+
primary_guild: PrimaryGuild
312314

313315
def __init__(self, *, data: MemberWithUserPayload, guild: Guild, state: ConnectionState):
314316
self._state: ConnectionState = state
@@ -452,9 +454,11 @@ def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]:
452454
u.global_name,
453455
u._public_flags,
454456
u._avatar_decoration_data['sku_id'] if u._avatar_decoration_data is not None else None,
457+
u._primary_guild,
455458
)
456459

457460
decoration_payload = user.get('avatar_decoration_data')
461+
primary_guild_payload = user.get('primary_guild', None)
458462
# These keys seem to always be available
459463
modified = (
460464
user['username'],
@@ -463,16 +467,26 @@ def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]:
463467
user.get('global_name'),
464468
user.get('public_flags', 0),
465469
decoration_payload['sku_id'] if decoration_payload is not None else None,
470+
primary_guild_payload,
466471
)
467472
if original != modified:
468473
to_return = User._copy(self._user)
469-
u.name, u.discriminator, u._avatar, u.global_name, u._public_flags, u._avatar_decoration_data = (
474+
(
475+
u.name,
476+
u.discriminator,
477+
u._avatar,
478+
u.global_name,
479+
u._public_flags,
480+
u._avatar_decoration_data,
481+
u._primary_guild,
482+
) = (
470483
user['username'],
471484
user['discriminator'],
472485
user['avatar'],
473486
user.get('global_name'),
474487
user.get('public_flags', 0),
475488
decoration_payload,
489+
primary_guild_payload,
476490
)
477491
# Signal to dispatch on_user_update
478492
return to_return, u

discord/primary_guild.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2015-present Rapptz
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a
7+
copy of this software and associated documentation files (the "Software"),
8+
to deal in the Software without restriction, including without limitation
9+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
10+
and/or sell copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+
DEALINGS IN THE SOFTWARE.
23+
"""
24+
25+
from __future__ import annotations
26+
27+
from typing import Optional, TYPE_CHECKING
28+
from datetime import datetime
29+
30+
from .asset import Asset
31+
from .utils import snowflake_time, _get_as_snowflake
32+
33+
if TYPE_CHECKING:
34+
from .state import ConnectionState
35+
from .types.user import PrimaryGuild as PrimaryGuildPayload
36+
from typing_extensions import Self
37+
38+
39+
class PrimaryGuild:
40+
"""Represents the primary guild identity of a :class:`User`
41+
42+
.. versionadded:: 2.6
43+
44+
Attributes
45+
-----------
46+
id: Optional[:class:`int`]
47+
The ID of the user's primary guild, if any.
48+
tag: Optional[:class:`str`]
49+
The primary guild's tag.
50+
identity_enabled: Optional[:class:`bool`]
51+
Whether the user has their primary guild publicly displayed. If ``None``, the user has a public guild but has not reaffirmed the guild identity after a change
52+
53+
.. warning::
54+
55+
Users can have their primary guild publicly displayed while still having an :attr:`id` of ``None``. Be careful when checking this attribute!
56+
"""
57+
58+
__slots__ = ('id', 'identity_enabled', 'tag', '_badge', '_state')
59+
60+
def __init__(self, *, state: ConnectionState, data: PrimaryGuildPayload) -> None:
61+
self._state = state
62+
self._update(data)
63+
64+
def _update(self, data: PrimaryGuildPayload):
65+
self.id = _get_as_snowflake(data, 'identity_guild_id')
66+
self.identity_enabled = data['identity_enabled']
67+
self.tag = data.get('tag', None)
68+
self._badge = data.get('badge')
69+
70+
@property
71+
def badge(self) -> Optional[Asset]:
72+
"""Optional[:class:`Asset`]: Returns the primary guild's asset"""
73+
if self._badge is not None and self.id is not None:
74+
return Asset._from_primary_guild(self._state, self.id, self._badge)
75+
return None
76+
77+
@property
78+
def created_at(self) -> Optional[datetime]:
79+
"""Optional[:class:`datetime.datetime`]: Returns the primary guild's creation time in UTC."""
80+
if self.id is not None:
81+
return snowflake_time(self.id)
82+
return None
83+
84+
@classmethod
85+
def _default(cls, state: ConnectionState) -> Self:
86+
payload: PrimaryGuildPayload = {"identity_enabled": False} # type: ignore
87+
return cls(state=state, data=payload)
88+
89+
def __repr__(self) -> str:
90+
return f'<PrimaryGuild id={self.id} identity_enabled={self.identity_enabled} tag={self.tag!r}>'

discord/types/user.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,10 @@ class User(PartialUser, total=False):
5454
flags: int
5555
premium_type: PremiumType
5656
public_flags: int
57+
58+
59+
class PrimaryGuild(TypedDict):
60+
identity_guild_id: Optional[int]
61+
identity_enabled: Optional[bool]
62+
tag: Optional[str]
63+
badge: Optional[str]

discord/user.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from .enums import DefaultAvatar
3333
from .flags import PublicUserFlags
3434
from .utils import snowflake_time, _bytes_to_base64_data, MISSING, _get_as_snowflake
35+
from .primary_guild import PrimaryGuild
3536

3637
if TYPE_CHECKING:
3738
from typing_extensions import Self
@@ -43,7 +44,12 @@
4344
from .message import Message
4445
from .state import ConnectionState
4546
from .types.channel import DMChannel as DMChannelPayload
46-
from .types.user import PartialUser as PartialUserPayload, User as UserPayload, AvatarDecorationData
47+
from .types.user import (
48+
PartialUser as PartialUserPayload,
49+
User as UserPayload,
50+
AvatarDecorationData,
51+
PrimaryGuild as PrimaryGuildPayload,
52+
)
4753

4854

4955
__all__ = (
@@ -71,6 +77,7 @@ class BaseUser(_UserTag):
7177
'_public_flags',
7278
'_state',
7379
'_avatar_decoration_data',
80+
'_primary_guild',
7481
)
7582

7683
if TYPE_CHECKING:
@@ -86,6 +93,7 @@ class BaseUser(_UserTag):
8693
_accent_colour: Optional[int]
8794
_public_flags: int
8895
_avatar_decoration_data: Optional[AvatarDecorationData]
96+
_primary_guild: Optional[PrimaryGuildPayload]
8997

9098
def __init__(self, *, state: ConnectionState, data: Union[UserPayload, PartialUserPayload]) -> None:
9199
self._state = state
@@ -123,6 +131,7 @@ def _update(self, data: Union[UserPayload, PartialUserPayload]) -> None:
123131
self.bot = data.get('bot', False)
124132
self.system = data.get('system', False)
125133
self._avatar_decoration_data = data.get('avatar_decoration_data')
134+
self._primary_guild = data.get('primary_guild', None)
126135

127136
@classmethod
128137
def _copy(cls, user: Self) -> Self:
@@ -139,6 +148,7 @@ def _copy(cls, user: Self) -> Self:
139148
self._state = user._state
140149
self._public_flags = user._public_flags
141150
self._avatar_decoration_data = user._avatar_decoration_data
151+
self._primary_guild = user._primary_guild
142152

143153
return self
144154

@@ -305,6 +315,15 @@ def display_name(self) -> str:
305315
return self.global_name
306316
return self.name
307317

318+
@property
319+
def primary_guild(self) -> PrimaryGuild:
320+
""":class:`PrimaryGuild`: Returns the user's primary guild.
321+
322+
.. versionadded:: 2.6"""
323+
if self._primary_guild is not None:
324+
return PrimaryGuild(state=self._state, data=self._primary_guild)
325+
return PrimaryGuild._default(self._state)
326+
308327
def mentioned_in(self, message: Message) -> bool:
309328
"""Checks if the user is mentioned in the specified message.
310329

docs/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,6 +5481,14 @@ ClientStatus
54815481
.. autoclass:: ClientStatus()
54825482
:members:
54835483

5484+
PrimaryGuild
5485+
~~~~~~~~~~~~
5486+
5487+
.. attributetable:: PrimaryGuild
5488+
5489+
.. autoclass:: PrimaryGuild()
5490+
:members:
5491+
54845492
Data Classes
54855493
--------------
54865494

0 commit comments

Comments
 (0)