-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcore.py
435 lines (370 loc) Β· 16.3 KB
/
core.py
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
import logging
from typing import Optional
import discord
from redbot.core import Config, checks, commands
BASECOG = getattr(commands, "Cog", object)
DEF_GUILD = {
"report_channel": None,
"archive_channel": None,
"emote_reactions": False,
"claim_reports": False,
"recieve_dms": [],
"category_roles": {},
}
# TODO Add reportdm command to disable dms on reports. To avoid annoyed members.
class Reports(BASECOG):
"""
Report system
Members can type `[p]report <user> <reason>` and it'll show up in your selected channel!
"""
__author__ = ["SharkyTheKing"]
__version__ = "1.1.0"
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=2233914253021)
self.config.register_guild(**DEF_GUILD)
self.log = logging.getLogger("red.cogs.reports")
async def red_delete_data_for_user(self, **kwargs):
"""
Nothing to delete
"""
return
def format_help_for_context(self, ctx: commands.Context) -> str:
context = super().format_help_for_context(ctx)
authors = ", ".join(self.__author__)
return f"{context}\n\nAuthor: {authors}\nVersion: {self.__version__}"
@commands.guild_only()
@commands.cooldown(1, 15, commands.BucketType.user)
@commands.command(usage="")
async def reportdm(self, ctx):
"""
Enables/Disables the messages the bot sends on report
By default this changes depending on your current setting.
"""
try:
await ctx.message.delete()
except (discord.Forbidden, discord.HTTPException):
pass
status = None
async with self.config.guild(ctx.guild).recieve_dms() as dmreport:
if ctx.author.id not in dmreport:
dmreport.append(ctx.author.id)
status = True
else:
dmreport.remove(ctx.author.id)
status = False
message = "Done. You will {status} receive DMs when you report".format(
status="not" if status else "now"
)
try:
await ctx.author.send(message)
except discord.HTTPException:
await ctx.send(message)
@commands.guild_only()
@commands.cooldown(2, 15, commands.BucketType.user)
@commands.command(usage="<member> <reason>")
async def report(self, ctx, member: Optional[discord.Member], *, reason: str):
"""
Report a member
Example: !report @SharkyTheKing#0001 Not being fishy enough.
Arguments:
`member`: The Discord member you want to report
`reason`: The reason for the report
"""
report_channel = await self.config.guild(ctx.guild).report_channel()
if report_channel is None:
try:
return await ctx.author.send(
"We're sorry! The Moderation team on this server hasn't setup a report "
"channel yet. Please reach out to the moderation team and ask if they could "
"set one up!"
)
except (discord.Forbidden, discord.NotFound):
pass
try:
await ctx.message.delete()
except (discord.Forbidden, discord.HTTPException):
self.log.info("Unable to delete message in {}".format(ctx.channel.name))
await self.build_report_embeds(ctx, member, reason, report_channel)
async def build_report_embeds(self, ctx, member, reason, report_channel):
"""
Builds embeds for report
If member is None. Default to no user
"""
embed = discord.Embed()
embed.description = "**Reason**:\n{}".format(reason)
embed.timestamp = ctx.message.created_at
if member is None:
embed.add_field(name="User", value="No user detected.")
else:
embed.add_field(name="User", value="{}\n**ID**: {}".format(member.mention, member.id))
if member is None or member.voice is None:
embed.add_field(name="Channel", value=ctx.channel.mention)
else:
embed.add_field(
name="Channel",
value="{}\n**VC**: {}".format(ctx.channel.mention, member.voice.channel.mention),
)
if ctx.author is None:
embed.add_field(name="Author", value="No Author Found")
else:
embed.add_field(name="Author", value=ctx.author.mention)
await self.send_report_to_mods(ctx, embed, report_channel)
async def send_report_to_mods(self, ctx, embed, report_channel):
"""
Sending to channel
"""
channel_report = self.bot.get_channel(report_channel)
if ctx.channel.category:
role_id = await self.config.guild(ctx.guild).category_roles.get_raw(str(ctx.channel.category.id), default=None)
ping = ctx.guild.get_role(role_id) if role_id else None
else:
ping = None
try:
await channel_report.send(content=ping.mention if ping else None, embed=embed, allowed_mentions=discord.AllowedMentions(roles=True))
except discord.Forbidden:
self.log.warning("Unable to send message in {}".format(channel_report))
except discord.HTTPException as e:
self.log.warning("HTTPException {} - {}".format(e.code, e.status))
if ctx.author.id in await self.config.guild(ctx.guild).recieve_dms():
return
try:
await ctx.author.send(
"Thank you for your report. The moderation team has received your report."
)
except (discord.Forbidden, discord.HTTPException):
self.log.info(
"Unable to send message to {} - {}".format(ctx.author.name, ctx.author.id)
)
@report.error
async def _report_error_handler(self, ctx, error):
"""Error handler for the report command"""
if isinstance(error, commands.CommandOnCooldown):
try:
await ctx.message.delete()
except (discord.errors.Forbidden, discord.errors.HTTPException):
pass
try:
return await ctx.author.send(
"Your report has been rate limited. Please do not mass report."
)
except (discord.errors.Forbidden, discord.errors.HTTPException):
pass
else:
await ctx.bot.on_command_error(ctx, error, unhandled_by_cog=True)
@checks.mod_or_permissions(kick_members=True)
@commands.group()
async def reportset(self, ctx):
"""
Manage reports system
"""
pass
@reportset.command(name="list")
async def show_settings(self, ctx):
"""
Displays report settings
"""
guild_config = await self.config.guild(ctx.guild).all()
report_channel = guild_config["report_channel"]
archive_channel = guild_config["archive_channel"]
emotes_toggle = guild_config["emote_reactions"]
claim_toggle = guild_config["claim_reports"]
embed = discord.Embed()
embed.title = "{}'s Report Settings".format(ctx.guild.name)
embed.add_field(
name="Report Channel",
value="<#{}>".format(report_channel) if report_channel else "No channel set",
inline=False,
)
embed.add_field(
name="Archive Channel",
value="<#{}>".format(archive_channel) if archive_channel else "No channel set",
inline=False,
)
embed.add_field(
name="Auto Emote Reaction", value="enabled" if emotes_toggle else "disabled"
)
embed.add_field(name="Moderation Claim", value="enabled" if claim_toggle else "disabled")
await ctx.send(embed=embed)
@reportset.command(name="reportclaim")
async def report_claim(self, ctx, toggle: Optional[bool]):
"""
Toggle report to be claimed.
If this is toggled on, any reaction on any reports is immediately claimed by the moderator.
"""
report_toggle = self.config.guild(ctx.guild).claim_reports
if toggle is None:
return await ctx.send(
"Report claim are {}".format("enabled" if await report_toggle() else "disabled")
)
elif toggle is True:
await report_toggle.set(True)
return await ctx.send("The setting is now enabled.")
elif toggle is False:
await report_toggle.set(False)
return await ctx.send("The setting is now disabled.")
@reportset.command()
async def channel(self, ctx, channel: Optional[discord.TextChannel]):
"""
Sets the channel where reports will be posted into
"""
if channel is None:
await self.config.guild(ctx.guild).report_channel.set(None)
return await ctx.send("Done. Cleared the report channel.")
await self.config.guild(ctx.guild).report_channel.set(channel.id)
await ctx.send("Done. Set {} to be the report channel.".format(channel.mention))
@reportset.command()
async def archive(self, ctx, channel: Optional[discord.TextChannel]):
"""
Sets the channel where reports will archived into
"""
if channel is None:
await self.config.guild(ctx.guild).archive_channel.set(None)
return await ctx.send("Done. Cleared the archive channel.")
await self.config.guild(ctx.guild).archive_channel.set(channel.id)
await ctx.send("Done. Set {} to be the archive channel.".format(channel.mention))
@reportset.command()
async def emotes(self, ctx, toggle: Optional[bool]):
"""
Sets it whether the bot automatically puts reactions for each report sent
Up is confirming it's a valid report
Down is confirming it's not a valid report
Question means you're unsure of the report or are in question of it
X means it's been too long to look into
"""
emotes_toggle = self.config.guild(ctx.guild).emote_reactions
if toggle is None:
return await ctx.send(
"Emotes are {}".format("enabled" if await emotes_toggle() else "disabled")
)
elif toggle is True:
await self.config.guild(ctx.guild).emote_reactions.set(True)
return await ctx.send("The setting is now enabled")
elif toggle is False:
await self.config.guild(ctx.guild).emote_reactions.set(False)
return await ctx.send("The setting is now disabled")
@reportset.command()
async def ping(self, ctx, category: discord.CategoryChannel, role: discord.Role):
"""
Sets the role to be pinged when a report is sent in a category
"""
await self.config.guild(ctx.guild).category_roles.set_raw(str(category.id), value=role.id)
await ctx.send(f"Done. Set {role.mention} to be pinged when a report is sent in {category.name}")
@reportset.command()
async def removeping(self, ctx, category: discord.CategoryChannel):
"""
Removes the pinged role for a report in a specific category.
"""
data = await self.config.guild(ctx.guild).category_roles.get_raw(str(category.id), default=None)
if data is None:
await ctx.send(f"No ping role is set for {category.name}.")
return
await self.config.guild(ctx.guild).category_roles.clear_raw(str(category.id))
await ctx.send(f"Removed the ping role for reports in {category.name}.")
@commands.Cog.listener()
async def on_message(self, message):
"""
Auto-add reactions
"""
if not message.guild:
return
if await self.bot.cog_disabled_in_guild(self, message.guild):
return
report_channel = await self.config.guild(message.guild).report_channel()
if await self.config.guild(message.guild).emote_reactions() is False:
return False
if report_channel is None:
return False
if message.author == self.bot.user:
emote_channel = discord.utils.get(message.guild.channels, id=int(report_channel))
if message.channel != emote_channel:
return False
try:
await message.add_reaction("π")
except discord.NotFound:
return # No need to log if message was removed
except (discord.Forbidden, discord.HTTPException):
self.log.info("Unable to react in {}".format(emote_channel))
@commands.Cog.listener()
async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User):
"""
Detects for when someone adds reaction
"""
if not reaction.message.guild:
return
if await self.bot.cog_disabled_in_guild(self, reaction.message.guild):
return False
if user.id == self.bot.user.id:
return
config_info = await self.config.guild(reaction.message.guild).all()
if config_info["report_channel"] is None:
return
if config_info["claim_reports"] is False:
return
report_channel = discord.utils.get(
reaction.message.guild.channels, id=int(config_info["report_channel"])
)
if reaction.message.channel != report_channel:
return
message = reaction.message
if message.author.id != self.bot.user.id:
return
if (
reaction.message.embeds
and "Status:" in str(reaction.message.embeds[0].fields)
or "has marked this resolved." in reaction.message.content
or "has marked this invalid." in reaction.message.content
or not reaction.message.embeds
):
return
if reaction.emoji == "π":
try:
embed = message.embeds[0]
embed.add_field(
name="Moderator Claimed:", value="{} ({})".format(user.mention, user.id)
)
await message.edit(embed=embed)
await reaction.clear()
await message.add_reaction("π")
await message.add_reaction("π")
except IndexError:
await message.edit("{} ({}) has claimed this.".format(user.mention, user.id))
elif reaction.emoji == "π":
try:
embed = message.embeds[0]
embed.add_field(
name="Status:", value="β
Resolved"
)
await message.edit(embed=embed)
await message.clear_reactions()
if config_info["archive_channel"]:
channel_archive = self.bot.get_channel(config_info["archive_channel"])
try:
await channel_archive.send(embed=embed)
await message.delete()
except discord.Forbidden:
self.log.warning("Unable to send message in {}".format(channel_archive))
except discord.HTTPException as e:
self.log.warning("HTTPException {} - {}".format(e.code, e.status))
except IndexError:
await message.edit("{} ({}) has marked this resolved.".format(user.mention, user.id))
elif reaction.emoji == "π":
try:
embed = message.embeds[0]
embed.add_field(
name="Status:", value="β Invalid"
)
await message.edit(embed=embed)
await message.clear_reactions()
if config_info["archive_channel"]:
channel_archive = self.bot.get_channel(config_info["archive_channel"])
try:
await channel_archive.send(embed=embed)
await message.delete()
except discord.Forbidden:
self.log.warning("Unable to send message in {}".format(channel_archive))
except discord.HTTPException as e:
self.log.warning("HTTPException {} - {}".format(e.code, e.status))
except IndexError:
await message.edit("{} ({}) has marked this invalid.".format(user.mention, user.id))
# Reason for no try on editing is because we check if it's the bot's message before editing