Passed
Push — master ( dcd1eb...4f7f97 )
by Cyb3r
02:51 queued 01:44
created

bot.cogs.errors   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 86
dl 0
loc 154
rs 10
c 0
b 0
f 0
wmc 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
A ErrorsCog.__init__() 0 2 1
A ErrorsCog.ack_all() 0 35 3
B ErrorsCog.on_command_error() 0 55 8
A ErrorsCog.ack_error() 0 25 2

1 Function

Rating   Name   Duplication   Size   Complexity  
A setup() 0 3 1
1
"""Cogs that handles errors"""
2
import logging
3
import random
4
from datetime import datetime
5
6
import discord
7
from discord.ext import commands
8
from bot import utils
9
10
log = logging.getLogger("bot")
11
12
13
class ErrorsCog(commands.Cog, name="Errors"):
14
    """ErrorsCogs
15
    ---
16
17
    The cog that handles all errors.
18
19
    Commands:
20
    ---
21
    `ack-error`: Acknowledge an error by ID
22
23
24
    """
25
26
    def __init__(self, bot):
27
        self.bot = bot
28
29
    @commands.command(name="ack-error", help="Acknowledge an error to stop it from appearing")
30
    @commands.check(utils.check_admin)
31
    async def ack_error(self, ctx: commands.Context, error_id: str) -> None:
32
        """Ack Error
33
34
        Acknowledge an error to prevent it from appearing in the task
35
36
        :param ctx: Command context
37
        :type ctx: discord.ext.commands.Context
38
        :param error_id: Id of the error
39
        :type error_id: str
40
        :return: None
41
        """
42
        error = await utils.select("errors", "id", "id", error_id)
43
        if not error:
44
            await ctx.send(f"Error {error_id} not found")
45
        else:
46
            await utils.update(
47
                table="errors",
48
                where_column="id",
49
                where_value=error_id,
50
                column="ack",
51
                new_value=True,
52
            )
53
            await ctx.send(f"Error {error_id} has been acknowledged")
54
55
    @commands.command(name="ack-all", help="Acknowledge all errors")
56
    @commands.check(utils.check_admin)
57
    async def ack_all(self, ctx: commands.Context) -> None:
58
        """Ack All
59
60
        Acknowledge all currently unacknowledged errors
61
62
        :param ctx: Command context
63
        :type ctx: discord.ext.commands.Context
64
        :return:  None
65
        """
66
        errors = await utils.select(
67
            table="errors", column="id", where_column="ack", where_value=False
68
        )
69
        if not errors:
70
            await ctx.send("No errors need acknowledging")
71
            return
72
        error_count = 0
73
        for error in errors:
74
            await utils.update(
75
                table="errors",
76
                where_column="id",
77
                where_value=error,
78
                column="ack",
79
                new_value=True,
80
            )
81
            log.debug(
82
                "Acknowledged error {} as part of bulk acknowledgement by {}".format(
83
                    error, ctx.author.display_name
84
                )
85
            )
86
            error_count += 1
87
        await ctx.send(
88
            (
89
                "All errors have been acknowledged."
90
                f"Total: {str(error_count)}\nError Numbers: {', '.join(map(str, errors))}"
91
            )
92
        )
93
94
    @commands.Cog.listener()
95
    async def on_command_error(self, ctx: commands.Context, error: Exception) -> None:
96
        """Error report
97
98
        On error add it to the database and inform user of error
99
100
        :param ctx: Command context
101
        :type ctx: discord.ext.commands.Context
102
        :param error: Error that was raised
103
        :type error: Exception
104
        :return: None
105
        """
106
        if isinstance(error, commands.DisabledCommand):
107
            await utils.error_message(ctx, message=f"{ctx.command} has been disabled.")
108
            return
109
110
        if isinstance(error, commands.NoPrivateMessage):
111
            try:
112
                await ctx.author.send(f"{ctx.command} can not be used in Private Messages.")
113
                return
114
            except discord.HTTPException:
115
                pass
116
117
        if isinstance(error, (commands.errors.MissingRole, commands.errors.CheckFailure)):
118
            error_msg = "You do not have the correct role for this command."
119
        elif isinstance(error, commands.errors.CommandNotFound):
120
            return
121
        elif isinstance(error, commands.MissingRequiredArgument):
122
            error_msg = f"`{ctx.message.content}` has missing required arguments"
123
        else:
124
            errors = await utils.fetch("errors", "id")
125
            error_id = random.randint(1, 32767)  # nosec
126
            while error_id in errors:
127
                log.warning("Error ID had to be regenerated")
128
                error_id = random.randint(1, 32767)  # nosec
129
130
            log.error((error_id, error))
131
            log.exception(error, exc_info=True)
132
            error_msg = (
133
                "There was an unknown error.\n"
134
                "Please report it for investigation.\n"
135
                "Error #{}".format(error_id)
136
            )
137
            log.error("There was the following error: {}".format(error))
138
            error_info = [
139
                error_id,
140
                ctx.message.content,
141
                f"COG: {ctx.command.cog.qualified_name} COMMAND: {ctx.command.name}",
142
                str(error),
143
                datetime.utcnow(),
144
                False,
145
            ]
146
            await utils.insert("errors", error_info)
147
148
        await utils.make_embed(ctx, "FF0000", title="Error:", description=error_msg)
149
150
151
def setup(bot):
152
    """Needed for extension loading"""
153
    bot.add_cog(ErrorsCog(bot))
154