import discord from discord.ext import commands import logging import sys import os # Add the parent directory to sys.path to ensure settings_manager is accessible sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import settings_manager from global_bot_accessor import get_bot_instance log = logging.getLogger(__name__) class WelcomeCog(commands.Cog): """Handles welcome and goodbye messages for guilds.""" def __init__(self, bot: commands.Bot): self.bot = bot print("WelcomeCog: Initializing and registering event listeners") # Check existing event listeners print( f"WelcomeCog: Bot event listeners before registration: {self.bot.extra_events}" ) # Register event listeners self.bot.add_listener(self.on_member_join, "on_member_join") self.bot.add_listener(self.on_member_remove, "on_member_remove") # Check if event listeners were registered print( f"WelcomeCog: Bot event listeners after registration: {self.bot.extra_events}" ) print("WelcomeCog: Event listeners registered") async def on_member_join(self, member: discord.Member): """Sends a welcome message when a new member joins.""" print(f"WelcomeCog: on_member_join event triggered for {member.name}") guild = member.guild if not guild: print(f"WelcomeCog: Guild not found for member {member.name}") return log.debug(f"Member {member.name} joined guild {guild.name} ({guild.id})") print( f"WelcomeCog: Member {member.name} joined guild {guild.name} ({guild.id})" ) # --- Fetch settings --- print(f"WelcomeCog: Fetching welcome settings for guild {guild.id}") welcome_channel_id_str = await settings_manager.get_setting( guild.id, "welcome_channel_id" ) welcome_message_template = await settings_manager.get_setting( guild.id, "welcome_message", default="Welcome {user} to {server}!" ) print( f"WelcomeCog: Retrieved settings - channel_id: {welcome_channel_id_str}, message: {welcome_message_template}" ) # Handle the "__NONE__" marker for potentially unset values if not welcome_channel_id_str or welcome_channel_id_str == "__NONE__": log.debug(f"Welcome channel not configured for guild {guild.id}") print(f"WelcomeCog: Welcome channel not configured for guild {guild.id}") return try: welcome_channel_id = int(welcome_channel_id_str) channel = guild.get_channel(welcome_channel_id) if not channel or not isinstance(channel, discord.TextChannel): log.warning( f"Welcome channel ID {welcome_channel_id} not found or not text channel in guild {guild.id}" ) # Maybe remove the setting here if the channel is invalid? return # --- Format and send message --- # Basic formatting, can be expanded formatted_message = welcome_message_template.format( user=member.mention, username=member.name, server=guild.name ) await channel.send(formatted_message) log.info(f"Sent welcome message for {member.name} in guild {guild.id}") except ValueError: log.error( f"Invalid welcome_channel_id '{welcome_channel_id_str}' configured for guild {guild.id}" ) except discord.Forbidden: log.error( f"Missing permissions to send welcome message in channel {welcome_channel_id} for guild {guild.id}" ) except Exception as e: log.exception(f"Error sending welcome message for guild {guild.id}: {e}") async def on_member_remove(self, member: discord.Member): """Sends a goodbye message when a member leaves.""" print(f"WelcomeCog: on_member_remove event triggered for {member.name}") guild = member.guild if not guild: print(f"WelcomeCog: Guild not found for member {member.name}") return log.debug(f"Member {member.name} left guild {guild.name} ({guild.id})") print(f"WelcomeCog: Member {member.name} left guild {guild.name} ({guild.id})") # --- Fetch settings --- print(f"WelcomeCog: Fetching goodbye settings for guild {guild.id}") goodbye_channel_id_str = await settings_manager.get_setting( guild.id, "goodbye_channel_id" ) goodbye_message_template = await settings_manager.get_setting( guild.id, "goodbye_message", default="{username} has left the server." ) print( f"WelcomeCog: Retrieved settings - channel_id: {goodbye_channel_id_str}, message: {goodbye_message_template}" ) # Handle the "__NONE__" marker if not goodbye_channel_id_str or goodbye_channel_id_str == "__NONE__": log.debug(f"Goodbye channel not configured for guild {guild.id}") print(f"WelcomeCog: Goodbye channel not configured for guild {guild.id}") return try: goodbye_channel_id = int(goodbye_channel_id_str) channel = guild.get_channel(goodbye_channel_id) if not channel or not isinstance(channel, discord.TextChannel): log.warning( f"Goodbye channel ID {goodbye_channel_id} not found or not text channel in guild {guild.id}" ) return # --- Format and send message --- formatted_message = goodbye_message_template.format( user=member.mention, # Might not be mentionable after leaving username=member.name, server=guild.name, ) await channel.send(formatted_message) log.info(f"Sent goodbye message for {member.name} in guild {guild.id}") except ValueError: log.error( f"Invalid goodbye_channel_id '{goodbye_channel_id_str}' configured for guild {guild.id}" ) except discord.Forbidden: log.error( f"Missing permissions to send goodbye message in channel {goodbye_channel_id} for guild {guild.id}" ) except Exception as e: log.exception(f"Error sending goodbye message for guild {guild.id}: {e}") @commands.command( name="setwelcome", help="Sets the welcome message and channel. Usage: `setwelcome #channel [message template]`", ) @commands.has_permissions(administrator=True) @commands.guild_only() async def set_welcome( self, ctx: commands.Context, channel: discord.TextChannel, *, message_template: str = "Welcome {user} to {server}!", ): """Sets the channel and template for welcome messages.""" guild_id = ctx.guild.id key_channel = "welcome_channel_id" key_message = "welcome_message" # Use settings_manager.set_setting success_channel = await settings_manager.set_setting( guild_id, key_channel, str(channel.id) ) success_message = await settings_manager.set_setting( guild_id, key_message, message_template ) if success_channel and success_message: # Both need to succeed await ctx.send( f"Welcome messages will now be sent to {channel.mention} with the template:\n```\n{message_template}\n```" ) log.info( f"Welcome settings updated for guild {guild_id} by {ctx.author.name}" ) else: await ctx.send("Failed to save welcome settings. Check logs.") log.error(f"Failed to save welcome settings for guild {guild_id}") @commands.command( name="disablewelcome", help="Disables welcome messages for this server." ) @commands.has_permissions(administrator=True) @commands.guild_only() async def disable_welcome(self, ctx: commands.Context): """Disables welcome messages by removing the channel setting.""" guild_id = ctx.guild.id key_channel = "welcome_channel_id" key_message = "welcome_message" # Also clear the message template # Use set_setting with None to delete the settings success_channel = await settings_manager.set_setting( guild_id, key_channel, None ) success_message = await settings_manager.set_setting( guild_id, key_message, None ) if success_channel and success_message: # Both need to succeed await ctx.send("Welcome messages have been disabled.") log.info( f"Welcome messages disabled for guild {guild_id} by {ctx.author.name}" ) else: await ctx.send("Failed to disable welcome messages. Check logs.") log.error(f"Failed to disable welcome settings for guild {guild_id}") @commands.command( name="setgoodbye", help="Sets the goodbye message and channel. Usage: `setgoodbye #channel [message template]`", ) @commands.has_permissions(administrator=True) @commands.guild_only() async def set_goodbye( self, ctx: commands.Context, channel: discord.TextChannel, *, message_template: str = "{username} has left the server.", ): """Sets the channel and template for goodbye messages.""" guild_id = ctx.guild.id key_channel = "goodbye_channel_id" key_message = "goodbye_message" # Use settings_manager.set_setting success_channel = await settings_manager.set_setting( guild_id, key_channel, str(channel.id) ) success_message = await settings_manager.set_setting( guild_id, key_message, message_template ) if success_channel and success_message: # Both need to succeed await ctx.send( f"Goodbye messages will now be sent to {channel.mention} with the template:\n```\n{message_template}\n```" ) log.info( f"Goodbye settings updated for guild {guild_id} by {ctx.author.name}" ) else: await ctx.send("Failed to save goodbye settings. Check logs.") log.error(f"Failed to save goodbye settings for guild {guild_id}") @commands.command( name="disablegoodbye", help="Disables goodbye messages for this server." ) @commands.has_permissions(administrator=True) @commands.guild_only() async def disable_goodbye(self, ctx: commands.Context): """Disables goodbye messages by removing the channel setting.""" guild_id = ctx.guild.id key_channel = "goodbye_channel_id" key_message = "goodbye_message" # Use set_setting with None to delete the settings success_channel = await settings_manager.set_setting( guild_id, key_channel, None ) success_message = await settings_manager.set_setting( guild_id, key_message, None ) if success_channel and success_message: # Both need to succeed await ctx.send("Goodbye messages have been disabled.") log.info( f"Goodbye messages disabled for guild {guild_id} by {ctx.author.name}" ) else: await ctx.send("Failed to disable goodbye messages. Check logs.") log.error(f"Failed to disable goodbye settings for guild {guild_id}") # Error Handling for this Cog @set_welcome.error @disable_welcome.error @set_goodbye.error @disable_goodbye.error async def on_command_error(self, ctx: commands.Context, error): if isinstance(error, commands.MissingPermissions): await ctx.send("You need Administrator permissions to use this command.") elif isinstance(error, commands.BadArgument): await ctx.send( f"Invalid argument provided. Check the command help: `{ctx.prefix}help {ctx.command.name}`" ) elif isinstance(error, commands.MissingRequiredArgument): await ctx.send( f"Missing required argument. Check the command help: `{ctx.prefix}help {ctx.command.name}`" ) elif isinstance(error, commands.NoPrivateMessage): await ctx.send("This command cannot be used in private messages.") else: log.error( f"Unhandled error in WelcomeCog command '{ctx.command.name}': {error}" ) await ctx.send("An unexpected error occurred. Please check the logs.") async def setup(bot: commands.Bot): # Ensure bot has pools initialized before adding the cog print("WelcomeCog setup function called!") if ( not hasattr(bot, "pg_pool") or not hasattr(bot, "redis") or bot.pg_pool is None or bot.redis is None ): log.warning( "Bot pools not initialized before loading WelcomeCog. Cog will not load." ) print("WelcomeCog: Bot pools not initialized. Cannot load cog.") return # Prevent loading if pools are missing welcome_cog = WelcomeCog(bot) await bot.add_cog(welcome_cog) print( f"WelcomeCog loaded! Event listeners registered: on_member_join, on_member_remove" ) log.info("WelcomeCog loaded.")