This commit is contained in:
2026-01-25 17:21:41 +01:00
parent 9c59413cfa
commit d4cc23f7cf

View File

@@ -49,57 +49,137 @@ class GuardDenHelpCommand(commands.HelpCommand):
"""Get description for a cog.""" """Get description for a cog."""
return self.CATEGORY_DESCRIPTIONS.get(cog_name, "Commands") return self.CATEGORY_DESCRIPTIONS.get(cog_name, "Commands")
def _get_permission_info(self, command: commands.Command) -> tuple[str, discord.Color]:
"""Get permission requirement text and color for a command."""
# Check cog-level restrictions
if command.cog:
cog_name = command.cog.qualified_name
if cog_name == "Admin":
return "🔒 Admin Only", discord.Color.red()
elif cog_name == "Moderation":
return "🛡️ Moderator/Owner", discord.Color.orange()
elif cog_name == "WordlistSync":
return "🔒 Admin Only", discord.Color.red()
# Check command-level checks
if hasattr(command.callback, "__commands_checks__"):
checks = command.callback.__commands_checks__
for check in checks:
check_name = getattr(check, "__name__", "")
if "is_owner" in check_name:
return "👑 Bot Owner Only", discord.Color.dark_red()
elif "has_permissions" in check_name or "administrator" in check_name:
return "🔒 Admin Only", discord.Color.red()
return "👥 Everyone", discord.Color.green()
async def send_bot_help(self, mapping: dict) -> None: async def send_bot_help(self, mapping: dict) -> None:
"""Send the main help menu showing all categories.""" """Send the main help menu showing all commands with detailed information."""
embed = discord.Embed( embeds = []
title="GuardDen Help Menu", prefix = self.context.clean_prefix
description="A comprehensive Discord moderation bot",
# Create overview embed
overview = discord.Embed(
title="📚 GuardDen Help - All Commands",
description=f"A comprehensive Discord moderation bot\n\n"
f"**Legend:**\n"
f"👥 Everyone can use | 🛡️ Moderators/Owners | 🔒 Admins | 👑 Bot Owner",
color=discord.Color.blue(), color=discord.Color.blue(),
) )
overview.set_footer(text=f"Prefix: {prefix} (customizable per server)")
embeds.append(overview)
# Filter and display categories # Collect all commands organized by category
for cog, cog_commands in mapping.items(): for cog, cog_commands in mapping.items():
if cog is None: if cog is None:
continue continue
# Filter commands the user can actually run # Get all commands (don't filter by permissions for full overview)
filtered = await self.filter_commands(cog_commands, sort=True) all_commands = sorted(cog_commands, key=lambda c: c.qualified_name)
if not filtered: if not all_commands:
continue continue
cog_name = cog.qualified_name cog_name = cog.qualified_name
display_name = self.get_cog_display_name(cog_name) display_name = self.get_cog_display_name(cog_name)
description = self.get_cog_description(cog_name)
embed.add_field( # Create embed for this category
name=display_name, embed = discord.Embed(
value=description, title=display_name,
inline=False, description=self.get_cog_description(cog_name),
color=discord.Color.gold() if "Admin" in display_name else discord.Color.blue(),
) )
# Add usage instructions # Add each command with full details
prefix = self.context.clean_prefix for command in all_commands:
embed.add_field( perm_text, _ = self._get_permission_info(command)
name="Usage",
value=f"Use `{prefix}help <category>` for category commands\n"
f"Use `{prefix}help <command>` for detailed help",
inline=False,
)
embed.set_footer(text=f"Prefix: {prefix} (customizable per server)") # Build command signature with all parameters
signature_parts = [command.name]
if command.signature:
signature_parts.append(command.signature)
full_signature = f"{prefix}{' '.join(signature_parts)}"
# Build description
desc_parts = []
# Add help text
if command.help:
desc_parts.append(command.help.split("\n")[0])
else:
desc_parts.append("No description available")
# Add aliases if present
if command.aliases:
desc_parts.append(f"*Aliases: {', '.join(command.aliases)}*")
# Add permission requirement
desc_parts.append(f"**Permission:** {perm_text}")
# Add parameter details if present
if command.clean_params:
param_details = []
for param_name, param in command.clean_params.items():
if param.default is param.empty:
param_details.append(f"`{param_name}` (required)")
else:
default_val = param.default if param.default is not None else "None"
param_details.append(f"`{param_name}` (default: {default_val})")
if param_details:
desc_parts.append(f"**Options:** {', '.join(param_details)}")
# Handle subcommands for groups
if isinstance(command, commands.Group):
subcommands = list(command.commands)
if subcommands:
subcommand_names = ", ".join(
f"`{cmd.name}`" for cmd in sorted(subcommands, key=lambda c: c.name)
)
desc_parts.append(f"**Subcommands:** {subcommand_names}")
description = "\n".join(desc_parts)
embed.add_field(
name=f"`{full_signature}`",
value=description,
inline=False,
)
embeds.append(embed)
# Send all embeds
channel = self.get_destination() channel = self.get_destination()
await channel.send(embed=embed) for embed in embeds:
await channel.send(embed=embed)
async def send_cog_help(self, cog: commands.Cog) -> None: async def send_cog_help(self, cog: commands.Cog) -> None:
"""Send help for a specific category/cog.""" """Send help for a specific category/cog."""
# Filter commands the user can run # Get all commands (show all, not just what user can run)
filtered = await self.filter_commands(cog.get_commands(), sort=True) all_commands = sorted(cog.get_commands(), key=lambda c: c.qualified_name)
if not filtered: if not all_commands:
await self.get_destination().send( await self.get_destination().send(f"No commands available in this category.")
f"No commands available in this category or you lack permissions to use them."
)
return return
cog_name = cog.qualified_name cog_name = cog.qualified_name
@@ -107,12 +187,16 @@ class GuardDenHelpCommand(commands.HelpCommand):
embed = discord.Embed( embed = discord.Embed(
title=f"{display_name} Commands", title=f"{display_name} Commands",
description=cog.description or "Commands in this category", description=f"{cog.description or 'Commands in this category'}\n\n"
f"**Legend:** 👥 Everyone | 🛡️ Moderators/Owners | 🔒 Admins | 👑 Bot Owner",
color=discord.Color.gold() if "Admin" in display_name else discord.Color.blue(), color=discord.Color.gold() if "Admin" in display_name else discord.Color.blue(),
) )
# Group commands by type (regular vs groups) # Show each command with full details
for command in filtered: for command in all_commands:
# Get permission info
perm_text, _ = self._get_permission_info(command)
# Get command signature # Get command signature
signature = self.get_command_signature(command) signature = self.get_command_signature(command)
@@ -120,30 +204,34 @@ class GuardDenHelpCommand(commands.HelpCommand):
desc_parts = [] desc_parts = []
if command.help: if command.help:
desc_parts.append(command.help.split("\n")[0]) # First line only desc_parts.append(command.help.split("\n")[0]) # First line only
else:
desc_parts.append("No description available")
if command.aliases: if command.aliases:
desc_parts.append(f"*Aliases: {', '.join(command.aliases)}*") desc_parts.append(f"*Aliases: {', '.join(command.aliases)}*")
description = "\n".join(desc_parts) if desc_parts else "No description available" # Add permission info
desc_parts.append(f"**Permission:** {perm_text}")
# Add parameter info
if command.clean_params:
param_count = len(command.clean_params)
required_count = sum(
1 for p in command.clean_params.values() if p.default is p.empty
)
desc_parts.append(
f"**Parameters:** {required_count} required, {param_count - required_count} optional"
)
description = "\n".join(desc_parts)
embed.add_field( embed.add_field(
name=signature, name=f"`{signature}`",
value=description, value=description,
inline=False, inline=False,
) )
# Add permission requirements if applicable embed.set_footer(text=f"Use {self.context.clean_prefix}help <command> for detailed info")
if hasattr(cog, "cog_check"):
# Try to determine permissions
footer_parts = []
# Check common permission patterns
if "Admin" in display_name or "Config" in display_name:
footer_parts.append("Requires: Administrator permission")
elif "Moderation" in display_name:
footer_parts.append("Requires: Kick Members or Ban Members permission")
if footer_parts:
embed.set_footer(text=" | ".join(footer_parts))
channel = self.get_destination() channel = self.get_destination()
await channel.send(embed=embed) await channel.send(embed=embed)
@@ -199,10 +287,12 @@ class GuardDenHelpCommand(commands.HelpCommand):
async def send_command_help(self, command: commands.Command) -> None: async def send_command_help(self, command: commands.Command) -> None:
"""Send help for a specific command.""" """Send help for a specific command."""
perm_text, perm_color = self._get_permission_info(command)
embed = discord.Embed( embed = discord.Embed(
title=f"Command: {command.qualified_name}", title=f"Command: {command.qualified_name}",
description=command.help or "No description available", description=command.help or "No description available",
color=discord.Color.green(), color=perm_color,
) )
# Add usage # Add usage
@@ -213,6 +303,13 @@ class GuardDenHelpCommand(commands.HelpCommand):
inline=False, inline=False,
) )
# Add permission requirement prominently
embed.add_field(
name="Permission Required",
value=perm_text,
inline=False,
)
# Add aliases # Add aliases
if command.aliases: if command.aliases:
embed.add_field( embed.add_field(
@@ -225,12 +322,20 @@ class GuardDenHelpCommand(commands.HelpCommand):
if command.clean_params: if command.clean_params:
params_text = [] params_text = []
for param_name, param in command.clean_params.items(): for param_name, param in command.clean_params.items():
# Get parameter annotation for type hint
param_type = ""
if param.annotation is not param.empty:
type_name = getattr(param.annotation, "__name__", str(param.annotation))
param_type = f" ({type_name})"
# Determine if required or optional # Determine if required or optional
if param.default is param.empty: if param.default is param.empty:
params_text.append(f"`{param_name}` - Required parameter") params_text.append(f"`{param_name}`{param_type} - **Required**")
else: else:
default_val = param.default if param.default is not None else "None" default_val = param.default if param.default is not None else "None"
params_text.append(f"`{param_name}` - Optional (default: {default_val})") params_text.append(
f"`{param_name}`{param_type} - Optional (default: `{default_val}`)"
)
if params_text: if params_text:
embed.add_field( embed.add_field(
@@ -239,26 +344,10 @@ class GuardDenHelpCommand(commands.HelpCommand):
inline=False, inline=False,
) )
# Add permission requirements # Add category info
footer_parts = []
if hasattr(command.callback, "__commands_checks__"):
# Try to extract permission requirements
checks = command.callback.__commands_checks__
for check in checks:
check_name = getattr(check, "__name__", "")
if "has_permissions" in check_name:
footer_parts.append("Requires specific permissions")
elif "is_owner" in check_name:
footer_parts.append("Requires bot owner")
elif "guild_only" in check_name:
footer_parts.append("Guild only (no DMs)")
if command.cog: if command.cog:
cog_name = command.cog.qualified_name cog_name = command.cog.qualified_name
footer_parts.append(f"Category: {self.get_cog_display_name(cog_name)}") embed.set_footer(text=f"Category: {self.get_cog_display_name(cog_name)}")
if footer_parts:
embed.set_footer(text=" | ".join(footer_parts))
channel = self.get_destination() channel = self.get_destination()
await channel.send(embed=embed) await channel.send(embed=embed)