tux.cogs.services.status_roles
¶
Classes:
Name | Description |
---|---|
StatusRoles | Assign roles to users based on their status. |
Classes¶
StatusRoles(bot: commands.Bot)
¶
Bases: Cog
Assign roles to users based on their status.
Methods:
Name | Description |
---|---|
on_ready | Check all users' statuses when the bot starts up. |
on_presence_update | Event triggered when a user's presence changes. |
has_activity_changed | Check if there was a relevant change in activities. |
get_custom_status | Extract the custom status text from a member's activities. |
check_and_update_roles | Check a member's status against configured patterns and update roles accordingly. |
Source code in tux/cogs/services/status_roles.py
Python
def __init__(self, bot: commands.Bot):
self.bot = bot
self.status_roles = CONFIG.STATUS_ROLES
self._unload_task = None # Store task reference here
# Check if config exists and is valid
if not self.status_roles:
logger.warning("No status roles configurations found. Unloading StatusRoles cog.")
# Store the task reference
self._unload_task = asyncio.create_task(self._unload_self())
else:
logger.info(f"StatusRoles cog initialized with {len(self.status_roles)} role configurations")
Functions¶
_unload_self()
async
¶
Unload this cog if configuration is missing.
Source code in tux/cogs/services/status_roles.py
Python
async def _unload_self(self):
"""Unload this cog if configuration is missing."""
try:
await self.bot.unload_extension("tux.cogs.services.status_roles")
logger.info("StatusRoles cog has been unloaded due to missing configuration")
except Exception as e:
logger.error(f"Failed to unload StatusRoles cog: {e}")
on_ready()
async
¶
Check all users' statuses when the bot starts up.
Source code in tux/cogs/services/status_roles.py
on_presence_update(before: discord.Member, after: discord.Member)
async
¶
Event triggered when a user's presence changes.
Source code in tux/cogs/services/status_roles.py
Python
@commands.Cog.listener()
async def on_presence_update(self, before: discord.Member, after: discord.Member):
"""Event triggered when a user's presence changes."""
logger.trace(f"Presence update for {after.display_name}: {before.status} -> {after.status}")
# Only process if the custom status changed
before_status = self.get_custom_status(before)
after_status = self.get_custom_status(after)
if before_status != after_status or self.has_activity_changed(before, after):
logger.trace(f"Status change detected for {after.display_name}: '{before_status}' -> '{after_status}'")
await self.check_and_update_roles(after)
has_activity_changed(before: discord.Member, after: discord.Member) -> bool
¶
Check if there was a relevant change in activities.
Source code in tux/cogs/services/status_roles.py
Python
def has_activity_changed(self, before: discord.Member, after: discord.Member) -> bool:
"""Check if there was a relevant change in activities."""
before_has_custom = (
any(isinstance(a, discord.CustomActivity) for a in before.activities) if before.activities else False
)
after_has_custom = (
any(isinstance(a, discord.CustomActivity) for a in after.activities) if after.activities else False
)
return before_has_custom != after_has_custom
get_custom_status(member: discord.Member) -> str | None
¶
Extract the custom status text from a member's activities.
Source code in tux/cogs/services/status_roles.py
Python
def get_custom_status(self, member: discord.Member) -> str | None:
"""Extract the custom status text from a member's activities."""
if not member.activities:
return None
return next(
(
activity.name
for activity in member.activities
if isinstance(activity, discord.CustomActivity) and activity.name
),
None,
)
check_and_update_roles(member: discord.Member)
async
¶
Check a member's status against configured patterns and update roles accordingly.
Source code in tux/cogs/services/status_roles.py
Python
async def check_and_update_roles(self, member: discord.Member):
"""Check a member's status against configured patterns and update roles accordingly."""
if member.bot:
return
status_text = self.get_custom_status(member)
if status_text is None:
status_text = "" # Use empty string for regex matching if no status
for config in self.status_roles:
# Skip if the config is for a different server
if int(config.get("server_id", 0)) != member.guild.id:
continue
role_id = int(config.get("role_id", 0))
pattern = str(config.get("status_regex", ".*"))
role = member.guild.get_role(role_id)
if not role:
logger.warning(f"Role {role_id} configured in STATUS_ROLES not found in guild {member.guild.name}")
continue
try:
matches = bool(re.search(pattern, status_text, re.IGNORECASE))
has_role = role in member.roles
if matches and not has_role:
# Add role if status matches and member doesn't have the role
logger.info(
f"Adding role {role.name} to {member.display_name} (status: '{status_text}' matched '{pattern}')",
)
await member.add_roles(role)
elif not matches and has_role:
# Remove role if status doesn't match and member has the role
logger.info(f"Removing role {role.name} from {member.display_name} (status no longer matches)")
await member.remove_roles(role)
except re.error:
logger.exception(f"Invalid regex pattern '{pattern}' in STATUS_ROLES config")
except discord.Forbidden:
logger.exception(
f"Bot lacks permission to modify roles for {member.display_name} in {member.guild.name}",
)
except Exception:
logger.exception(f"Error updating roles for {member.display_name}")