Files
muzovkantv2/cogs/role_manager.py
2026-03-09 14:46:45 +05:00

143 lines
5.1 KiB
Python

import discord
from discord.ext import commands
import config
from utils.data_manager import save_message_id, load_message_id
import logging
import asyncio
logger = logging.getLogger(__name__)
class RoleManager(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.role_message_id = None
self.CHANNEL_ID = config.CHANNEL_ID
self.REACTION_ROLES = config.REACTION_ROLES
async def cog_load(self):
self.role_message_id = load_message_id()
if self.role_message_id:
logger.info("Initialized role message with id: %s", self.role_message_id)
else:
logger.info("No role message found")
asyncio.ensure_future(self._startup())
async def _startup(self):
await self.bot.wait_until_ready()
if self.role_message_id:
await self.check_and_sync_roles()
@commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
await self.handle_reaction(payload, add_role=True)
@commands.Cog.listener()
async def on_raw_reaction_remove(self, payload):
await self.handle_reaction(payload, add_role=False)
async def handle_reaction(self, payload, add_role=True):
if payload.message_id != self.role_message_id:
return
emoji = str(payload.emoji)
if emoji not in self.REACTION_ROLES:
return
guild = self.bot.get_guild(payload.guild_id)
if not guild:
return
member = guild.get_member(payload.user_id)
if not member or member.bot:
return
role_id = self.REACTION_ROLES[emoji]
role = guild.get_role(role_id)
if not role:
logger.warning("Role with id %s not found", role_id)
return
try:
if add_role:
await member.add_roles(role)
logger.info("Gave role '%s' to '%s'", role.name, member.name)
else:
await member.remove_roles(role)
logger.info("Removed role '%s' from '%s'", role.name, member.name)
except discord.Forbidden:
logger.error("Missing permissions to manage role '%s'", role.name)
except Exception as e:
logger.error("Unexpected error in handle_reaction: %s", e)
async def check_and_sync_roles(self):
if not self.role_message_id:
return
try:
channel = await self.bot.fetch_channel(self.CHANNEL_ID)
message = await channel.fetch_message(self.role_message_id)
for reaction in message.reactions:
emoji = str(reaction.emoji)
if emoji not in self.REACTION_ROLES:
continue
role = message.guild.get_role(self.REACTION_ROLES[emoji])
if not role:
logger.warning("Role with id %s not found during sync", self.REACTION_ROLES[emoji])
continue
async for user in reaction.users():
if user.bot:
continue
member = message.guild.get_member(user.id)
if member and role not in member.roles:
await member.add_roles(role)
logger.info("Sync gave role '%s' to '%s'", role.name, member.name)
except discord.NotFound:
logger.warning("Role message not found during sync")
except discord.Forbidden:
logger.error("Missing permissions to fetch channel or message")
except Exception as e:
logger.error("Unexpected sync error: %s", e)
@commands.hybrid_command()
@commands.has_permissions(administrator=True)
async def create_role_message(self, ctx):
message = await ctx.send(config.ROLE_MESSAGE_TEXT)
for emoji in self.REACTION_ROLES:
await message.add_reaction(emoji)
self.role_message_id = message.id
save_message_id(message.id)
logger.info("Created new role message with id: %s", message.id)
@commands.hybrid_command()
@commands.has_permissions(administrator=True)
async def update_role_message(self, ctx):
if not self.role_message_id:
return
try:
channel = await self.bot.fetch_channel(self.CHANNEL_ID)
message = await channel.fetch_message(self.role_message_id)
await message.edit(content=config.ROLE_MESSAGE_TEXT)
existing = [str(r.emoji) for r in message.reactions]
for emoji in self.REACTION_ROLES:
if emoji not in existing:
await message.add_reaction(emoji)
logger.info("Role message updated by %s", ctx.author.name)
except discord.NotFound:
logger.warning("Role message not found during update")
except discord.Forbidden:
logger.error("Missing permissions to edit role message")
async def setup(bot):
await bot.add_cog(RoleManager(bot))