import os import discord from discord.ext import commands from data import react_roles from util.console import console, panel, track_iterable as track GUILD_IDS = [int(os.getenv("DEV_GUILD_ID"))] REACTION_ROLE_CHANNEL_ID = int(os.getenv("REACT_ROLE_CHANNEL_ID")) def update_react_role_embed(category_name): # Generate role list roles = react_roles.get_react_roles_by_category(category_name) role_list = [] for role in roles: emoji = role[2] description = role[3] role_list.append(f"{emoji} - {description}") # Create an embed for the react-role category embed = discord.Embed(title=f"**{category_name.capitalize()} Roles**", description="React to this message to gain access to the relevant text and voice channels.\n\n" + "\n".join(role_list), color=discord.Color.dark_orange()) return embed class ReactRoles(commands.Cog): def __init__(self, bot): self.bot = bot # Slash command to add a new reaction role Category / Message @commands.slash_command(name="new_react_role_category", description="Create a new category of react roles", guild_ids=GUILD_IDS) @commands.has_permissions(manage_roles=True) async def new_react_role_category(self, ctx: discord.ApplicationContext, category_name: str): # Verify the category is unique existing_categories = react_roles.get_react_roles_categories() if category_name.lower() in [cat[1] for cat in existing_categories]: await ctx.respond(f"Category '{category_name}' already exists.", ephemeral=True) return # Send a new Embed message embed = discord.Embed(title=f"**{category_name.capitalize()} Roles**", description="React to this message to gain access to the relevant text and voice channels.", color=discord.Color.dark_orange()) message = await ctx.guild.get_channel(REACTION_ROLE_CHANNEL_ID).send(embed=embed) # Create the category in the database react_roles.add_react_role_category_to_db(message.id, category_name) # Send a confirmation message await ctx.respond(f"React role category '{category_name}' created successfully!", ephemeral=True) #Slash command to add a new reaction role to an existing category @commands.slash_command(name="new_react_role", description="Create a new react role", guild_ids=GUILD_IDS) @commands.has_permissions(manage_roles=True) async def new_react_role(self, ctx: discord.ApplicationContext, category_name: str, role: discord.Role, emoji: str, description: str): # Verify the category exists existing_categories = react_roles.get_react_roles_categories() if category_name.lower() not in [cat[1] for cat in existing_categories]: await ctx.respond(f"Category '{category_name}' does not exist.", ephemeral=True) return # Get the message ID of the category message_id = next(cat[0] for cat in existing_categories if cat[1] == category_name.lower()) # Add the react-role to the database react_roles.add_react_role_to_db(message_id, role.id, emoji, description) message = await self.bot.get_channel(REACTION_ROLE_CHANNEL_ID).fetch_message(message_id) await message.edit(embed=update_react_role_embed(category_name)) await message.add_reaction(emoji) # Send a confirmation message await ctx.respond(f"React role '{emoji}' - '{role.name}' added to category '{category_name}'.", ephemeral=True) # Event listener for reaction add @commands.Cog.listener() async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): # Check if the reaction is in the correct channel and not from the bot itself if payload.channel_id != REACTION_ROLE_CHANNEL_ID or payload.user_id == self.bot.user.id: return # Ge all react roles for the message_id that was reacted to message_id = payload.message_id emoji = str(payload.emoji) react_roles_list = react_roles.get_react_roles_by_message_id(message_id) if react_roles_list: for role in react_roles_list: if role[2] == emoji: guild = self.bot.get_guild(payload.guild_id) member = payload.member role_obj = guild.get_role(role[1]) # Add the role to the member if role_obj not in member.roles: await member.add_roles(role_obj) console.log (f"[green]✔ Added role:[/] {emoji} {role_obj.name} to {member.name}") # Event Listener for reaction remove @commands.Cog.listener() async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): # Check if the reaction is in the correct channel and not from the bot itself if payload.channel_id != REACTION_ROLE_CHANNEL_ID or payload.user_id == self.bot.user.id: return # Ge all react roles for the message_id that was reacted to message_id = payload.message_id emoji = str(payload.emoji) react_roles_list = react_roles.get_react_roles_by_message_id(message_id) if react_roles_list: for role in react_roles_list: if role[2] == emoji: guild = self.bot.get_guild(payload.guild_id) # Member object is not available in the payload, so we need to fetch it... member = await guild.fetch_member(payload.user_id) role_obj = guild.get_role(role[1]) # Add the role to the member if role_obj in member.roles: await member.remove_roles(role_obj) console.log (f"[red]✖ Removed role:[/] {emoji} {role_obj.name} from {member.name}") def setup(bot): bot.add_cog(ReactRoles(bot))