Changes the `group_customizations` data structure to store a dictionary containing `name` and `description` for each group, rather than just the custom name. This aligns with how command customizations are stored and prepares for future additions like custom group descriptions. Updates the dashboard UI and settings cog to correctly display the new group customization format, while maintaining backward compatibility for existing data.
585 lines
30 KiB
Python
585 lines
30 KiB
Python
import discord
|
|
from discord.ext import commands
|
|
import logging
|
|
import settings_manager # Assuming settings_manager is accessible
|
|
import command_customization # Import command customization utilities
|
|
from typing import Optional
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
# Get CORE_COGS from bot instance
|
|
def get_core_cogs(bot):
|
|
return getattr(bot, 'core_cogs', {'SettingsCog', 'HelpCog'})
|
|
|
|
class SettingsCog(commands.Cog, name="Settings"):
|
|
"""Commands for server administrators to configure the bot."""
|
|
|
|
def __init__(self, bot: commands.Bot):
|
|
self.bot = bot
|
|
|
|
# --- Prefix Management ---
|
|
@commands.command(name='setprefix', help="Sets the command prefix for this server. Usage: `setprefix <new_prefix>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def set_prefix(self, ctx: commands.Context, new_prefix: str):
|
|
"""Sets the command prefix for the current guild."""
|
|
if not new_prefix:
|
|
await ctx.send("Prefix cannot be empty.")
|
|
return
|
|
if len(new_prefix) > 10: # Arbitrary limit
|
|
await ctx.send("Prefix cannot be longer than 10 characters.")
|
|
return
|
|
if new_prefix.isspace():
|
|
await ctx.send("Prefix cannot be just whitespace.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_guild_prefix(guild_id, new_prefix)
|
|
|
|
if success:
|
|
await ctx.send(f"Command prefix for this server has been set to: `{new_prefix}`")
|
|
log.info(f"Prefix updated for guild {guild_id} to '{new_prefix}' by {ctx.author.name}")
|
|
else:
|
|
await ctx.send("Failed to set the prefix. Please check the logs.")
|
|
log.error(f"Failed to save prefix for guild {guild_id}")
|
|
|
|
@commands.command(name='showprefix', help="Shows the current command prefix for this server.")
|
|
@commands.guild_only()
|
|
async def show_prefix(self, ctx: commands.Context):
|
|
"""Shows the current command prefix."""
|
|
# We need the bot's default prefix as a fallback
|
|
# This might need access to the bot instance's initial config or a constant
|
|
default_prefix = self.bot.command_prefix # This might not work if command_prefix is the callable
|
|
# Use the constant defined in main.py if possible, or keep a local fallback
|
|
default_prefix_fallback = "!" # TODO: Get default prefix reliably if needed elsewhere
|
|
|
|
guild_id = ctx.guild.id
|
|
current_prefix = await settings_manager.get_guild_prefix(guild_id, default_prefix_fallback)
|
|
await ctx.send(f"The current command prefix for this server is: `{current_prefix}`")
|
|
|
|
|
|
# --- Cog Management ---
|
|
@commands.command(name='enablecog', help="Enables a specific module (cog) for this server. Usage: `enablecog <CogName>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def enable_cog(self, ctx: commands.Context, cog_name: str):
|
|
"""Enables a cog for the current guild."""
|
|
# Validate if cog exists
|
|
if cog_name not in self.bot.cogs:
|
|
await ctx.send(f"Error: Cog `{cog_name}` not found.")
|
|
return
|
|
|
|
core_cogs = get_core_cogs(self.bot)
|
|
if cog_name in core_cogs:
|
|
await ctx.send(f"Error: Core cog `{cog_name}` cannot be disabled/enabled.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_cog_enabled(guild_id, cog_name, enabled=True)
|
|
|
|
if success:
|
|
await ctx.send(f"Module `{cog_name}` has been enabled for this server.")
|
|
log.info(f"Cog '{cog_name}' enabled for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to enable module `{cog_name}`. Check logs.")
|
|
log.error(f"Failed to enable cog '{cog_name}' for guild {guild_id}")
|
|
|
|
@commands.command(name='disablecog', help="Disables a specific module (cog) for this server. Usage: `disablecog <CogName>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def disable_cog(self, ctx: commands.Context, cog_name: str):
|
|
"""Disables a cog for the current guild."""
|
|
if cog_name not in self.bot.cogs:
|
|
await ctx.send(f"Error: Cog `{cog_name}` not found.")
|
|
return
|
|
|
|
core_cogs = get_core_cogs(self.bot)
|
|
if cog_name in core_cogs:
|
|
await ctx.send(f"Error: Core cog `{cog_name}` cannot be disabled.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_cog_enabled(guild_id, cog_name, enabled=False)
|
|
|
|
if success:
|
|
await ctx.send(f"Module `{cog_name}` has been disabled for this server.")
|
|
log.info(f"Cog '{cog_name}' disabled for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to disable module `{cog_name}`. Check logs.")
|
|
log.error(f"Failed to disable cog '{cog_name}' for guild {guild_id}")
|
|
|
|
@commands.command(name='listcogs', help="Lists all available modules (cogs) and their status for this server.")
|
|
@commands.guild_only()
|
|
async def list_cogs(self, ctx: commands.Context):
|
|
"""Lists available cogs and their enabled/disabled status."""
|
|
guild_id = ctx.guild.id
|
|
# Note: Default enabled status might need adjustment based on desired behavior
|
|
# If a cog has no entry in the DB, should it be considered enabled or disabled by default?
|
|
# Let's assume default_enabled=True for now.
|
|
default_behavior = True
|
|
|
|
embed = discord.Embed(title="Available Modules (Cogs)", color=discord.Color.blue())
|
|
lines = []
|
|
# Get core cogs from bot instance
|
|
core_cogs_list = get_core_cogs(self.bot)
|
|
|
|
for cog_name in sorted(self.bot.cogs.keys()):
|
|
is_enabled = await settings_manager.is_cog_enabled(guild_id, cog_name, default_enabled=default_behavior)
|
|
status = "✅ Enabled" if is_enabled else "❌ Disabled"
|
|
if cog_name in core_cogs_list:
|
|
status += " (Core)"
|
|
lines.append(f"`{cog_name}`: {status}")
|
|
|
|
embed.description = "\n".join(lines) if lines else "No cogs found."
|
|
await ctx.send(embed=embed)
|
|
|
|
|
|
# --- Command Permission Management (Basic Role-Based) ---
|
|
@commands.command(name='allowcmd', help="Allows a role to use a specific command. Usage: `allowcmd <command_name> <@Role>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def allow_command(self, ctx: commands.Context, command_name: str, role: discord.Role):
|
|
"""Allows a specific role to use a command."""
|
|
command = self.bot.get_command(command_name)
|
|
if not command:
|
|
await ctx.send(f"Error: Command `{command_name}` not found.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
role_id = role.id
|
|
success = await settings_manager.add_command_permission(guild_id, command_name, role_id)
|
|
|
|
if success:
|
|
await ctx.send(f"Role `{role.name}` is now allowed to use command `{command_name}`.")
|
|
log.info(f"Permission added for command '{command_name}', role '{role.name}' ({role_id}) in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to add permission for command `{command_name}`. Check logs.")
|
|
log.error(f"Failed to add permission for command '{command_name}', role {role_id} in guild {guild_id}")
|
|
|
|
|
|
@commands.command(name='disallowcmd', help="Disallows a role from using a specific command. Usage: `disallowcmd <command_name> <@Role>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def disallow_command(self, ctx: commands.Context, command_name: str, role: discord.Role):
|
|
"""Disallows a specific role from using a command."""
|
|
command = self.bot.get_command(command_name)
|
|
if not command:
|
|
await ctx.send(f"Error: Command `{command_name}` not found.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
role_id = role.id
|
|
success = await settings_manager.remove_command_permission(guild_id, command_name, role_id)
|
|
|
|
if success:
|
|
await ctx.send(f"Role `{role.name}` is no longer allowed to use command `{command_name}`.")
|
|
log.info(f"Permission removed for command '{command_name}', role '{role.name}' ({role_id}) in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to remove permission for command `{command_name}`. Check logs.")
|
|
log.error(f"Failed to remove permission for command '{command_name}', role {role_id} in guild {guild_id}")
|
|
|
|
# --- Command Customization Management ---
|
|
@commands.command(name='setcmdname', help="Sets a custom name for a slash command in this server. Usage: `setcmdname <original_name> <custom_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def set_command_name(self, ctx: commands.Context, original_name: str, custom_name: str):
|
|
"""Sets a custom name for a slash command in the current guild."""
|
|
# Validate the original command exists
|
|
command_found = False
|
|
for cmd in self.bot.tree.get_commands():
|
|
if cmd.name == original_name:
|
|
command_found = True
|
|
break
|
|
|
|
if not command_found:
|
|
await ctx.send(f"Error: Slash command `{original_name}` not found.")
|
|
return
|
|
|
|
# Validate custom name format (Discord has restrictions on command names)
|
|
if not custom_name.islower() or not custom_name.replace('_', '').isalnum():
|
|
await ctx.send("Error: Custom command names must be lowercase and contain only letters, numbers, and underscores.")
|
|
return
|
|
|
|
if len(custom_name) < 1 or len(custom_name) > 32:
|
|
await ctx.send("Error: Custom command names must be between 1 and 32 characters long.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_custom_command_name(guild_id, original_name, custom_name)
|
|
|
|
if success:
|
|
await ctx.send(f"Command `{original_name}` will now appear as `{custom_name}` in this server.\n"
|
|
f"Note: You'll need to restart the bot or use `/sync` for changes to take effect.")
|
|
log.info(f"Custom command name set for '{original_name}' to '{custom_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to set custom command name. Check logs.")
|
|
log.error(f"Failed to set custom command name for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='resetcmdname', help="Resets a slash command to its original name. Usage: `resetcmdname <original_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def reset_command_name(self, ctx: commands.Context, original_name: str):
|
|
"""Resets a slash command to its original name in the current guild."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_custom_command_name(guild_id, original_name, None)
|
|
|
|
if success:
|
|
await ctx.send(f"Command `{original_name}` has been reset to its original name in this server.\n"
|
|
f"Note: You'll need to restart the bot or use `/sync` for changes to take effect.")
|
|
log.info(f"Custom command name reset for '{original_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to reset command name. Check logs.")
|
|
log.error(f"Failed to reset command name for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='setgroupname', help="Sets a custom name for a command group. Usage: `setgroupname <original_name> <custom_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def set_group_name(self, ctx: commands.Context, original_name: str, custom_name: str):
|
|
"""Sets a custom name for a command group in the current guild."""
|
|
# Validate the original group exists
|
|
group_found = False
|
|
for cmd in self.bot.tree.get_commands():
|
|
# Check if this command is itself a group with the specified name
|
|
if hasattr(cmd, 'name') and cmd.name == original_name and hasattr(cmd, 'commands'):
|
|
group_found = True
|
|
break
|
|
# Also check if this is a subcommand of a group with the specified name (for nested groups)
|
|
elif hasattr(cmd, 'parent') and cmd.parent and cmd.parent.name == original_name:
|
|
group_found = True
|
|
break
|
|
|
|
if not group_found:
|
|
await ctx.send(f"Error: Command group `{original_name}` not found.")
|
|
return
|
|
|
|
# Validate custom name format (Discord has restrictions on command names)
|
|
if not custom_name.islower() or not custom_name.replace('_', '').isalnum():
|
|
await ctx.send("Error: Custom group names must be lowercase and contain only letters, numbers, and underscores.")
|
|
return
|
|
|
|
if len(custom_name) < 1 or len(custom_name) > 32:
|
|
await ctx.send("Error: Custom group names must be between 1 and 32 characters long.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_custom_group_name(guild_id, original_name, custom_name)
|
|
|
|
if success:
|
|
await ctx.send(f"Command group `{original_name}` will now appear as `{custom_name}` in this server.\n"
|
|
f"Note: You'll need to restart the bot or use `/sync` for changes to take effect.")
|
|
log.info(f"Custom group name set for '{original_name}' to '{custom_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to set custom group name. Check logs.")
|
|
log.error(f"Failed to set custom group name for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='resetgroupname', help="Resets a command group to its original name. Usage: `resetgroupname <original_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def reset_group_name(self, ctx: commands.Context, original_name: str):
|
|
"""Resets a command group to its original name in the current guild."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_custom_group_name(guild_id, original_name, None)
|
|
|
|
if success:
|
|
await ctx.send(f"Command group `{original_name}` has been reset to its original name in this server.\n"
|
|
f"Note: You'll need to restart the bot or use `/sync` for changes to take effect.")
|
|
log.info(f"Custom group name reset for '{original_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to reset group name. Check logs.")
|
|
log.error(f"Failed to reset group name for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='addcmdalias', help="Adds an alias for a command. Usage: `addcmdalias <original_name> <alias_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def add_command_alias(self, ctx: commands.Context, original_name: str, alias_name: str):
|
|
"""Adds an alias for a command in the current guild."""
|
|
# Validate the original command exists
|
|
command = self.bot.get_command(original_name)
|
|
if not command:
|
|
await ctx.send(f"Error: Command `{original_name}` not found.")
|
|
return
|
|
|
|
# Validate alias format
|
|
if not alias_name.islower() or not alias_name.replace('_', '').isalnum():
|
|
await ctx.send("Error: Aliases must be lowercase and contain only letters, numbers, and underscores.")
|
|
return
|
|
|
|
if len(alias_name) < 1 or len(alias_name) > 32:
|
|
await ctx.send("Error: Aliases must be between 1 and 32 characters long.")
|
|
return
|
|
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.add_command_alias(guild_id, original_name, alias_name)
|
|
|
|
if success:
|
|
await ctx.send(f"Added alias `{alias_name}` for command `{original_name}` in this server.")
|
|
log.info(f"Command alias added for '{original_name}': '{alias_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to add command alias. Check logs.")
|
|
log.error(f"Failed to add command alias for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='removecmdalias', help="Removes an alias for a command. Usage: `removecmdalias <original_name> <alias_name>`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def remove_command_alias(self, ctx: commands.Context, original_name: str, alias_name: str):
|
|
"""Removes an alias for a command in the current guild."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.remove_command_alias(guild_id, original_name, alias_name)
|
|
|
|
if success:
|
|
await ctx.send(f"Removed alias `{alias_name}` for command `{original_name}` in this server.")
|
|
log.info(f"Command alias removed for '{original_name}': '{alias_name}' in guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send(f"Failed to remove command alias. Check logs.")
|
|
log.error(f"Failed to remove command alias for '{original_name}' in guild {guild_id}")
|
|
|
|
@commands.command(name='listcmdaliases', help="Lists all command aliases for this server.")
|
|
@commands.guild_only()
|
|
async def list_command_aliases(self, ctx: commands.Context):
|
|
"""Lists all command aliases for the current guild."""
|
|
guild_id = ctx.guild.id
|
|
aliases_dict = await settings_manager.get_all_command_aliases(guild_id)
|
|
|
|
if aliases_dict is None:
|
|
await ctx.send("Failed to retrieve command aliases. Check logs.")
|
|
return
|
|
|
|
if not aliases_dict:
|
|
await ctx.send("No command aliases are set for this server.")
|
|
return
|
|
|
|
embed = discord.Embed(title="Command Aliases", color=discord.Color.blue())
|
|
for cmd_name, aliases in aliases_dict.items():
|
|
embed.add_field(name=f"Command: {cmd_name}", value=", ".join([f"`{alias}`" for alias in aliases]), inline=False)
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
@commands.command(name='listcustomcmds', help="Lists all custom command names for this server.")
|
|
@commands.guild_only()
|
|
async def list_custom_commands(self, ctx: commands.Context):
|
|
"""Lists all custom command names for the current guild."""
|
|
guild_id = ctx.guild.id
|
|
cmd_customizations = await settings_manager.get_all_command_customizations(guild_id)
|
|
group_customizations = await settings_manager.get_all_group_customizations(guild_id)
|
|
|
|
if cmd_customizations is None or group_customizations is None:
|
|
await ctx.send("Failed to retrieve command customizations. Check logs.")
|
|
return
|
|
|
|
if not cmd_customizations and not group_customizations:
|
|
await ctx.send("No command customizations are set for this server.")
|
|
return
|
|
|
|
embed = discord.Embed(title="Command Customizations", color=discord.Color.blue())
|
|
|
|
if cmd_customizations:
|
|
cmd_text = "\n".join([f"`{orig}` → `{custom['name']}`" for orig, custom in cmd_customizations.items()])
|
|
embed.add_field(name="Custom Command Names", value=cmd_text, inline=False)
|
|
|
|
if group_customizations:
|
|
group_text = "\n".join([f"`{orig}` → `{custom['name']}`" for orig, custom in group_customizations.items()])
|
|
embed.add_field(name="Custom Group Names", value=group_text, inline=False)
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
@commands.command(name='listgroups', help="Lists all available command groups for debugging.")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def list_groups(self, ctx: commands.Context):
|
|
"""Lists all available command groups for debugging purposes."""
|
|
groups = []
|
|
commands_list = []
|
|
|
|
for cmd in self.bot.tree.get_commands():
|
|
# Check if this is a group
|
|
if hasattr(cmd, 'commands') and hasattr(cmd, 'name'):
|
|
groups.append(f"`{cmd.name}` - {getattr(cmd, 'description', 'No description')}")
|
|
# Check if this is a regular command
|
|
elif hasattr(cmd, 'name'):
|
|
commands_list.append(f"`{cmd.name}`")
|
|
|
|
embed = discord.Embed(title="Available Command Groups & Commands", color=discord.Color.green())
|
|
|
|
if groups:
|
|
groups_text = "\n".join(groups[:10]) # Limit to first 10 to avoid message length issues
|
|
if len(groups) > 10:
|
|
groups_text += f"\n... and {len(groups) - 10} more groups"
|
|
embed.add_field(name="Command Groups", value=groups_text, inline=False)
|
|
else:
|
|
embed.add_field(name="Command Groups", value="No groups found", inline=False)
|
|
|
|
if commands_list:
|
|
commands_text = ", ".join(commands_list[:20]) # Limit to first 20
|
|
if len(commands_list) > 20:
|
|
commands_text += f", ... and {len(commands_list) - 20} more commands"
|
|
embed.add_field(name="Individual Commands", value=commands_text, inline=False)
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
@commands.command(name='synccmds', help="Syncs slash commands with Discord to apply customizations.")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def sync_commands(self, ctx: commands.Context):
|
|
"""Syncs slash commands with Discord to apply customizations."""
|
|
try:
|
|
guild = ctx.guild
|
|
await ctx.send("Syncing commands with Discord... This may take a moment.")
|
|
|
|
# Use the command_customization module to sync commands with customizations
|
|
try:
|
|
synced = await command_customization.register_guild_commands(self.bot, guild)
|
|
|
|
await ctx.send(f"Successfully synced {len(synced)} commands for this server with customizations.")
|
|
log.info(f"Commands synced with customizations for guild {guild.id} by {ctx.author.name}")
|
|
except Exception as e:
|
|
log.error(f"Failed to sync commands with customizations: {e}")
|
|
# Don't fall back to regular sync to avoid command duplication
|
|
await ctx.send(f"Failed to apply customizations. Please check the logs and try again.")
|
|
log.info(f"Command sync with customizations failed for guild {guild.id}")
|
|
except Exception as e:
|
|
await ctx.send(f"Failed to sync commands: {str(e)}")
|
|
log.error(f"Failed to sync commands for guild {ctx.guild.id}: {e}")
|
|
|
|
# TODO: Add command to list permissions?
|
|
|
|
|
|
# --- Moderation Logging Settings ---
|
|
@commands.group(name='modlogconfig', help="Configure the integrated moderation logging.", invoke_without_command=True)
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def modlog_config_group(self, ctx: commands.Context):
|
|
"""Base command for moderation log configuration. Shows current settings."""
|
|
guild_id = ctx.guild.id
|
|
enabled = await settings_manager.is_mod_log_enabled(guild_id)
|
|
channel_id = await settings_manager.get_mod_log_channel_id(guild_id)
|
|
channel = ctx.guild.get_channel(channel_id) if channel_id else None
|
|
|
|
status = "✅ Enabled" if enabled else "❌ Disabled"
|
|
channel_status = channel.mention if channel else ("Not Set" if channel_id else "Not Set")
|
|
|
|
embed = discord.Embed(title="Moderation Logging Configuration", color=discord.Color.teal())
|
|
embed.add_field(name="Status", value=status, inline=False)
|
|
embed.add_field(name="Log Channel", value=channel_status, inline=False)
|
|
await ctx.send(embed=embed)
|
|
|
|
@modlog_config_group.command(name='enable', help="Enables the integrated moderation logging.")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def modlog_enable(self, ctx: commands.Context):
|
|
"""Enables the integrated moderation logging for this server."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_mod_log_enabled(guild_id, True)
|
|
if success:
|
|
await ctx.send("✅ Integrated moderation logging has been enabled.")
|
|
log.info(f"Moderation logging enabled for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send("❌ Failed to enable moderation logging. Please check logs.")
|
|
log.error(f"Failed to enable moderation logging for guild {guild_id}")
|
|
|
|
@modlog_config_group.command(name='disable', help="Disables the integrated moderation logging.")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def modlog_disable(self, ctx: commands.Context):
|
|
"""Disables the integrated moderation logging for this server."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_mod_log_enabled(guild_id, False)
|
|
if success:
|
|
await ctx.send("❌ Integrated moderation logging has been disabled.")
|
|
log.info(f"Moderation logging disabled for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send("❌ Failed to disable moderation logging. Please check logs.")
|
|
log.error(f"Failed to disable moderation logging for guild {guild_id}")
|
|
|
|
@modlog_config_group.command(name='setchannel', help="Sets the channel where moderation logs will be sent. Usage: `setchannel #channel`")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def modlog_setchannel(self, ctx: commands.Context, channel: discord.TextChannel):
|
|
"""Sets the channel for integrated moderation logs."""
|
|
guild_id = ctx.guild.id
|
|
# Basic check for bot permissions in the target channel
|
|
if not channel.permissions_for(ctx.guild.me).send_messages or not channel.permissions_for(ctx.guild.me).embed_links:
|
|
await ctx.send(f"❌ I need 'Send Messages' and 'Embed Links' permissions in {channel.mention} to send logs there.")
|
|
return
|
|
|
|
success = await settings_manager.set_mod_log_channel_id(guild_id, channel.id)
|
|
if success:
|
|
await ctx.send(f"✅ Moderation logs will now be sent to {channel.mention}.")
|
|
log.info(f"Moderation log channel set to {channel.id} for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send("❌ Failed to set the moderation log channel. Please check logs.")
|
|
log.error(f"Failed to set moderation log channel for guild {guild_id}")
|
|
|
|
@modlog_config_group.command(name='unsetchannel', help="Unsets the moderation log channel (disables sending logs).")
|
|
@commands.has_permissions(administrator=True)
|
|
@commands.guild_only()
|
|
async def modlog_unsetchannel(self, ctx: commands.Context):
|
|
"""Unsets the channel for integrated moderation logs."""
|
|
guild_id = ctx.guild.id
|
|
success = await settings_manager.set_mod_log_channel_id(guild_id, None)
|
|
if success:
|
|
await ctx.send("✅ Moderation log channel has been unset. Logs will not be sent to a channel.")
|
|
log.info(f"Moderation log channel unset for guild {guild_id} by {ctx.author.name}")
|
|
else:
|
|
await ctx.send("❌ Failed to unset the moderation log channel. Please check logs.")
|
|
log.error(f"Failed to unset moderation log channel for guild {guild_id}")
|
|
|
|
|
|
# --- Error Handling for this Cog ---
|
|
@set_prefix.error
|
|
@enable_cog.error
|
|
@disable_cog.error
|
|
@allow_command.error
|
|
@disallow_command.error
|
|
@set_command_name.error
|
|
@reset_command_name.error
|
|
@set_group_name.error
|
|
@reset_group_name.error
|
|
@add_command_alias.error
|
|
@remove_command_alias.error
|
|
@list_groups.error
|
|
@sync_commands.error
|
|
@modlog_config_group.error # Add error handler for the group
|
|
@modlog_enable.error
|
|
@modlog_disable.error
|
|
@modlog_setchannel.error
|
|
@modlog_unsetchannel.error
|
|
async def on_command_error(self, ctx: commands.Context, error):
|
|
# Check if the error originates from the modlogconfig group or its subcommands
|
|
if ctx.command and (ctx.command.name == 'modlogconfig' or (ctx.command.parent and ctx.command.parent.name == 'modlogconfig')):
|
|
if isinstance(error, commands.MissingPermissions):
|
|
await ctx.send("You need Administrator permissions to configure moderation logging.")
|
|
return # Handled
|
|
elif isinstance(error, commands.BadArgument):
|
|
await ctx.send(f"Invalid argument. Usage: `{ctx.prefix}help {ctx.command.qualified_name}`")
|
|
return # Handled
|
|
elif isinstance(error, commands.MissingRequiredArgument):
|
|
await ctx.send(f"Missing argument. Usage: `{ctx.prefix}help {ctx.command.qualified_name}`")
|
|
return # Handled
|
|
elif isinstance(error, commands.NoPrivateMessage):
|
|
await ctx.send("This command can only be used in a server.")
|
|
return # Handled
|
|
# Let other errors fall through to the generic handler below
|
|
|
|
# Generic handlers for other commands in this cog
|
|
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 SettingsCog command '{ctx.command.name}': {error}")
|
|
await ctx.send("An unexpected error occurred. Please check the logs.")
|
|
|
|
|
|
async def setup(bot: commands.Bot):
|
|
# Ensure pools are initialized before adding the cog
|
|
if getattr(bot, "pg_pool", None) is None or getattr(bot, "redis", None) is None:
|
|
log.warning("Bot pools not initialized before loading SettingsCog. Cog will not load.")
|
|
return # Prevent loading if pools are missing
|
|
|
|
await bot.add_cog(SettingsCog(bot))
|
|
log.info("SettingsCog loaded.")
|