Skip to content

Commit 7e7d40e

Browse files
committed
✨ Things
1 parent 54d030d commit 7e7d40e

File tree

1 file changed

+144
-80
lines changed

1 file changed

+144
-80
lines changed

discord/role.py

Lines changed: 144 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
from __future__ import annotations
2727

28-
from typing import TYPE_CHECKING, Any, Final, TypeVar
28+
from enum import IntEnum
29+
from typing import TYPE_CHECKING, Any, TypeVar
2930

3031
from .asset import Asset
3132
from .colour import Colour
@@ -36,6 +37,8 @@
3637
from .utils import (
3738
MISSING,
3839
_bytes_to_base64_data,
40+
cached_slot_property,
41+
deprecated,
3942
snowflake_time,
4043
)
4144

@@ -109,6 +112,43 @@ def _parse_tag_int(data: RoleTagPayload, key: str) -> int | None:
109112
return None
110113

111114

115+
class RoleType(IntEnum):
116+
"""Represents the type of role.
117+
118+
This is NOT provided by discord but is rather computed by pycord based on the role tags.
119+
120+
.. versionadded:: 2.7
121+
122+
Attributes
123+
----------
124+
APPLICATION: :class:`int`
125+
The role is an application role.
126+
BOOSTER: :class:`int`
127+
The role is a guild's booster role.
128+
GUILD_PRODUCT: :class:`int`
129+
The role is a guild product role.
130+
PREMIUM_SUBSCRIPTION_BASE: :class:`int`
131+
The role is a base subscription role.
132+
PREMIUM_SUBSCRIPTION_TIER: :class:`int`
133+
The role is a subscription role.
134+
DRAFT_PREMIUM_SUBSCRIPTION_TIER: :class:`int`
135+
The role is a draft subscription role.
136+
INTEGRATION: :class:`int`
137+
The role is an integration role.
138+
CONNECTION: :class:`int`
139+
The role is a guild connections role.
140+
"""
141+
142+
APPLICATION = 1
143+
BOOSTER = 2
144+
GUILD_PRODUCT = 3
145+
PREMIUM_SUBSCRIPTION_BASE = 4 # Not possible to determine currently, will be INTEGRATION if it's a base subscription
146+
PREMIUM_SUBSCRIPTION_TIER = 5
147+
DRAFT_PREMIUM_SUBSCRIPTION_TIER = 5
148+
INTEGRATION = 7
149+
CONNECTION = 8
150+
151+
112152
class RoleTags:
113153
"""Represents tags on a role.
114154
@@ -142,6 +182,7 @@ class RoleTags:
142182
"_guild_connections",
143183
"bot_id",
144184
"_data",
185+
"_type",
145186
)
146187

147188
def __init__(self, data: RoleTagPayload):
@@ -161,102 +202,73 @@ def __init__(self, data: RoleTagPayload):
161202
data, "available_for_purchase"
162203
)
163204

164-
@property
165-
def is_bot_role(self) -> bool:
166-
"""Whether the role is associated with a bot.
167-
.. versionadded:: 2.7
168-
"""
205+
@cached_slot_property("_type")
206+
def type(self) -> RoleType:
207+
"""Determine the role type based on tag flags."""
208+
# Bot role
209+
if self.bot_id is not None:
210+
return RoleType.APPLICATION
211+
212+
# Role connection
213+
if self._guild_connections is True:
214+
return RoleType.CONNECTION
215+
216+
# Paid roles
217+
if self._guild_connections is False:
218+
if self._premium_subscriber is False:
219+
return RoleType.GUILD_PRODUCT
220+
221+
if self._premium_subscriber is True:
222+
return RoleType.BOOSTER
223+
224+
# subscription roles
225+
if self.integration_id is not None:
226+
if (
227+
self._premium_subscriber is None
228+
and self.subscription_listing_id is not None
229+
):
230+
if self._available_for_purchase is True:
231+
return RoleType.PREMIUM_SUBSCRIPTION_TIER
232+
return RoleType.DRAFT_PREMIUM_SUBSCRIPTION_TIER
233+
234+
# integration role (Twitch/YouTube)
235+
if self.integration_id is not None:
236+
return RoleType.INTEGRATION
237+
238+
raise ValueError("Unable to determine the role type based on provided tags.")
239+
240+
@deprecated("RoleTags.type", "2.7")
241+
def is_bot_managed(self) -> bool:
242+
"""Whether the role is associated with a bot."""
169243
return self.bot_id is not None
170244

171-
@property
172-
def is_booster_role(self) -> bool:
173-
"""Whether the role is the "boost", role for the guild.
174-
.. versionadded:: 2.7
175-
"""
176-
return self._guild_connections is False and self._premium_subscriber is True
177-
178-
@property
179-
def is_guild_product_role(self) -> bool:
180-
"""Whether the role is a guild product role.
245+
@deprecated("RoleTags.type", "2.7")
246+
def is_premium_subscriber(self) -> bool:
247+
"""Whether the role is the premium subscriber, AKA "boost", role for the guild."""
248+
return self._premium_subscriber is None
181249

