Passed
Pull Request — master (#50)
by Cyb3r
01:15
created

bot.cogs.errors   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Importance

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