Skip to content

Commit 7107f01

Browse files
committed
✨ Things
1 parent 54d030d commit 7107f01

File tree

1 file changed

+134
-76
lines changed

1 file changed

+134
-76
lines changed

discord/role.py

Lines changed: 134 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
from __future__ import annotations
2727

28+
from enum import IntEnum, auto
2829
from typing import TYPE_CHECKING, Any, Final, TypeVar
2930

3031
from .asset import Asset
@@ -36,7 +37,7 @@
3637
from .utils import (
3738
MISSING,
3839
_bytes_to_base64_data,
39-
snowflake_time,
40+
snowflake_time, cached_slot_property, deprecated,
4041
)
4142

4243
__all__ = (
@@ -108,6 +109,41 @@ def _parse_tag_int(data: RoleTagPayload, key: str) -> int | None:
108109
# value error means it's not an number string (None or "")
109110
return None
110111

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

112148
class RoleTags:
113149
"""Represents tags on a role.
@@ -142,6 +178,7 @@ class RoleTags:
142178
"_guild_connections",
143179
"bot_id",
144180
"_data",
181+
"_type",
145182
)
146183

147184
def __init__(self, data: RoleTagPayload):
@@ -161,102 +198,75 @@ def __init__(self, data: RoleTagPayload):
161198
data, "available_for_purchase"
162199
)
163200

164-
@property
165-
def is_bot_role(self) -> bool:
166-
"""Whether the role is associated with a bot.
167-
.. versionadded:: 2.7
201+
@cached_slot_property("_type")
202+
def type(self) -> RoleType:
168203
"""
169-
return self.bot_id is not None
170-
171-
@property
172-
def is_booster_role(self) -> bool:
173-
"""Whether the role is the "boost", role for the guild.
174-
.. versionadded:: 2.7
204+
Determine the role type based on tag flags.
175205
"""
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.
206+
# Bot role
207+
if self.bot_id is not None:
208+
return RoleType.APPLICATION
209+
210+
# Role connection
211+
if self._guild_connections is True:
212+
return RoleType.CONNECTION
213+
214+
# Paid roles
215+
if self._guild_connections is False:
216+
if self._premium_subscriber is False:
217+
return RoleType.GUILD_PRODUCT
218+
219+
if self._premium_subscriber is True:
220+
return RoleType.BOOSTER
221+
222+
# subscription roles
223+
if self.integration_id is not None:
224+
if self._premium_subscriber is None and self.subscription_listing_id is not None:
225+
if self._available_for_purchase is True:
226+
return RoleType.PREMIUM_SUBSCRIPTION_TIER
227+
return RoleType.DRAFT_PREMIUM_SUBSCRIPTION_TIER
228+
229+
# integration role (Twitch/YouTube)
230+
if self.integration_id is not None:
231+
return RoleType.INTEGRATION
232+
233+
raise ValueError("Unable to determine the role type based on provided tags.")
234+
235+
@deprecated("RoleTags.type", "2.7")
236+
def is_bot_managed(self) -> bool:
237+
"""Whether the role is associated with a bot."""
238+
return self.bot_id is not None
181239

182-
.. versionadded:: 2.7
183-
"""
184-
return self._guild_connections is False and self._premium_subscriber is False
240+
@deprecated("RoleTags.type", "2.7")
241+
def is_premium_subscriber(self) -> bool:
242+
"""Whether the role is the premium subscriber, AKA "boost", role for the guild."""
243+
return self._premium_subscriber is None
185244

186-
@property
245+
@deprecated("RoleTags.type", "2.7")
187246
def is_integration(self) -> bool:
188247
"""Whether the guild manages the role through some form of
189248
integrations such as Twitch or through guild subscriptions.
190249
"""
191250
return self.integration_id is not None
192251

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.
208-
209-
.. versionadded:: 2.7
252+
@deprecated("RoleTags.type", "2.7")
253+
def is_available_for_purchase(self) -> bool:
254+
"""Whether the role is available for purchase.
210255
"""
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-
)
256+
return self._available_for_purchase is True
218257

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
258+
@deprecated("RoleTags.type", "2.7")
234259
def is_guild_connections_role(self) -> bool:
235260
"""Whether the role is a guild connections role.
236261
237-
.. versionadded:: 2.7
238-
"""
262+
"""
239263
return self._guild_connections is True
240264

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-
252265
def __repr__(self) -> str:
253266
return (
254267
f"<RoleTags bot_id={self.bot_id} integration_id={self.integration_id} "
255268
+ 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-
+ ">"
269+
+ f"type={self.type!r}>"
260270
)
261271

262272

@@ -431,6 +441,29 @@ def is_default(self) -> bool:
431441
"""Checks if the role is the default role."""
432442
return self.guild.id == self.id
433443

444+
@deprecated("Role.type", "2.7")
445+
def is_bot_managed(self) -> bool:
446+
"""Whether the role is associated with a bot.
447+
.. versionadded:: 1.6
448+
"""
449+
return self.tags is not None and self.tags.is_bot_managed()
450+
451+
@deprecated("Role.type", "2.7")
452+
def is_premium_subscriber(self) -> bool:
453+
"""Whether the role is the premium subscriber, AKA "boost", role for the guild.
454+
.. versionadded:: 1.6
455+
"""
456+
return self.tags is not None and self.tags.is_premium_subscriber()
457+
458+
@deprecated("Role.type", "2.7")
459+
def is_integration(self) -> bool:
460+
"""Whether the guild manages the role through some form of
461+
integrations such as Twitch or through guild subscriptions.
462+
.. versionadded:: 1.6
463+
"""
464+
return self.tags is not None and self.tags.is_integration()
465+
466+
434467
def is_assignable(self) -> bool:
435468
"""Whether the role is able to be assigned or removed by the bot.
436469
@@ -443,6 +476,23 @@ def is_assignable(self) -> bool:
443476
and (me.top_role > self or me.id == self.guild.owner_id)
444477
)
445478

479+
@deprecated("Role.type", "2.7")
480+
def is_available_for_purchase(self) -> bool:
481+
"""Whether the role is available for purchase.
482+
Returns ``True`` if the role is available for purchase, and
483+
``False`` if it is not available for purchase or if the
484+
role is not linked to a guild subscription.
485+
.. versionadded:: 2.7
486+
"""
487+
return self.tags is not None and self.tags.is_available_for_purchase()
488+
489+
@deprecated("Role.type", "2.7")
490+
def is_guild_connections_role(self) -> bool:
491+
"""Whether the role is a guild connections role.
492+
.. versionadded:: 2.7
493+
"""
494+
return self.tags is not None and self.tags.is_guild_connections_role()
495+
446496
@property
447497
def permissions(self) -> Permissions:
448498
"""Returns the role's permissions."""
@@ -489,6 +539,14 @@ def icon(self) -> Asset | None:
489539

490540
return Asset._from_icon(self._state, self.id, self._icon, "role")
491541

542+
@property
543+
def type(self) -> RoleType:
544+
"""The type of the role.
545+
546+
.. versionadded:: 2.7
547+
"""
548+
return self.tags.type
549+
492550
async def _move(self, position: int, reason: str | None) -> None:
493551
if position <= 0:
494552
raise InvalidArgument("Cannot move role to position 0 or below")

0 commit comments

Comments
 (0)