182-
.. versionadded:: 2.7
183-
"""
184-
return self._guild_connections is False and self._premium_subscriber is False
185-
186-
@property
250+
@deprecated("RoleTags.type", "2.7")
187251
def is_integration(self) -> bool:
188252
"""Whether the guild manages the role through some form of
189253
integrations such as Twitch or through guild subscriptions.
190254
"""
191255
return self.integration_id is not None
192256

193-
@property
194-
def is_base_subscription_role(self) -> bool:
195-
"""Whether the role is a base subscription role.
196-
197-
.. versionadded:: 2.7
198-
"""
199-
return (
200-
self._guild_connections is False
201-
and self._premium_subscriber is False
202-
and self.integration_id is not None
203-
)
204-
205-
@property
206-
def is_subscription_role(self) -> bool:
207-
"""Whether the role is a subscription role.
257+
@deprecated("RoleTags.type", "2.7")
258+
def is_available_for_purchase(self) -> bool:
259+
"""Whether the role is available for purchase."""
260+
return self._available_for_purchase is True
208261

209-
.. versionadded:: 2.7
210-
"""
211-
return (
212-
self._guild_connections is False
213-
and self._premium_subscriber is None
214-
and self.integration_id is not None
215-
and self.subscription_listing_id is not None
216-
and self._available_for_purchase is True
217-
)
218-
219-
@property
220-
def is_draft_subscription_role(self) -> bool:
221-
"""Whether the role is a draft subscription role.
222-
223-
.. versionadded:: 2.7
224-
"""
225-
return (
226-
self._guild_connections is False
227-
and self._premium_subscriber is None
228-
and self.subscription_listing_id is not None
229-
and self.integration_id is not None
230-
and self._available_for_purchase is False
231-
)
232-
233-
@property
262+
@deprecated("RoleTags.type", "2.7")
234263
def is_guild_connections_role(self) -> bool:
235-
"""Whether the role is a guild connections role.
236-
237-
.. versionadded:: 2.7
238-
"""
264+
"""Whether the role is a guild connections role."""
239265
return self._guild_connections is True
240266

241-
QUALIFIERS: Final = (
242-
"is_bot_role",
243-
"is_booster_role",
244-
"is_guild_product_role",
245-
"is_integration",
246-
"is_base_subscription_role",
247-
"is_subscription_role",
248-
"is_draft_subscription_role",
249-
"is_guild_connections_role",
250-
)
251-
252267
def __repr__(self) -> str:
253268
return (
254269
f"<RoleTags bot_id={self.bot_id} integration_id={self.integration_id} "
255270
+ f"subscription_listing_id={self.subscription_listing_id} "
256-
+ " ".join(
257-
q.removeprefix("is_") for q in self.QUALIFIERS if getattr(self, q)
258-
)
259-
+ ">"
271+
+ f"type={self.type!r}>"
260272
)
261273

262274

@@ -431,6 +443,31 @@ def is_default(self) -> bool:
431443
"""Checks if the role is the default role."""
432444
return self.guild.id == self.id
433445

446+
@deprecated("Role.type", "2.7")
447+
def is_bot_managed(self) -> bool:
448+
"""Whether the role is associated with a bot.
449+
450+
.. versionadded:: 1.6
451+
"""
452+
return self.tags is not None and self.tags.is_bot_managed()
453+
454+
@deprecated("Role.type", "2.7")
455+
def is_premium_subscriber(self) -> bool:
456+
"""Whether the role is the premium subscriber, AKA "boost", role for the guild.
457+
458+
.. versionadded:: 1.6
459+
"""
460+
return self.tags is not None and self.tags.is_premium_subscriber()
461+
462+
@deprecated("Role.type", "2.7")
463+
def is_integration(self) -> bool:
464+
"""Whether the guild manages the role through some form of
465+
integrations such as Twitch or through guild subscriptions.
466+
467+
.. versionadded:: 1.6
468+
"""
469+
return self.tags is not None and self.tags.is_integration()
470+
434471
def is_assignable(self) -> bool:
435472
"""Whether the role is able to be assigned or removed by the bot.
436473
@@ -443,6 +480,25 @@ def is_assignable(self) -> bool:
443480
and (me.top_role > self or me.id == self.guild.owner_id)
444481
)
445482

483+
@deprecated("Role.type", "2.7")
484+
def is_available_for_purchase(self) -> bool:
485+
"""Whether the role is available for purchase.
486+
Returns ``True`` if the role is available for purchase, and
487+
``False`` if it is not available for purchase or if the
488+
role is not linked to a guild subscription.
489+
490+
.. versionadded:: 2.7
491+
"""
492+
return self.tags is not None and self.tags.is_available_for_purchase()
493+
494+
@deprecated("Role.type", "2.7")
495+
def is_guild_connections_role(self) -> bool:
496+
"""Whether the role is a guild connections role.
497+
498+
.. versionadded:: 2.7
499+
"""
500+
return self.tags is not None and self.tags.is_guild_connections_role()
501+
446502
@property
447503
def permissions(self) -> Permissions:
448504
"""Returns the role's permissions."""
@@ -489,6 +545,14 @@ def icon(self) -> Asset | None:
489545

490546
return Asset._from_icon(self._state, self.id, self._icon, "role")
491547

548+
@property
549+
def type(self) -> RoleType:
550+
"""The type of the role.
551+
552+
.. versionadded:: 2.7
553+
"""
554+
return self.tags.type
555+
492556
async def _move(self, position: int, reason: str | None) -> None:
493557
if position <= 0:
494558
raise InvalidArgument("Cannot move role to position 0 or below")

0 commit comments

Comments
 (0)