removed help command and fixed rm .git/COMMIT_EDITMSG bug

This commit is contained in:
Lilac-Rose
2026-01-06 17:54:01 +01:00
parent 4f70efb69f
commit ce6bdb0e30
5 changed files with 103 additions and 331 deletions

View File

@@ -9,7 +9,6 @@ EMPTY = "⚪"
RED = "🔴"
YELLOW = "🟡"
class ColumnButton(discord.ui.Button):
def __init__(self, col: int):
super().__init__(

View File

@@ -1,249 +0,0 @@
import discord
from discord.ext import commands
from discord import app_commands
from typing import Optional
import difflib
class Help(commands.Cog):
def __init__(self, bot):
self.bot = bot
def get_command_signature(self, command):
"""Get the usage signature for a command"""
if isinstance(command, commands.HybridCommand):
# For hybrid commands, show both formats
params = []
for name, param in command.clean_params.items():
if param.default == param.empty:
params.append(f"<{name}>")
else:
params.append(f"[{name}]")
param_str = " ".join(params)
return f"!{command.name} {param_str}\n/{command.name} {param_str}"
else:
return f"{command.qualified_name} {command.signature}"
def get_all_commands(self):
"""Get all commands organized by cog"""
cog_commands = {}
for cog_name, cog in self.bot.cogs.items():
commands_list = []
# Get regular commands
for cmd in cog.get_commands():
if not cmd.hidden:
commands_list.append(cmd)
# Get app commands (slash only)
if hasattr(cog, '__cog_app_commands__'):
for cmd in cog.__cog_app_commands__:
if isinstance(cmd, app_commands.Command):
commands_list.append(cmd)
elif isinstance(cmd, app_commands.Group):
# Add group commands
commands_list.append(cmd)
if commands_list:
cog_commands[cog_name] = commands_list
# Get commands not in cogs
no_cog_commands = [cmd for cmd in self.bot.commands if not cmd.cog and not cmd.hidden]
if no_cog_commands:
cog_commands["Other"] = no_cog_commands
return cog_commands
def search_commands(self, query):
"""Search for commands matching the query"""
query = query.lower()
results = []
for cog_name, cog in self.bot.cogs.items():
for cmd in cog.get_commands():
if not cmd.hidden:
# Check command name
if query in cmd.name.lower():
results.append((cmd, cog_name, 100))
# Check command aliases
elif any(query in alias.lower() for alias in cmd.aliases):
results.append((cmd, cog_name, 90))
# Check description
elif cmd.description and query in cmd.description.lower():
results.append((cmd, cog_name, 70))
# Check help text
elif cmd.help and query in cmd.help.lower():
results.append((cmd, cog_name, 60))
# Sort by relevance
results.sort(key=lambda x: x[2], reverse=True)
return results
def create_help_embed(self, title, description=None):
"""Create a base help embed"""
embed = discord.Embed(
title=title,
description=description,
color=discord.Color.blurple()
)
embed.set_footer(text="Use !help <command> or /help <command> for more info on a specific command")
return embed
@commands.hybrid_command(name="help", description="Shows help information for commands")
@app_commands.describe(command="The command to get help for")
async def help_command(self, ctx: commands.Context, *, command: Optional[str] = None):
"""
Get help for bot commands
Usage:
!help - Show all commands
!help <command> - Get detailed help for a specific command
!help <search> - Search for commands
"""
if command:
# Try to find exact command match first
cmd = self.bot.get_command(command.lower())
if cmd:
# Show detailed help for specific command
embed = self.create_help_embed(
title=f"Help: {cmd.name}",
description=cmd.help or cmd.description or "No description available"
)
# Usage
embed.add_field(
name="Usage",
value=f"```\n{self.get_command_signature(cmd)}\n```",
inline=False
)
# Aliases
if cmd.aliases:
embed.add_field(
name="Aliases",
value=", ".join(f"`{alias}`" for alias in cmd.aliases),
inline=False
)
# Category
if cmd.cog:
embed.add_field(name="Category", value=cmd.cog.qualified_name, inline=True)
await ctx.send(embed=embed)
else:
# Search for commands
results = self.search_commands(command)
if not results:
# Suggest similar commands
all_cmd_names = [c.name for c in self.bot.commands]
suggestions = difflib.get_close_matches(command.lower(), all_cmd_names, n=3, cutoff=0.6)
embed = discord.Embed(
title="❌ Command Not Found",
description=f"No command found matching `{command}`",
color=discord.Color.red()
)
if suggestions:
embed.add_field(
name="Did you mean?",
value="\n".join(f"• `{s}`" for s in suggestions),
inline=False
)
await ctx.send(embed=embed)
else:
# Show search results
embed = self.create_help_embed(
title=f"🔍 Search Results for '{command}'",
description=f"Found {len(results)} matching command(s)"
)
for cmd, cog_name, score in results[:10]: # Limit to 10 results
desc = cmd.description or cmd.help or "No description"
if len(desc) > 100:
desc = desc[:97] + "..."
embed.add_field(
name=f"{cmd.name} ({cog_name})",
value=desc,
inline=False
)
if len(results) > 10:
embed.set_footer(text=f"Showing top 10 of {len(results)} results. Use !help <command> for details.")
await ctx.send(embed=embed)
else:
# Show all commands organized by category
cog_commands = self.get_all_commands()
embed = self.create_help_embed(
title="📚 Bot Commands",
description=f"Prefix: `!` | Total Commands: {len(list(self.bot.commands))}\n\n"
"Commands work with both `!` and `/`"
)
for cog_name, cmds in sorted(cog_commands.items()):
if not cmds:
continue
# Group commands by name
cmd_names = []
seen = set()
for cmd in cmds:
if isinstance(cmd, (commands.Command, commands.HybridCommand)):
name = cmd.name
elif isinstance(cmd, (app_commands.Command, app_commands.Group)):
name = cmd.name
else:
continue
if name not in seen:
cmd_names.append(f"`{name}`")
seen.add(name)
if cmd_names:
embed.add_field(
name=f"**{cog_name}**",
value="".join(cmd_names),
inline=False
)
await ctx.send(embed=embed)
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context, error):
"""Show help if command not found"""
if isinstance(error, commands.CommandNotFound):
# Extract the attempted command
cmd_used = ctx.message.content.split()[0][len(ctx.prefix):]
# Suggest similar commands
all_cmd_names = [c.name for c in self.bot.commands]
suggestions = difflib.get_close_matches(cmd_used, all_cmd_names, n=3, cutoff=0.6)
embed = discord.Embed(
title="❓ Unknown Command",
description=f"Command `{cmd_used}` not found.",
color=discord.Color.orange()
)
if suggestions:
embed.add_field(
name="Did you mean?",
value="\n".join(f"• `!{s}` or `/{s}`" for s in suggestions),
inline=False
)
embed.set_footer(text="Use !help to see all commands")
await ctx.send(embed=embed, delete_after=10)
async def setup(bot):
# Remove default help command
bot.remove_command('help')
await bot.add_cog(Help(bot))

