|
|
@@ -29,6 +29,7 @@ from discord.ext import tasks
|
|
29
|
29
|
from discord.ext.commands import Cog
|
|
30
|
30
|
from discord.utils import escape_markdown
|
|
31
|
31
|
|
|
|
32
|
+from config import CONFIG
|
|
32
|
33
|
from rocketbot.cogs.basecog import BaseCog, BotMessage, CogSetting
|
|
33
|
34
|
from rocketbot.storage import Storage
|
|
34
|
35
|
from rocketbot.utils import dump_stacktrace, norm_datetime
|
|
|
@@ -213,58 +214,83 @@ class LoggingCog(BaseCog, name='Logging'):
|
|
213
|
214
|
guild = member.guild
|
|
214
|
215
|
if not self.get_guild_setting(guild, self.SETTING_ENABLED):
|
|
215
|
216
|
return
|
|
216
|
|
- text = f'Member joined server: {self.__describe_user(member)}.'
|
|
217
|
217
|
flags = []
|
|
218
|
218
|
noteworthy = False
|
|
219
|
219
|
|
|
220
|
|
- if member.flags.did_rejoin:
|
|
221
|
|
- flags.append('Rejoined this server')
|
|
222
|
|
-
|
|
223
|
|
- if member.public_flags.active_developer:
|
|
224
|
|
- flags.append('Is an active developer')
|
|
225
|
|
- if member.public_flags.hypesquad:
|
|
226
|
|
- flags.append('Is a HypeSquad Events member')
|
|
227
|
|
- if member.public_flags.hypesquad_bravery:
|
|
228
|
|
- flags.append('Is a HypeSquad Bravery member')
|
|
229
|
|
- if member.public_flags.hypesquad_brilliance:
|
|
230
|
|
- flags.append('Is a HypeSquad Brilliance member')
|
|
231
|
|
- if member.public_flags.hypesquad_balance:
|
|
232
|
|
- flags.append('Is a HypeSquad Balance member')
|
|
233
|
|
- if member.public_flags.early_supporter:
|
|
234
|
|
- flags.append('Is an early supporter')
|
|
|
220
|
+ badge_info_link = 'https://support.discord.com/hc/en-us/articles/360035962891-Profile-Badges-101'
|
|
235
|
221
|
|
|
|
222
|
+ # Highest priority - should flag mods to be aware
|
|
236
|
223
|
if member.public_flags.spammer:
|
|
237
|
|
- flags.append('**Is flagged as a spammer**')
|
|
|
224
|
+ flags.append(f"{CONFIG['warning_emoji']} **Is flagged as a spammer by Discord**")
|
|
238
|
225
|
noteworthy = True
|
|
239
|
|
- if member.public_flags.discord_certified_moderator:
|
|
240
|
|
- flags.append('**Is a Discord Certified Moderator**')
|
|
|
226
|
+ if member.flags.automod_quarantined_username:
|
|
|
227
|
+ flags.append(f"{CONFIG['warning_emoji']} **Quarantined by AutoMod for their username**")
|
|
241
|
228
|
noteworthy = True
|
|
242
|
|
- if member.public_flags.early_verified_bot_developer:
|
|
243
|
|
- flags.append('**Is a verified bot developer**')
|
|
|
229
|
+ if member.flags.automod_quarantined_guild_tag:
|
|
|
230
|
+ flags.append(f"{CONFIG['warning_emoji']} **Quarantined by AutoMod for their server tag**")
|
|
244
|
231
|
noteworthy = True
|
|
245
|
232
|
if member.public_flags.verified_bot:
|
|
246
|
|
- flags.append('**Is a verified bot**')
|
|
247
|
|
- noteworthy = True
|
|
248
|
|
- if member.public_flags.bug_hunter or member.public_flags.bug_hunter_level_2:
|
|
249
|
|
- flags.append('**Is a bug hunter**')
|
|
|
233
|
+ flags.append(f"{CONFIG['info_emoji']} **Is a verified bot**")
|
|
250
|
234
|
noteworthy = True
|
|
251
|
235
|
if member.public_flags.system:
|
|
252
|
|
- flags.append('**Is a Discord system user**')
|
|
|
236
|
+ flags.append(f"{CONFIG['info_emoji']} **Is a Discord system user**")
|
|
253
|
237
|
noteworthy = True
|
|
254
|
238
|
if member.public_flags.staff:
|
|
255
|
|
- flags.append('**Is Discord staff**')
|
|
|
239
|
+ flags.append(f"{CONFIG['info_emoji']} **Is Discord staff**")
|
|
256
|
240
|
noteworthy = True
|
|
|
241
|
+
|
|
|
242
|
+ # Interesting but doesn't need flagging
|
|
257
|
243
|
if member.public_flags.partner:
|
|
258
|
|
- flags.append('**Is a Discord partner**')
|
|
259
|
|
- noteworthy = True
|
|
|
244
|
+ flags.append(f"{CONFIG['info_emoji']} **Is a Discord partner**")
|
|
260
|
245
|
|
|
|
246
|
+ # Guild-specific
|
|
|
247
|
+ if member.flags.did_rejoin:
|
|
|
248
|
+ flags.append('Rejoined this server')
|
|
|
249
|
+ if member.flags.guest:
|
|
|
250
|
+ flags.append('Guest (can only access voice channel they were invited to)')
|
|
|
251
|
+ if member.flags.bypasses_verification:
|
|
|
252
|
+ flags.append('Can bypass guild verification steps')
|
|
|
253
|
+ if member.flags.completed_home_actions:
|
|
|
254
|
+ flags.append('Completed guild Server Guide actions')
|
|
|
255
|
+ elif member.flags.started_home_actions:
|
|
|
256
|
+ flags.append('Started guild Server Guide actions')
|
|
|
257
|
+ if member.flags.completed_onboarding:
|
|
|
258
|
+ flags.append('Completed guild onboarding')
|
|
|
259
|
+ elif member.flags.started_onboarding:
|
|
|
260
|
+ flags.append('Started guild onboarding')
|
|
|
261
|
+ # member.flags.dm_settings_upsell_acknowledged - no idea what the "DM settings upsell" is
|
|
|
262
|
+
|
|
|
263
|
+ # Trivia
|
|
|
264
|
+ if member.public_flags.verified_bot_developer:
|
|
|
265
|
+ flags.append('In an Early Verified Bot Developer')
|
|
|
266
|
+ elif member.public_flags.active_developer:
|
|
|
267
|
+ flags.append('Is an active developer')
|
|
|
268
|
+ if member.public_flags.hypesquad_bravery:
|
|
|
269
|
+ flags.append(f'Was a HypeSquad Bravery member ([info](<{badge_info_link}>))')
|
|
|
270
|
+ elif member.public_flags.hypesquad_brilliance:
|
|
|
271
|
+ flags.append(f'Was a HypeSquad Brilliance member ([info](<{badge_info_link}>))')
|
|
|
272
|
+ elif member.public_flags.hypesquad_balance:
|
|
|
273
|
+ flags.append(f'Was a HypeSquad Balance member ([info](<{badge_info_link}>))')
|
|
|
274
|
+ elif member.public_flags.hypesquad:
|
|
|
275
|
+ flags.append(f'Was a HypeSquad Events member ([info](<{badge_info_link}>))')
|
|
|
276
|
+ if member.public_flags.early_supporter:
|
|
|
277
|
+ flags.append(f'Was a Nitro early supporter ([info](<{badge_info_link}>))')
|
|
|
278
|
+ if member.public_flags.team_user:
|
|
|
279
|
+ flags.append('Is a Team User')
|
|
|
280
|
+ if member.public_flags.bug_hunter_level_2:
|
|
|
281
|
+ flags.append('Is a Discord bug hunter level 2')
|
|
|
282
|
+ elif member.public_flags.bug_hunter:
|
|
|
283
|
+ flags.append('Is a Discord bug hunter')
|
|
|
284
|
+ if member.public_flags.discord_certified_moderator:
|
|
|
285
|
+ flags.append('Was a Discord Certified Moderator')
|
|
|
286
|
+ if member.public_flags.early_verified_bot_developer:
|
|
|
287
|
+ flags.append('Is a verified bot developer')
|
|
|
288
|
+ # public_flags.bot_http_interactions isn't interesting
|
|
|
289
|
+
|
|
|
290
|
+ text = f"Member joined server: {self.__describe_user(member, tag=noteworthy)}"
|
|
261
|
291
|
if len(flags) > 0:
|
|
262
|
|
- text += '\n* ' + '\n* '.join(flags)
|
|
263
|
|
- if noteworthy:
|
|
264
|
|
- text += f'\n\nLink: {member.mention}'
|
|
265
|
|
- bot_message = BotMessage(guild, text, BotMessage.TYPE_MOD_WARNING)
|
|
266
|
|
- else:
|
|
267
|
|
- bot_message = BotMessage(guild, text, BotMessage.TYPE_LOG)
|
|
|
292
|
+ text += '\n- ' + '\n- '.join(flags)
|
|
|
293
|
+ bot_message = BotMessage(guild, text, BotMessage.TYPE_MOD_WARNING if noteworthy else BotMessage.TYPE_LOG)
|
|
268
|
294
|
await bot_message.update()
|
|
269
|
295
|
|
|
270
|
296
|
@Cog.listener()
|
|
|
@@ -324,8 +350,13 @@ class LoggingCog(BaseCog, name='Logging'):
|
|
324
|
350
|
if not self.get_guild_setting(guild, self.SETTING_ENABLED):
|
|
325
|
351
|
return
|
|
326
|
352
|
changes = []
|
|
|
353
|
+ noteworthy = False
|
|
327
|
354
|
if after.nick != before.nick:
|
|
328
|
355
|
changes.append(f'Nick: `{before.nick}` -> `{after.nick}`')
|
|
|
356
|
+ if after.name != before.name:
|
|
|
357
|
+ changes.append(f'Username: `@{before.name}` -> `@{after.name}`')
|
|
|
358
|
+ if after.display_name != before.display_name:
|
|
|
359
|
+ changes.append(f'Display name: `{before.display_name}` -> `{after.display_name}`')
|
|
329
|
360
|
if after.roles != before.roles:
|
|
330
|
361
|
added_role_names = []
|
|
331
|
362
|
removed_role_names = []
|
|
|
@@ -353,18 +384,33 @@ class LoggingCog(BaseCog, name='Logging'):
|
|
353
|
384
|
changes.append(f'Guild avatar: <{before_guild_avatar}> -> <{after_guild_avatar}>')
|
|
354
|
385
|
if after.flags != before.flags:
|
|
355
|
386
|
flag_changes = []
|
|
|
387
|
+ noteworthy_flags = { 'automod_quarantined_username', 'automod_quarantined_guild_tag' }
|
|
356
|
388
|
for (name, after_value) in iter(after.flags):
|
|
357
|
389
|
before_value = getattr(before.flags, name)
|
|
358
|
390
|
if after_value != before_value:
|
|
359
|
391
|
flag_changes.append(f'`{name}` = `{before_value}` -> `{after_value}`')
|
|
|
392
|
+ if after_value and name in noteworthy_flags:
|
|
|
393
|
+ noteworthy = True
|
|
|
394
|
+ if len(flag_changes) > 0:
|
|
|
395
|
+ changes.append(f'Guild-specific flag changes: {", ".join(flag_changes)}')
|
|
|
396
|
+ if after.public_flags != before.public_flags:
|
|
|
397
|
+ flag_changes = []
|
|
|
398
|
+ noteworthy_flags = { 'spammer' }
|
|
|
399
|
+ for (name, after_value) in iter(after.public_flags):
|
|
|
400
|
+ before_value = getattr(before.public_flags, name)
|
|
|
401
|
+ if after_value != before_value:
|
|
|
402
|
+ flag_changes.append(f'`{name}` = `{before_value}` -> `{after_value}`')
|
|
|
403
|
+ if after_value and name in noteworthy_flags:
|
|
|
404
|
+ noteworthy = True
|
|
360
|
405
|
if len(flag_changes) > 0:
|
|
361
|
|
- changes.append(f'Flag changes: {", ".join(flag_changes)}')
|
|
|
406
|
+ changes.append(f'Public flag changes: {", ".join(flag_changes)}')
|
|
362
|
407
|
|
|
363
|
408
|
if len(changes) == 0:
|
|
364
|
409
|
return
|
|
365
|
|
- text = f'Details for member {self.__describe_user(before)} changed:\n'
|
|
366
|
|
- text += '* ' + ('\n* '.join(changes))
|
|
367
|
|
- bot_message = BotMessage(guild, text, BotMessage.TYPE_LOG)
|
|
|
410
|
+ text = f'Details for member {self.__describe_user(before, tag=noteworthy)} changed:\n'
|
|
|
411
|
+ text += '- ' + ('\n- '.join(changes))
|
|
|
412
|
+ bot_message = BotMessage(guild, text,
|
|
|
413
|
+ BotMessage.TYPE_MOD_WARNING if noteworthy else BotMessage.TYPE_LOG)
|
|
368
|
414
|
await bot_message.update()
|
|
369
|
415
|
|
|
370
|
416
|
@Cog.listener()
|
|
|
@@ -874,11 +920,13 @@ class LoggingCog(BaseCog, name='Logging'):
|
|
874
|
920
|
return '> _<no content>_'
|
|
875
|
921
|
return '> ' + escape_markdown(s).replace('\n', '\n> ')
|
|
876
|
922
|
|
|
877
|
|
- def __describe_user(self, user: User | Member) -> str:
|
|
|
923
|
+ def __describe_user(self, user: User | Member, tag: bool = False) -> str:
|
|
878
|
924
|
"""
|
|
879
|
925
|
Standardized Markdown describing a user or member.
|
|
880
|
926
|
"""
|
|
881
|
|
- return f'**{user.name}** ({user.display_name} {user.id})'
|
|
|
927
|
+ if tag:
|
|
|
928
|
+ return f'<@{user.id}> (`@{user.name}`, display "{user.display_name}", id `{user.id}`)'
|
|
|
929
|
+ return f'**`@{user.name}`** (display "{user.display_name}", id `{user.id}`)'
|
|
882
|
930
|
|
|
883
|
931
|
def __diff(self, a: str, b: str) -> tuple[str, str]:
|
|
884
|
932
|
# URLs don't work well in the diffs. Replace them with private use characters, one per unique URL.
|