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