From 8c75a0f773adaa4022568b53cd08cb08e128a3ca Mon Sep 17 00:00:00 2001 From: No767 <73260931+No767@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:42:04 -0700 Subject: [PATCH 1/6] redo error handling --- bot/cogs/admin.py | 5 ++++ bot/cogs/config.py | 19 +++++++++++- bot/cogs/tickets.py | 11 ++++++- bot/libs/utils/__init__.py | 1 - bot/libs/utils/embeds.py | 30 +++++++++++++++++++ bot/libs/utils/errors.py | 61 -------------------------------------- bot/libs/utils/modals.py | 4 +-- bot/libs/utils/tree.py | 4 +-- bot/libs/utils/views.py | 5 ++-- bot/rodhaj.py | 27 ++++++++++++----- 10 files changed, 88 insertions(+), 79 deletions(-) delete mode 100644 bot/libs/utils/errors.py diff --git a/bot/cogs/admin.py b/bot/cogs/admin.py index 9a2dcd7..d12dc4a 100644 --- a/bot/cogs/admin.py +++ b/bot/cogs/admin.py @@ -10,6 +10,7 @@ from discord.ext import commands from discord.ext.commands import Greedy from libs.utils import RoboContext + from rodhaj import Rodhaj GIT_PULL_REGEX = re.compile(r"\s+(?P.*)\b\s+\|\s+[\d]") @@ -179,6 +180,10 @@ async def reload(self, ctx: RoboContext) -> None: await ctx.send(self.format_results(statuses)) + @commands.command(name="test") + async def testing(self, ctx: RoboContext) -> None: + raise ValueError("hi") + async def setup(bot: Rodhaj) -> None: await bot.add_cog(Admin(bot)) diff --git a/bot/cogs/config.py b/bot/cogs/config.py index 6a59431..4241de0 100644 --- a/bot/cogs/config.py +++ b/bot/cogs/config.py @@ -19,12 +19,13 @@ from libs.tickets.utils import get_cached_thread from libs.utils import GuildContext from libs.utils.checks import bot_check_permissions, check_permissions -from libs.utils.embeds import Embed +from libs.utils.embeds import CooldownEmbed, Embed from libs.utils.pages import SimplePages from libs.utils.prefix import get_prefix if TYPE_CHECKING: from cogs.tickets import Tickets + from rodhaj import Rodhaj UNKNOWN_ERROR_MESSAGE = ( @@ -463,6 +464,22 @@ async def delete(self, ctx: GuildContext) -> None: else: await ctx.send("Cancelling.") + @setup.error + async def on_setup_error( + self, ctx: GuildContext, error: commands.CommandError + ) -> None: + if isinstance(error, commands.CommandOnCooldown): + embed = CooldownEmbed(error.retry_after) + await ctx.send(embed=embed) + + @delete.error + async def on_delete_error( + self, ctx: GuildContext, error: commands.CommandError + ) -> None: + if isinstance(error, commands.CommandOnCooldown): + embed = CooldownEmbed(error.retry_after) + await ctx.send(embed=embed) + @check_permissions(manage_guild=True) @commands.guild_only() @config.group(name="prefix", fallback="info") diff --git a/bot/cogs/tickets.py b/bot/cogs/tickets.py index 543e07e..3e5c6d3 100644 --- a/bot/cogs/tickets.py +++ b/bot/cogs/tickets.py @@ -14,12 +14,13 @@ safe_content, ) from libs.utils.checks import bot_check_permissions -from libs.utils.embeds import Embed, LoggingEmbed +from libs.utils.embeds import CooldownEmbed, Embed, LoggingEmbed from .config import GuildWebhookDispatcher if TYPE_CHECKING: from libs.utils import GuildContext, RoboContext + from rodhaj import Rodhaj @@ -526,6 +527,14 @@ async def on_ticket_close( embed.add_field(name="Link", value=ticket.mention) await webhook.send(embed=embed) + @reply.error + async def on_reply_error( + self, ctx: GuildContext, error: commands.CommandError + ) -> None: + if isinstance(error, commands.CommandOnCooldown): + embed = CooldownEmbed(error.retry_after) + await ctx.send(embed=embed) + async def setup(bot: Rodhaj) -> None: await bot.add_cog(Tickets(bot)) diff --git a/bot/libs/utils/__init__.py b/bot/libs/utils/__init__.py index 47c19df..b558372 100644 --- a/bot/libs/utils/__init__.py +++ b/bot/libs/utils/__init__.py @@ -11,7 +11,6 @@ ErrorEmbed as ErrorEmbed, LoggingEmbed as LoggingEmbed, ) -from .errors import send_error_embed as send_error_embed from .handler import KeyboardInterruptHandler as KeyboardInterruptHandler from .help import RodhajHelp as RodhajHelp from .logger import RodhajLogger as RodhajLogger diff --git a/bot/libs/utils/embeds.py b/bot/libs/utils/embeds.py index 8efdede..c04ff45 100644 --- a/bot/libs/utils/embeds.py +++ b/bot/libs/utils/embeds.py @@ -1,3 +1,5 @@ +import traceback + import discord @@ -23,3 +25,31 @@ def __init__(self, **kwargs): "Uh oh! It seems like the command ran into an issue! For support, ask the dev team", ) super().__init__(**kwargs) + + +class FullErrorEmbed(ErrorEmbed): + def __init__(self, error: Exception, **kwargs): + kwargs.setdefault("description", self._format_description(error)) + super().__init__(**kwargs) + + def _format_description(self, error: Exception) -> str: + error_traceback = "\n".join(traceback.format_exception_only(type(error), error)) + desc = f""" + Uh oh! It seems like there was an issue. Ask the devs for help. + + **Error**: + ```{error_traceback}``` + """ + return desc + + +class CooldownEmbed(discord.Embed): + def __init__(self, retry_after: float, **kwargs): + kwargs.setdefault("color", discord.Color.from_rgb(214, 6, 6)) + kwargs.setdefault("timestamp", discord.utils.utcnow()) + kwargs.setdefault("title", "Command On Cooldown") + kwargs.setdefault( + "description", + f"This command is on cooldown. Try again in {retry_after:.2f}s", + ) + super().__init__(**kwargs) diff --git a/bot/libs/utils/errors.py b/bot/libs/utils/errors.py deleted file mode 100644 index 196e9ed..0000000 --- a/bot/libs/utils/errors.py +++ /dev/null @@ -1,61 +0,0 @@ -import traceback - -import discord -from discord.ext import commands - -from .embeds import ErrorEmbed - - -def produce_error_embed(error: Exception) -> ErrorEmbed: - error_traceback = "\n".join(traceback.format_exception_only(type(error), error)) - embed = ErrorEmbed() - desc = f""" - Uh oh! It seems like there was an issue. Ask the devs for help. - - **Error**: - ```{error_traceback}``` - """ - embed.description = desc - embed.set_footer(text="Happened At") - embed.timestamp = discord.utils.utcnow() - return embed - - -def create_premade_embed(title: str, description: str) -> ErrorEmbed: - embed = ErrorEmbed() - embed.timestamp = discord.utils.utcnow() - embed.title = title - embed.description = description - return embed - - -def build_cooldown_embed(error: commands.CommandOnCooldown) -> ErrorEmbed: - embed = ErrorEmbed() - embed.timestamp = discord.utils.utcnow() - embed.title = "Command On Cooldown" - embed.description = ( - f"This command is on cooldown. Try again in {error.retry_after:.2f}s" - ) - return embed - - -async def send_error_embed(ctx: commands.Context, error: commands.CommandError) -> None: - if isinstance(error, commands.CommandOnCooldown): - await ctx.send(embed=build_cooldown_embed(error)) - elif isinstance(error, commands.CommandInvokeError) or isinstance( - error, commands.HybridCommandError - ): - await ctx.send(embed=produce_error_embed(error)) - elif isinstance(error, commands.NoPrivateMessage): - await ctx.author.send( - embed=create_premade_embed( - "Guild Only", "This command cannot be used in private messages" - ) - ) - elif isinstance(error, commands.MissingRequiredArgument): - await ctx.send( - embed=create_premade_embed( - "Missing Required Argument", - f"You are missing the following argument(s): {error.param.name}", - ) - ) diff --git a/bot/libs/utils/modals.py b/bot/libs/utils/modals.py index 8a02e0d..7486ed0 100644 --- a/bot/libs/utils/modals.py +++ b/bot/libs/utils/modals.py @@ -3,7 +3,7 @@ import discord from .context import RoboContext -from .errors import produce_error_embed +from .embeds import FullErrorEmbed NO_CONTROL_MSG = "This modal cannot be controlled by you, sorry!" @@ -28,6 +28,6 @@ async def on_error( self, interaction: discord.Interaction, error: Exception, / ) -> None: await interaction.response.send_message( - embed=produce_error_embed(error), ephemeral=True + embed=FullErrorEmbed(error), ephemeral=True ) self.stop() diff --git a/bot/libs/utils/tree.py b/bot/libs/utils/tree.py index 729b39d..ad5576f 100644 --- a/bot/libs/utils/tree.py +++ b/bot/libs/utils/tree.py @@ -5,7 +5,7 @@ import discord from discord import app_commands -from .errors import produce_error_embed +from .embeds import FullErrorEmbed if TYPE_CHECKING: from rodhaj import Rodhaj @@ -25,4 +25,4 @@ async def interaction_check(self, interaction: discord.Interaction, /) -> bool: async def on_error( self, interaction: discord.Interaction, error: app_commands.AppCommandError ) -> None: - await interaction.response.send_message(embed=produce_error_embed(error)) + await interaction.response.send_message(embed=FullErrorEmbed(error)) diff --git a/bot/libs/utils/views.py b/bot/libs/utils/views.py index 41932a3..231a56b 100644 --- a/bot/libs/utils/views.py +++ b/bot/libs/utils/views.py @@ -4,8 +4,7 @@ import discord -from .embeds import ErrorEmbed -from .errors import produce_error_embed +from .embeds import ErrorEmbed, FullErrorEmbed if TYPE_CHECKING: from .context import RoboContext @@ -38,7 +37,7 @@ async def on_error( /, ) -> None: await interaction.response.send_message( - embed=produce_error_embed(error), ephemeral=True + embed=FullErrorEmbed(error), ephemeral=True ) self.stop() diff --git a/bot/rodhaj.py b/bot/rodhaj.py index 903b39d..dec574a 100644 --- a/bot/rodhaj.py +++ b/bot/rodhaj.py @@ -14,18 +14,14 @@ from libs.tickets.structs import PartialConfig, ReservedTags, StatusChecklist from libs.tickets.utils import get_cached_thread, get_partial_ticket from libs.tickets.views import TicketConfirmView -from libs.utils import ( - RoboContext, - RodhajCommandTree, - RodhajHelp, - send_error_embed, -) +from libs.utils import RoboContext, RodhajCommandTree, RodhajHelp from libs.utils.config import RodhajConfig from libs.utils.prefix import get_prefix from libs.utils.reloader import Reloader if TYPE_CHECKING: from cogs.tickets import Tickets + from libs.utils.context import RoboContext class Rodhaj(commands.Bot): @@ -89,9 +85,24 @@ async def get_context( return await super().get_context(origin, cls=cls) async def on_command_error( - self, ctx: commands.Context, error: commands.CommandError + self, ctx: RoboContext, error: commands.CommandError ) -> None: - await send_error_embed(ctx, error) + if self._dev_mode: + self.logger.exception("Ignoring exception:", exc_info=error) + return + + if isinstance(error, commands.NoPrivateMessage): + await ctx.author.send("This command cannot be used in private messages") + elif isinstance(error, commands.MissingRequiredArgument): + await ctx.send( + f"You are missing the following argument(s): {error.param.name}" + ) + elif isinstance(error, commands.CommandInvokeError): + original = error.original + if not isinstance(original, discord.HTTPException): + self.logger.exception("In %s:", ctx.command.qualified_name, exc_info=original) # type: ignore + elif isinstance(error, commands.BadArgument): + await ctx.send(str(error)) ### Ticket processing and handling From 8c47db0c9807b1511c936e5a102d38adbe181ef1 Mon Sep 17 00:00:00 2001 From: No767 <73260931+No767@users.noreply.github.com> Date: Sun, 2 Jun 2024 13:32:27 -0700 Subject: [PATCH 2/6] fmt changes --- bot/libs/utils/embeds.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/libs/utils/embeds.py b/bot/libs/utils/embeds.py index c04ff45..66209f2 100644 --- a/bot/libs/utils/embeds.py +++ b/bot/libs/utils/embeds.py @@ -35,11 +35,11 @@ def __init__(self, error: Exception, **kwargs): def _format_description(self, error: Exception) -> str: error_traceback = "\n".join(traceback.format_exception_only(type(error), error)) desc = f""" - Uh oh! It seems like there was an issue. Ask the devs for help. - - **Error**: - ```{error_traceback}``` - """ + Uh oh! It seems like there was an issue. Ask the devs for help. + + **Error**: + ```{error_traceback}``` + """ return desc From b82ac0356f0e01a66e6f1961f9e29f797f5eaadf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:33:07 +0000 Subject: [PATCH 3/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- bot/cogs/admin.py | 1 - bot/cogs/config.py | 1 - bot/cogs/tickets.py | 1 - 3 files changed, 3 deletions(-) diff --git a/bot/cogs/admin.py b/bot/cogs/admin.py index d12dc4a..13d6be8 100644 --- a/bot/cogs/admin.py +++ b/bot/cogs/admin.py @@ -10,7 +10,6 @@ from discord.ext import commands from discord.ext.commands import Greedy from libs.utils import RoboContext - from rodhaj import Rodhaj GIT_PULL_REGEX = re.compile(r"\s+(?P.*)\b\s+\|\s+[\d]") diff --git a/bot/cogs/config.py b/bot/cogs/config.py index 4241de0..f5665a6 100644 --- a/bot/cogs/config.py +++ b/bot/cogs/config.py @@ -25,7 +25,6 @@ if TYPE_CHECKING: from cogs.tickets import Tickets - from rodhaj import Rodhaj UNKNOWN_ERROR_MESSAGE = ( diff --git a/bot/cogs/tickets.py b/bot/cogs/tickets.py index 3e5c6d3..4438a68 100644 --- a/bot/cogs/tickets.py +++ b/bot/cogs/tickets.py @@ -20,7 +20,6 @@ if TYPE_CHECKING: from libs.utils import GuildContext, RoboContext - from rodhaj import Rodhaj From f71227e51898f55c52dc89a40bd98629b42a9d15 Mon Sep 17 00:00:00 2001 From: No767 <73260931+No767@users.noreply.github.com> Date: Sun, 2 Jun 2024 13:33:25 -0700 Subject: [PATCH 4/6] remove testing cmd --- bot/cogs/admin.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bot/cogs/admin.py b/bot/cogs/admin.py index d12dc4a..7725121 100644 --- a/bot/cogs/admin.py +++ b/bot/cogs/admin.py @@ -180,10 +180,6 @@ async def reload(self, ctx: RoboContext) -> None: await ctx.send(self.format_results(statuses)) - @commands.command(name="test") - async def testing(self, ctx: RoboContext) -> None: - raise ValueError("hi") - async def setup(bot: Rodhaj) -> None: await bot.add_cog(Admin(bot)) From cbb148c0880a60db123b38bb588ddf5e5f8ba925 Mon Sep 17 00:00:00 2001 From: No767 <73260931+No767@users.noreply.github.com> Date: Sun, 2 Jun 2024 13:51:08 -0700 Subject: [PATCH 5/6] conform to sonarcloud standards --- bot/cogs/config.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/bot/cogs/config.py b/bot/cogs/config.py index f5665a6..7702fc9 100644 --- a/bot/cogs/config.py +++ b/bot/cogs/config.py @@ -25,6 +25,7 @@ if TYPE_CHECKING: from cogs.tickets import Tickets + from rodhaj import Rodhaj UNKNOWN_ERROR_MESSAGE = ( @@ -242,6 +243,14 @@ async def get_block_ticket( return BlocklistTicket(cog=tickets_cog, thread=cached_ticket.thread) + ### Misc Utilities + async def _handle_error( + self, ctx: GuildContext, error: commands.CommandError + ) -> None: + if isinstance(error, commands.CommandOnCooldown): + embed = CooldownEmbed(error.retry_after) + await ctx.send(embed=embed) + @check_permissions(manage_guild=True) @bot_check_permissions(manage_channels=True, manage_webhooks=True) @commands.guild_only() @@ -467,17 +476,13 @@ async def delete(self, ctx: GuildContext) -> None: async def on_setup_error( self, ctx: GuildContext, error: commands.CommandError ) -> None: - if isinstance(error, commands.CommandOnCooldown): - embed = CooldownEmbed(error.retry_after) - await ctx.send(embed=embed) + await self._handle_error(ctx, error) @delete.error async def on_delete_error( self, ctx: GuildContext, error: commands.CommandError ) -> None: - if isinstance(error, commands.CommandOnCooldown): - embed = CooldownEmbed(error.retry_after) - await ctx.send(embed=embed) + await self._handle_error(ctx, error) @check_permissions(manage_guild=True) @commands.guild_only() From 35d33ce014fac5b2448fdc2250f34ad953d54bba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:51:21 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- bot/cogs/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/cogs/config.py b/bot/cogs/config.py index 7702fc9..0dc7964 100644 --- a/bot/cogs/config.py +++ b/bot/cogs/config.py @@ -25,7 +25,6 @@ if TYPE_CHECKING: from cogs.tickets import Tickets - from rodhaj import Rodhaj UNKNOWN_ERROR_MESSAGE = (