discordbot/cogs/role_creator_cog.py
2025-04-25 14:03:49 -06:00

140 lines
7.7 KiB
Python

import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(name)s: %(message)s')
logger = logging.getLogger(__name__)
# Load environment variables
load_dotenv()
OWNER_USER_ID = int(os.getenv("OWNER_USER_ID")) # Although commands.is_owner() handles this, loading for clarity/potential future use
class RoleCreatorCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.command(name='create_roles', help='Creates predefined roles for reaction roles. Owner only.')
@commands.is_owner() # Restricts this command to the bot owner specified during bot setup
async def create_roles(self, ctx):
"""Creates a set of predefined roles typically used with reaction roles."""
guild = ctx.guild
if not guild:
await ctx.send("This command can only be used in a server.")
return
# Check if the bot has permission to manage roles
if not ctx.me.guild_permissions.manage_roles:
await ctx.send("I don't have permission to manage roles.")
logger.warning(f"Missing 'Manage Roles' permission in guild {guild.id} ({guild.name}).")
return
# Define color mapping for specific roles
color_map = {
"Red": discord.Color.red(),
"Blue": discord.Color.blue(),
"Green": discord.Color.green(),
"Yellow": discord.Color.gold(),
"Purple": discord.Color.purple(),
"Orange": discord.Color.orange(),
"Pink": discord.Color.fuchsia(),
"Black": discord.Color(0x010101), # Near black to avoid blending with themes
"White": discord.Color(0xFEFEFE) # Near white to avoid blending
}
await ctx.send("Starting role creation/update process...")
logger.info(f"Role creation/update initiated by {ctx.author} in guild {guild.id} ({guild.name}).")
role_categories = {
"Colors": ["Red", "Blue", "Green", "Yellow", "Purple", "Orange", "Pink", "Black", "White"],
"Regions": ["NA East", "NA West", "EU", "Asia", "Oceania", "South America"],
"Pronouns": ["He/Him", "She/Her", "They/Them", "Ask Pronouns"],
"Interests": ["Art", "Music", "Movies", "Books", "Technology", "Science", "History", "Food", "Programming", "Anime", "Photography", "Travel", "Writing", "Cooking", "Fitness", "Nature", "Gaming", "Philosophy", "Psychology", "Design", "Machine Learning", "Cryptocurrency", "Astronomy", "Mythology", "Languages", "Architecture", "DIY Projects", "Hiking", "Streaming", "Virtual Reality", "Coding Challenges", "Board Games", "Meditation", "Urban Exploration", "Tattoo Art", "Comics", "Robotics", "3D Modeling", "Podcasts"],
"Gaming Platforms": ["PC", "PlayStation", "Xbox", "Nintendo Switch", "Mobile"],
"Favorite Vocaloids": ["Hatsune Miku", "Kasane Teto", "Akita Neru", "Kagamine Rin", "Kagamine Len", "Megurine Luka", "Kaito", "Meiko", "Gumi", "Kaai Yuki"],
"Notifications": ["Announcements"]
}
created_count = 0
updated_count = 0 # Renamed from eped_count
skipped_other_count = 0 # For non-color roles that exist
error_count = 0
existing_roles = {role.name.lower(): role for role in guild.roles} # Cache existing roles for faster lookup
for category, names in role_categories.items():
logger.info(f"Processing category: {category}")
for name in names:
role_color = color_map.get(name) if category == "Colors" else None
role_exists = name.lower() in existing_roles
try:
if role_exists:
existing_role = existing_roles[name.lower()]
# Only edit if it's a color role and needs a color update (or just ensure color is set)
if category == "Colors" and role_color is not None:
# Check if color needs updating to avoid unnecessary API calls
if existing_role.color != role_color:
await existing_role.edit(color=role_color)
logger.info(f"Successfully updated color for existing role: {name}")
updated_count += 1
else:
logger.info(f"Role '{name}' already exists with correct color. Skipping update.")
updated_count += 1 # Count as updated/checked even if no change needed
else:
# Non-color role exists, skip it
logger.info(f"Non-color role '{name}' already exists. Skipping.")
skipped_other_count += 1
continue # Move to next role name
# Role does not exist, create it
await guild.create_role(
name=name,
color=role_color or discord.Color.default(), # Use mapped color or default
permissions=discord.Permissions.none(),
mentionable=False
)
logger.info(f"Successfully created role: {name}" + (f" with color {role_color}" if role_color else ""))
created_count += 1
except discord.Forbidden:
logger.error(f"Forbidden to {'edit' if role_exists else 'create'} role '{name}'. Check bot permissions.")
await ctx.send(f"Error: I lack permissions to {'edit' if role_exists else 'create'} the role '{name}'.")
error_count += 1
# Stop if permission error occurs, as it likely affects subsequent operations
await ctx.send(f"Stopping role processing due to permission error on role '{name}'.")
return
except discord.HTTPException as e:
logger.error(f"Failed to {'edit' if role_exists else 'create'} role '{name}': {e}")
await ctx.send(f"Error {'editing' if role_exists else 'creating'} role '{name}': {e}")
error_count += 1
except Exception as e:
logger.exception(f"An unexpected error occurred while processing role '{name}': {e}")
await ctx.send(f"An unexpected error occurred for role '{name}'. Check logs.")
error_count += 1
summary_message = f"Role creation/update process complete.\n" \
f"Created: {created_count}\n" \
f"Updated/Checked Colors: {updated_count}\n" \
f"Skipped (Other existing): {skipped_other_count}\n" \
f"Errors: {error_count}"
await ctx.send(summary_message)
logger.info(summary_message)
async def setup(bot):
# Ensure the owner ID is loaded correctly before adding the cog
if not OWNER_USER_ID:
logger.error("OWNER_USER_ID not found in .env file. RoleCreatorCog will not be loaded.")
return
# Check if the bot object has owner_id or owner_ids set, which discord.py uses for is_owner()
if not bot.owner_id and not bot.owner_ids:
logger.warning("Bot owner_id or owner_ids not set. The 'is_owner()' check might not function correctly.")
# Potentially load from OWNER_USER_ID if needed, though discord.py usually handles this
# bot.owner_id = OWNER_USER_ID # Uncomment if necessary and discord.py doesn't auto-load
await bot.add_cog(RoleCreatorCog(bot))
logger.info("RoleCreatorCog loaded successfully.")