Passed
Push — master ( 95e0ba...ca4927 )
by Cyb3r
01:11
created

health.HealthCog.get_status()   B

Complexity

Conditions 7

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
nop 4
dl 0
loc 35
rs 8
c 0
b 0
f 0
1
"""Cog the preforms health functions"""
2
from datetime import datetime
3
from discord.ext import commands
4
import discord
5
from bot import utils
6
7
8
async def managed_role_check(role: discord.Role) -> [bool, str]:
9
    """Managed role check
10
11
    Checks to see if the updated one was one that the bot cares about.
12
13
    :param role: the role was cared about or does not return.
14
    :type role: str
15
    :return: If role was found and table the role is in
16
    """
17
    for table in ["schools", "regions"]:
18
        if await utils.select(table, "id", "id", role.id):
19
            return True, table
20
    return False, "error"
21
22
23
class HealthCog(commands.Cog, name="Health"):
24
    """
25
    HealthCog
26
27
28
    Cog that holds the health commands and is responsible for updating the
29
    tables when roles change in discord.
30
31
    **Commands:**
32
        - `check-health`: Makes sure that all the roles in the tables `schools` and `regions` map
33
            to roles in the discord server.
34
35
    **Events:**
36
        - `on_guild_role_update`: Event that is triggered when a role is updated.
37
38
        - `on_guild_role_delete`: Event that is triggered when a role is deleted.
39
40
    """
41
42
    def __init__(self, bot):
43
        self.bot = bot
44
45
    async def cog_check(self, ctx: commands.Context) -> bool:
46
        """
47
        Cog check
48
49
        Makes all the commands in health admin only
50
51
        :param ctx: Command context
52
        :return: User in bot_admins table
53
        :rtype: bool
54
        """
55
        return await utils.check_admin(ctx)
56
57
    @commands.command(name="check-health", help="Checks health of roles for schools and regions")
58
    async def check_health(self, ctx: commands.Context) -> None:
59
        """Check health
60
61
        Checks health of roles for schools and regions. It pulls all the IDs for school and
62
        region roles. Then compares the names of the matching ids to see if they match. If
63
        they match then added to a list called success and if the check fails then then
64
        both names are added to a list called fail.
65
66
67
        :param ctx: Command context
68
        :return:
69
        """
70
        async with ctx.typing():
71
            table_schools = await utils.fetch("schools", "school")
72
            regions = await utils.fetch("regions", "name")
73
            success, fail = [], []
74
            for roles in [table_schools, regions]:
75
                for role in roles:
76
                    try:
77
                        role_name = discord.utils.get(ctx.guild.roles, name=role)
78
                        if role_name.name == role:
79
                            success.append(role_name)
80
                        else:
81
                            fail.append((role_name, role))
82
                    except AttributeError:
83
                        self.bot.log.error(f"Attribute error with role {role}")
84
                        fail.append((role, None))
85
86
        message = "There were {len(success)} successes and {len(fail)} failures"
87
        await utils.make_embed(ctx, "28b463", title="Check Complete", description=message)
88
89
    @commands.command(
90
        name="get-status",
91
        help="Gets all errors or reports for the day.",
92
        description="Admin Only Feature",
93
    )
94
    async def get_status(self, ctx: commands.Context, which: str, ack: bool = False):
95
        """Get Status
96
97
        Get user reports or errors for the current day
98
99
        :param ctx: Command Context
100
        :param which: Either reports or errors
101
        :type which: str
102
        :param ack: Get acknowledged errors
103
        :type ack: bool
104
        :return: None
105
        """
106
        if which == "errors":
107
            columns = "id, message, command, error, ack"
108
        elif which == "reports":
109
            columns = "name, message"
110
        else:
111
            return await utils.error_message(ctx, "Please pick a valid option.")
112
        date = datetime.utcnow().strftime("%Y-%m-%d")
113
        results = await utils.select(which, columns, "date_trunc('day', time)", date)
114
        if not results:
115
            await utils.make_embed(
116
                ctx, "28b463", title="Success", description=f"No {which} for {date}"
117
            )
118
        else:
119
            results_string = []
120
            for result in results:
121
                if result[-1] == ack and which == "errors":
122
                    results_string.append(" ".join(map(str, result)))
123
            await utils.list_message(ctx, results_string, which)
124
125
    @commands.command(
126
        name="test-log",
127
        help="Tests to make sure that that logging feature works.",
128
        description="Admin Only Feature",
129
    )
130
    async def check_log(self, ctx: commands.Context):
131
        """Test log
132
133
        Sends a debugging log
134
135
        :param ctx: Command context
136
        :return: None
137
        """
138
        await utils.admin_log(self.bot, "TESTING LOG: True", True)
139
        await utils.admin_log(self.bot, "TESTING LOG: False", False)
140
        await utils.make_embed(ctx, color="28b463", title="Test Complete")
141
142
    @commands.Cog.listener()
143
    async def on_guild_role_update(self, before: discord.Role, after: discord.Role) -> None:
144
        """Role update
145
146
        Triggered when a role is edited. Logs the old name and new name then updates the name in the
147
        table.
148
149
        :param before: Discord role before it was edited.
150
        :type before: discord.Role
151
        :param after: Discord role after it was edited.
152
        :type after: discord.Role
153
        :return: None
154
        """
155
        managed, _ = await managed_role_check(before)
156
        self.bot.log.debug(f"Role: {before.name} Managed: {managed}")
157
        if managed:
158
            await utils.update("schools", "school", before.name, after.name)
159
            self.bot.log.warning(f'Role "{before.name}" was updated. It is now {after.name}')
160
            await utils.admin_log(self.bot, f"Old role {before} now new role {after}")
161
        else:
162
            self.bot.log.info(f"Old role {before} now new role {after}")
163
164
    @commands.Cog.listener()
165
    async def on_guild_role_delete(self, role: discord.Role) -> None:
166
        """Role delete
167
168
        Triggered when a role is deleted. Will only delete an entry if it existed in the schools or
169
        regions table.
170
171
        :param role: Role that was deleted.
172
        :type role: discord.Role
173
        :return: None
174
        """
175
        managed, table = await managed_role_check(role)
176
        if managed:
177
            await utils.delete("schools", "id", role.id)
178
            self.bot.log.warning(f'Role "{role.name}" was deleted. It was in {table}')
179
        else:
180
            self.bot.log.info(f'Role "{role.name}" was deleted. It was not a managed role')
181
182
        await utils.admin_log(self.bot, f"Role: {role.name} was deleted", True)
183
184
185
def setup(bot):
186
    """Needed for extension loading"""
187
    bot.add_cog(HealthCog(bot))
188