View File

@@ -24,6 +24,9 @@ class DenyModal(discord.ui.Modal, title="Reason for denying suggestion"):
async def on_submit(self, interaction: discord.Interaction):
try:
# Defer the response immediately to prevent timeout
await interaction.response.defer(ephemeral=False)
reason_text = self.reason.value or None
db_path = os.path.join(os.path.dirname(__file__), "suggestions.db")
@@ -31,17 +34,39 @@ class DenyModal(discord.ui.Modal, title="Reason for denying suggestion"):
await db.execute("UPDATE suggestions SET status = ?, reason = ? WHERE id = ?", ("Denied", reason_text, self.suggestion_id))
await db.commit()
await interaction.response.send_message(f"❌ Suggestion #{self.suggestion_id} denied.", ephemeral=False)
# Use followup instead of response since we deferred
await interaction.followup.send(f"❌ Suggestion #{self.suggestion_id} denied.", ephemeral=False)
# Disable buttons on the admin message
if self.admin_message_id:
try:
admin_user = await self.bot.fetch_user(ADMIN_ID)
dm = admin_user.dm_channel or await admin_user.create_dm()
orig_msg = await dm.fetch_message(self.admin_message_id)
disabled_view = SuggestionButtons(
self.bot,
suggestion_id=self.suggestion_id,
user_id=self.user_id,
suggestion_text=self.suggestion_text,
channel_id=self.channel_id,
admin_message_id=self.admin_message_id,
disabled=True
)
await orig_msg.edit(view=disabled_view)
except Exception as e:
print(f"Failed to edit admin message: {e}")
# Send DM to user
try:
user = await self.bot.fetch_user(self.user_id)
dm_note = f"❌ Your suggestion (ID: {self.suggestion_id}) — `{self.suggestion_text}` has been **denied**."
if reason_text:
dm_note += f"\n**Reason:** {reason_text}"
await user.send(dm_note)
except:
pass
except Exception as e:
print(f"Failed to DM user: {e}")
# Send message in original channel
channel = self.bot.get_channel(self.channel_id)
if channel:
try:
@@ -49,21 +74,16 @@ class DenyModal(discord.ui.Modal, title="Reason for denying suggestion"):
if reason_text:
msg += f"\n**Reason:** {reason_text}"
await channel.send(msg)
except:
pass
except Exception as e:
print(f"Failed to send message in channel: {e}")
if self.admin_message_id:
try:
admin_user = await self.bot.fetch_user(ADMIN_ID)
dm = admin_user.dm_channel or await admin_user.create_dm()
orig_msg = await dm.fetch_message(self.admin_message_id)
disabled_view = SuggestionButtons(self.bot, suggestion_id=self.suggestion_id, user_id=self.user_id, suggestion_text=self.suggestion_text, channel_id=self.channel_id, admin_message_id=self.admin_message_id, disabled=True)
await orig_msg.edit(view=disabled_view)
except Exception:
pass
except Exception as e:
error_msg = f"❌ Error denying suggestion: {str(e)}\n```{traceback.format_exc()}```"
await interaction.response.send_message(error_msg[:2000], ephemeral=True)
print(error_msg)
try:
await interaction.followup.send(error_msg[:2000], ephemeral=True)
except:
pass
class SuggestionButtons(discord.ui.View):
@@ -76,8 +96,8 @@ class SuggestionButtons(discord.ui.View):
self.channel_id = channel_id
self.admin_message_id = admin_message_id
approve_cid = f"suggest_approve_{suggestion_id}"
deny_cid = f"suggest_deny_{suggestion_id}"
approve_cid = f"suggest_approve_{suggestion_id}" if suggestion_id else "suggest_approve"
deny_cid = f"suggest_deny_{suggestion_id}" if suggestion_id else "suggest_deny"
approve_btn = discord.ui.Button(label="Approve ✅", style=discord.ButtonStyle.success, custom_id=approve_cid, disabled=disabled)
approve_btn.callback = self.approve
@@ -97,43 +117,61 @@ class SuggestionButtons(discord.ui.View):
await interaction.response.send_message("⚠️ This button is no longer active.", ephemeral=True)
return
# Defer immediately to prevent timeout
await interaction.response.defer(ephemeral=False)
db_path = os.path.join(os.path.dirname(__file__), "suggestions.db")
async with aiosqlite.connect(db_path) as db:
await db.execute("UPDATE suggestions SET status = ? WHERE id = ?", ("Approved", self.suggestion_id))
await db.commit()
await interaction.response.send_message(f"✅ Suggestion #{self.suggestion_id} approved.", ephemeral=False)
try:
user = await self.bot.fetch_user(self.user_id)
await user.send(f"✅ Your suggestion (ID: {self.suggestion_id}) — `{self.suggestion_text}` has been **approved!**")
except:
pass
channel = self.bot.get_channel(self.channel_id)
if channel:
await channel.send(f"✅ Suggestion **#{self.suggestion_id}** (`{self.suggestion_text}`) has been **approved!**")
# Use followup since we deferred
await interaction.followup.send(f"✅ Suggestion #{self.suggestion_id} approved.", ephemeral=False)
# Disable buttons on the admin message
if self.admin_message_id:
try:
admin_user = await self.bot.fetch_user(ADMIN_ID)
dm = admin_user.dm_channel or await admin_user.create_dm()
orig_msg = await dm.fetch_message(self.admin_message_id)
disabled_view = SuggestionButtons(self.bot, suggestion_id=self.suggestion_id, user_id=self.user_id, suggestion_text=self.suggestion_text, channel_id=self.channel_id, admin_message_id=self.admin_message_id, disabled=True)
disabled_view = SuggestionButtons(
self.bot,
suggestion_id=self.suggestion_id,
user_id=self.user_id,
suggestion_text=self.suggestion_text,
channel_id=self.channel_id,
admin_message_id=self.admin_message_id,
disabled=True
)
await orig_msg.edit(view=disabled_view)
except Exception:
for item in self.children:
item.disabled = True
try:
await interaction.message.edit(view=self)
except:
pass
except Exception as e:
print(f"Failed to edit admin message: {e}")
# Send DM to user
try:
user = await self.bot.fetch_user(self.user_id)
await user.send(f"✅ Your suggestion (ID: {self.suggestion_id}) — `{self.suggestion_text}` has been **approved!**")
except Exception as e:
print(f"Failed to DM user: {e}")
# Send message in original channel
channel = self.bot.get_channel(self.channel_id)
if channel:
try:
await channel.send(f"✅ Suggestion **#{self.suggestion_id}** (`{self.suggestion_text}`) has been **approved!**")
except Exception as e:
print(f"Failed to send message in channel: {e}")
except Exception as e:
error_msg = f"❌ Error approving suggestion: {str(e)}\n```{traceback.format_exc()}```"
print(error_msg)
try:
await interaction.response.send_message(error_msg[:2000], ephemeral=True)
if not interaction.response.is_done():
await interaction.response.send_message(error_msg[:2000], ephemeral=True)
else:
await interaction.followup.send(error_msg[:2000], ephemeral=True)
except:
await interaction.followup.send(error_msg[:2000], ephemeral=True)
pass
async def deny(self, interaction: discord.Interaction):
try:
@@ -145,14 +183,25 @@ class SuggestionButtons(discord.ui.View):
await interaction.response.send_message("⚠️ This button is no longer active.", ephemeral=True)
return
modal = DenyModal(suggestion_id=self.suggestion_id, user_id=self.user_id, suggestion_text=self.suggestion_text, channel_id=self.channel_id, admin_message_id=self.admin_message_id, bot=self.bot)
modal = DenyModal(
suggestion_id=self.suggestion_id,
user_id=self.user_id,
suggestion_text=self.suggestion_text,
channel_id=self.channel_id,
admin_message_id=self.admin_message_id,
bot=self.bot
)
await interaction.response.send_modal(modal)
except Exception as e:
error_msg = f"❌ Error opening deny modal: {str(e)}\n```{traceback.format_exc()}```"
print(error_msg)
try:
await interaction.response.send_message(error_msg[:2000], ephemeral=True)
if not interaction.response.is_done():
await interaction.response.send_message(error_msg[:2000], ephemeral=True)
else:
await interaction.followup.send(error_msg[:2000], ephemeral=True)
except:
await interaction.followup.send(error_msg[:2000], ephemeral=True)
pass
class PaginationView(discord.ui.View):
@@ -218,16 +267,17 @@ class Suggestion(commands.Cog):
rows = await cursor.fetchall()
for sid, uid, suggestion_text, channel_id, admin_msg_id in rows:
view = SuggestionButtons(
self.bot,
suggestion_id=sid,
user_id=uid,
suggestion_text=suggestion_text,
channel_id=channel_id,
admin_message_id=admin_msg_id
)
self.bot.add_view(view, message_id=admin_msg_id)
print(f"Re-registered view for suggestion #{sid} (message {admin_msg_id})")
if admin_msg_id: # Only register if we have a message ID
view = SuggestionButtons(
self.bot,
suggestion_id=sid,
user_id=uid,
suggestion_text=suggestion_text,
channel_id=channel_id,
admin_message_id=admin_msg_id
)
self.bot.add_view(view, message_id=admin_msg_id)
print(f"Re-registered view for suggestion #{sid} (message {admin_msg_id})")
async def cog_unload(self):
if self.db:
@@ -280,6 +330,7 @@ class Suggestion(commands.Cog):
except Exception as e:
print(f"Failed to send DM to admin: {e}")
traceback.print_exc()
except Exception as e:
error_msg = f"❌ An error occurred: {str(e)}\n```{traceback.format_exc()}```"

