aboutsummaryrefslogtreecommitdiffstats
path: root/bot/cogs/error_handler.py
blob: f8a27fda8051e33383b4a0237fce166cdb861596 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import contextlib
import logging

from discord.ext.commands import (
    BadArgument,
    BotMissingPermissions,
    CommandError,
    CommandInvokeError,
    CommandNotFound,
    NoPrivateMessage,
    UserInputError,
)
from discord.ext.commands import Bot, Context

from bot.api import ResponseCodeError


log = logging.getLogger(__name__)


class ErrorHandler:
    """Handles errors emitted from commands."""

    def __init__(self, bot: Bot):
        self.bot = bot

    async def on_command_error(self, ctx: Context, e: CommandError) -> None:
        """Provide command error handling."""
        command = ctx.command
        parent = None

        if command is not None:
            parent = command.parent

        if parent and command:
            help_command = (self.bot.get_command("help"), parent.name, command.name)
        elif command:
            help_command = (self.bot.get_command("help"), command.name)
        else:
            help_command = (self.bot.get_command("help"),)

        if hasattr(command, "on_error"):
            log.debug(f"Command {command} has a local error handler, ignoring.")
            return

        if isinstance(e, CommandNotFound) and not hasattr(ctx, "invoked_from_error_handler"):
            tags_get_command = self.bot.get_command("tags get")
            ctx.invoked_from_error_handler = True

            # Return to not raise the exception
            with contextlib.suppress(ResponseCodeError):
                return await ctx.invoke(tags_get_command, tag_name=ctx.invoked_with)
        elif isinstance(e, BadArgument):
            await ctx.send(f"Bad argument: {e}\n")
            await ctx.invoke(*help_command)
        elif isinstance(e, UserInputError):
            await ctx.send("Something about your input seems off. Check the arguments:")
            await ctx.invoke(*help_command)
        elif isinstance(e, NoPrivateMessage):
            await ctx.send("Sorry, this command can't be used in a private message!")
        elif isinstance(e, BotMissingPermissions):
            await ctx.send(
                f"Sorry, it looks like I don't have the permissions I need to do that.\n\n"
                f"Here's what I'm missing: **{e.missing_perms}**"
            )
        elif isinstance(e, CommandInvokeError):
            if isinstance(e.original, ResponseCodeError):
                if e.original.response.status == 404:
                    await ctx.send("There does not seem to be anything matching your query.")
                elif e.original.response.status == 400:
                    content = await e.original.response.json()
                    log.debug("API gave bad request on command. Response: %r.", content)
                    await ctx.send("According to the API, your request is malformed.")
                elif 500 <= e.original.response.status < 600:
                    await ctx.send("Sorry, there seems to be an internal issue with the API.")
                else:
                    await ctx.send(
                        "Got an unexpected status code from the "
                        f"API (`{e.original.response.code}`)."
                    )

            else:
                await ctx.send(
                    f"Sorry, an unexpected error occurred. Please let us know!\n\n```{e}```"
                )
                raise e.original
        else:
            raise e


def setup(bot: Bot) -> None:
    """Error handler cog load."""
    bot.add_cog(ErrorHandler(bot))
    log.info("Cog loaded: Events")