2525
2626from __future__ import annotations
2727
28+ from enum import IntEnum , auto
2829from typing import TYPE_CHECKING , Any , Final , TypeVar
2930
3031from .asset import Asset
3637from .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
112148class 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