View File

@@ -145,25 +145,8 @@ class BackupXP(commands.Cog):
annual_size = os.path.getsize(annual_db) / (1024 * 1024)
total_size = lifetime_size + annual_size
backup_type = "Auto Backup" if is_auto else "Manual Backup"
msg = (
f"✅ **{backup_type}** - Databases backed up successfully!\n"
f"**Lifetime:** `{os.path.basename(lifetime_backup)}` ({lifetime_size:.2f} MB)\n"
f"**Annual:** `{os.path.basename(annual_backup)}` ({annual_size:.2f} MB)\n"
f"**Total size:** {total_size:.2f} MB"
)
if log_channel:
# Send to notification channel only
notification_channel = self.bot.get_channel(NOTIFICATION_CHANNEL_ID)
if notification_channel:
print(f"[Backup] Sending notification to channel {NOTIFICATION_CHANNEL_ID}")
await notification_channel.send(msg)
else:
print(f"[Backup] Could not find notification channel {NOTIFICATION_CHANNEL_ID}")
print(f"[Backup] Backup completed successfully")
return True, msg
return True
except Exception as e:
error_msg = f"❌ Backup failed: `{e}`"

View File

@@ -45,18 +45,6 @@ class ResetTask(commands.Cog):
if last_reset_month != now.month:
reset_leaderboard("monthly")
print(f"[XP System] Monthly leaderboard reset at {now}")
await self.send_reset_notification(notification_channel_id, user_id, "Monthly")
async def send_reset_notification(self, channel_id, user_id, reset_type):
"""Send a notification message when a reset occurs."""
try:
channel = self.bot.get_channel(channel_id)
if channel:
await channel.send(f"<@{user_id}> {reset_type} leaderboard has been reset! 🔄")
else:
print(f"[XP System] Could not find channel {channel_id} for reset notification")
except Exception as e:
print(f"[XP System] Error sending reset notification: {e}")
def should_reset_daily(self, now):
"""Check if it's time for daily reset (00:00 UTC)."""