Files
hmgrisen/bot/src/cogs/errors.py
T
2026-10-23 21:28:21 +02:00

199 lines
7.3 KiB
Python

import traceback
import discord
from cogs.utils import embed_templates
from discord import app_commands
from discord.ext import commands
class Errors(commands.Cog):
"""Error handlers for commands"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
bot.tree.on_error = self.on_app_command_error # Set error handler for slash commands
@commands.Cog.listener()
async def on_command(self, ctx: commands.Context):
"""
Logs prefix command execution metadata
Parameters
----------
ctx (commands.Context): Context object
"""
self.bot.logger.info(
f'{"❌ " if ctx.command_failed else "✔ "} {ctx.command} | '
+ f"{ctx.author.name} ({ctx.author.id}) | "
+ f"{ctx.guild.id}-{ctx.channel.id}-{ctx.message.id}"
)
@commands.Cog.listener()
async def on_app_command_completion(
self, interaction: discord.Interaction, command: app_commands.Command | app_commands.ContextMenu
):
"""
Logs slash command execution metadata
Parameters
----------
interaction (discord.Interaction): Slash command context object
command (app_commands.Command | app_commands.ContextMenu): Command object
"""
self.bot.logger.info(
f'{"❌ " if interaction.command_failed else "✔ "} {command.name} | '
+ f"{interaction.user.name} ({interaction.user.id}) | "
+ f"{interaction.guild_id}-{interaction.channel_id}-{interaction.id}"
)
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context, error: commands.CommandError):
"""
Handle prefix command errors
Parameters
----------
ctx (commands.Context): Context object
error (commands.CommandError): Eror context object
"""
# Reset cooldown if command throws AttributeError
try:
self.bot.get_command(f"{ctx.command}").reset_cooldown(ctx)
except AttributeError:
pass
# Ignore command's own error handling
if hasattr(ctx.command, "on_error"):
return
error = getattr(error, "original", error)
# Ignored errors
ignored_errors = (commands.CommandNotFound, commands.DisabledCommand, commands.CheckFailure)
if isinstance(error, ignored_errors):
self.bot.logger.info("Ignored error", error)
return
# Errors that should prompt a help message
send_help = (commands.MissingRequiredArgument, commands.TooManyArguments, commands.BadArgument)
if isinstance(error, send_help):
return await ctx.send_help(ctx.command)
elif isinstance(error, commands.BotMissingPermissions):
embed = self.error_missing_perms(error.missing_permissions, "Jeg")
elif isinstance(error, commands.MissingPermissions):
embed = self.error_missing_perms(error.missing_permissions, "Du")
elif isinstance(error, commands.NotOwner):
embed = embed_templates.error_warning("Bare boteieren kan gjøre dette")
elif isinstance(error, commands.CommandOnCooldown):
embed = embed_templates.error_warning(
f"Kommandoen har nettopp blitt brukt\nPrøv igjen om `{error.retry_after:.1f}` sekunder.",
)
elif isinstance(error, commands.NoPrivateMessage):
embed = embed_templates.error_warning("Denne kommandoen kan bare utføres it servere")
else:
embed = embed_templates.error_fatal("En ukjent feil oppstod!")
f = discord.File("./src/assets/edb.png")
embed.set_image(url="attachment://edb.png")
# Yeah, this fucking sucks but I want my beautiful edb picture :_;
try:
f
except NameError:
f = None
try:
await ctx.reply(embed=embed, file=f)
except discord.errors.Forbidden:
self.bot.logger.warning("Could not send error message to user")
except app_commands.BotMissingPermissions:
await ctx.reply(
"Jeg mangler `embed_links` og/eller `attach_files` tillatelsen(e). Ingenting funker uten de"
)
# Log full exception to file
self.bot.logger.error("".join(traceback.format_exception(type(error), error, error.__traceback__)))
async def on_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError):
"""
Handle slash command errors
Parameters
----------
interaction (discord.Interaction): Slash command context object
error (app_commands.AppCommandError): Eror context object
"""
# The command may have deferred or responded before it failed
if not interaction.response.is_done():
await interaction.response.defer()
# Log command usage, just in case
await self.on_app_command_completion(interaction, interaction.command)
# Followups crash on file=None, so the edb picture is passed in a list that is empty for known errors
files = []
if isinstance(error, app_commands.BotMissingPermissions):
embed = self.error_missing_perms(error.missing_permissions, "Jeg")
elif isinstance(error, app_commands.MissingPermissions):
embed = self.error_missing_perms(error.missing_permissions, "Du")
elif isinstance(error, app_commands.CommandOnCooldown):
embed = embed_templates.error_warning(
f"Kommandoen har nettopp blitt brukt\nPrøv igjen om `{error.retry_after:.1f}` sekunder."
)
else:
embed = embed_templates.error_fatal("En ukjent feil oppstod!")
files.append(discord.File("./src/assets/edb.png"))
embed.set_image(url="attachment://edb.png")
try:
await interaction.followup.send(embed=embed, files=files)
except discord.errors.Forbidden:
self.bot.logger.warning("Could not send error message to user")
except app_commands.BotMissingPermissions:
await interaction.followup.send(
"Jeg mangler `embed_links` og/eller `attach_files` tillatelsen(e). Ingenting funker uten de"
)
# Log full exception to file
self.bot.logger.error("".join(traceback.format_exception(type(error), error, error.__traceback__)))
def error_missing_perms(self, permissions: list[str], client: str) -> discord.Embed:
"""
Missing permissions embed template.
Since it only applies to this cog it has been put here instead of the util file
Parameters
----------
permissions (list[str]): The missing permissions
client (str): Who is missing the permissions? Typically "Du" (user) or "Jeg" (bot client)
Returns
----------
(discord.Embed): The final embed
"""
permissions = ", ".join(permissions)
return embed_templates.error_warning(f"{client} mangler følgende tillatelser\n\n```{permissions}\n```")
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Errors(bot))