aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/moderation/modlog.py
diff options
context:
space:
mode:
Diffstat (limited to 'bot/exts/moderation/modlog.py')
-rw-r--r--bot/exts/moderation/modlog.py136
1 files changed, 74 insertions, 62 deletions
diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py
index a96638e53..efa87ce25 100644
--- a/bot/exts/moderation/modlog.py
+++ b/bot/exts/moderation/modlog.py
@@ -5,13 +5,15 @@ import typing as t
from datetime import datetime, timezone
from itertools import zip_longest
-import disnake
+import discord
+from botcore.site_api import ResponseCodeError
from dateutil.relativedelta import relativedelta
from deepdiff import DeepDiff
-from disnake import Colour, Message, Thread
-from disnake.abc import GuildChannel
-from disnake.ext.commands import Cog, Context
-from disnake.utils import escape_markdown
+from discord import Colour, Message, Thread
+from discord.abc import GuildChannel
+from discord.ext.commands import Cog, Context
+from discord.utils import escape_markdown, format_dt, snowflake_time
+from sentry_sdk import add_breadcrumb
from bot.bot import Bot
from bot.constants import Categories, Channels, Colours, Emojis, Event, Guild as GuildConstant, Icons, Roles, URLs
@@ -21,7 +23,7 @@ from bot.utils.messages import format_user
log = get_logger(__name__)
-GUILD_CHANNEL = t.Union[disnake.CategoryChannel, disnake.TextChannel, disnake.VoiceChannel]
+GUILD_CHANNEL = t.Union[discord.CategoryChannel, discord.TextChannel, discord.VoiceChannel]
CHANNEL_CHANGES_UNSUPPORTED = ("permissions",)
CHANNEL_CHANGES_SUPPRESSED = ("_overwrites", "position")
@@ -45,7 +47,7 @@ class ModLog(Cog, name="ModLog"):
async def upload_log(
self,
- messages: t.Iterable[disnake.Message],
+ messages: t.Iterable[discord.Message],
actor_id: int,
attachments: t.Iterable[t.List[str]] = None
) -> str:
@@ -53,24 +55,35 @@ class ModLog(Cog, name="ModLog"):
if attachments is None:
attachments = []
- response = await self.bot.api_client.post(
- 'bot/deleted-messages',
- json={
- 'actor': actor_id,
- 'creation': datetime.now(timezone.utc).isoformat(),
- 'deletedmessage_set': [
- {
- 'id': message.id,
- 'author': message.author.id,
- 'channel_id': message.channel.id,
- 'content': message.content.replace("\0", ""), # Null chars cause 400.
- 'embeds': [embed.to_dict() for embed in message.embeds],
- 'attachments': attachment,
- }
- for message, attachment in zip_longest(messages, attachments, fillvalue=[])
- ]
+ deletedmessage_set = [
+ {
+ "id": message.id,
+ "author": message.author.id,
+ "channel_id": message.channel.id,
+ "content": message.content.replace("\0", ""), # Null chars cause 400.
+ "embeds": [embed.to_dict() for embed in message.embeds],
+ "attachments": attachment,
}
- )
+ for message, attachment in zip_longest(messages, attachments, fillvalue=[])
+ ]
+
+ try:
+ response = await self.bot.api_client.post(
+ "bot/deleted-messages",
+ json={
+ "actor": actor_id,
+ "creation": datetime.now(timezone.utc).isoformat(),
+ "deletedmessage_set": deletedmessage_set,
+ }
+ )
+ except ResponseCodeError as e:
+ add_breadcrumb(
+ category="api_error",
+ message=str(e),
+ level="error",
+ data=deletedmessage_set,
+ )
+ raise
return f"{URLs.site_logs_view}/{response['id']}"
@@ -83,22 +96,22 @@ class ModLog(Cog, name="ModLog"):
async def send_log_message(
self,
icon_url: t.Optional[str],
- colour: t.Union[disnake.Colour, int],
+ colour: t.Union[discord.Colour, int],
title: t.Optional[str],
text: str,
- thumbnail: t.Optional[t.Union[str, disnake.Asset]] = None,
+ thumbnail: t.Optional[t.Union[str, discord.Asset]] = None,
channel_id: int = Channels.mod_log,
ping_everyone: bool = False,
- files: t.Optional[t.List[disnake.File]] = None,
+ files: t.Optional[t.List[discord.File]] = None,
content: t.Optional[str] = None,
- additional_embeds: t.Optional[t.List[disnake.Embed]] = None,
+ additional_embeds: t.Optional[t.List[discord.Embed]] = None,
timestamp_override: t.Optional[datetime] = None,
footer: t.Optional[str] = None,
) -> Context:
"""Generate log embed and send to logging channel."""
await self.bot.wait_until_guild_available()
# Truncate string directly here to avoid removing newlines
- embed = disnake.Embed(
+ embed = discord.Embed(
description=text[:4093] + "..." if len(text) > 4096 else text
)
@@ -143,10 +156,10 @@ class ModLog(Cog, name="ModLog"):
if channel.guild.id != GuildConstant.id:
return
- if isinstance(channel, disnake.CategoryChannel):
+ if isinstance(channel, discord.CategoryChannel):
title = "Category created"
message = f"{channel.name} (`{channel.id}`)"
- elif isinstance(channel, disnake.VoiceChannel):
+ elif isinstance(channel, discord.VoiceChannel):
title = "Voice channel created"
if channel.category:
@@ -169,14 +182,14 @@ class ModLog(Cog, name="ModLog"):
if channel.guild.id != GuildConstant.id:
return
- if isinstance(channel, disnake.CategoryChannel):
+ if isinstance(channel, discord.CategoryChannel):
title = "Category deleted"
- elif isinstance(channel, disnake.VoiceChannel):
+ elif isinstance(channel, discord.VoiceChannel):
title = "Voice channel deleted"
else:
title = "Text channel deleted"
- if channel.category and not isinstance(channel, disnake.CategoryChannel):
+ if channel.category and not isinstance(channel, discord.CategoryChannel):
message = f"{channel.category}/{channel.name} (`{channel.id}`)"
else:
message = f"{channel.name} (`{channel.id}`)"
@@ -256,7 +269,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_guild_role_create(self, role: disnake.Role) -> None:
+ async def on_guild_role_create(self, role: discord.Role) -> None:
"""Log role create event to mod log."""
if role.guild.id != GuildConstant.id:
return
@@ -267,7 +280,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_guild_role_delete(self, role: disnake.Role) -> None:
+ async def on_guild_role_delete(self, role: discord.Role) -> None:
"""Log role delete event to mod log."""
if role.guild.id != GuildConstant.id:
return
@@ -278,7 +291,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_guild_role_update(self, before: disnake.Role, after: disnake.Role) -> None:
+ async def on_guild_role_update(self, before: discord.Role, after: discord.Role) -> None:
"""Log role update event to mod log."""
if before.guild.id != GuildConstant.id:
return
@@ -331,7 +344,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_guild_update(self, before: disnake.Guild, after: disnake.Guild) -> None:
+ async def on_guild_update(self, before: discord.Guild, after: discord.Guild) -> None:
"""Log guild update event to mod log."""
if before.id != GuildConstant.id:
return
@@ -382,7 +395,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_member_ban(self, guild: disnake.Guild, member: disnake.Member) -> None:
+ async def on_member_ban(self, guild: discord.Guild, member: discord.Member) -> None:
"""Log ban event to user log."""
if guild.id != GuildConstant.id:
return
@@ -399,7 +412,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_member_join(self, member: disnake.Member) -> None:
+ async def on_member_join(self, member: discord.Member) -> None:
"""Log member join event to user log."""
if member.guild.id != GuildConstant.id:
return
@@ -420,7 +433,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_member_remove(self, member: disnake.Member) -> None:
+ async def on_member_remove(self, member: discord.Member) -> None:
"""Log member leave event to user log."""
if member.guild.id != GuildConstant.id:
return
@@ -437,7 +450,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_member_unban(self, guild: disnake.Guild, member: disnake.User) -> None:
+ async def on_member_unban(self, guild: discord.Guild, member: discord.User) -> None:
"""Log member unban event to mod log."""
if guild.id != GuildConstant.id:
return
@@ -454,7 +467,7 @@ class ModLog(Cog, name="ModLog"):
)
@staticmethod
- def get_role_diff(before: t.List[disnake.Role], after: t.List[disnake.Role]) -> t.List[str]:
+ def get_role_diff(before: t.List[discord.Role], after: t.List[discord.Role]) -> t.List[str]:
"""Return a list of strings describing the roles added and removed."""
changes = []
before_roles = set(before)
@@ -469,7 +482,7 @@ class ModLog(Cog, name="ModLog"):
return changes
@Cog.listener()
- async def on_member_update(self, before: disnake.Member, after: disnake.Member) -> None:
+ async def on_member_update(self, before: discord.Member, after: discord.Member) -> None:
"""Log member update event to user log."""
if before.guild.id != GuildConstant.id:
return
@@ -539,7 +552,7 @@ class ModLog(Cog, name="ModLog"):
channel = self.bot.get_channel(channel_id)
# Ignore not found channels, DMs, and messages outside of the main guild.
- if not channel or not hasattr(channel, "guild") or channel.guild.id != GuildConstant.id:
+ if not channel or channel.guild is None or channel.guild.id != GuildConstant.id:
return True
# Look at the parent channel of a thread.
@@ -552,7 +565,7 @@ class ModLog(Cog, name="ModLog"):
return channel.id in GuildConstant.modlog_blacklist
- async def log_cached_deleted_message(self, message: disnake.Message) -> None:
+ async def log_cached_deleted_message(self, message: discord.Message) -> None:
"""
Log the message's details to message change log.
@@ -573,6 +586,7 @@ class ModLog(Cog, name="ModLog"):
f"**Author:** {format_user(author)}\n"
f"**Channel:** {channel.category}/#{channel.name} (`{channel.id}`)\n"
f"**Message ID:** `{message.id}`\n"
+ f"**Sent at:** {format_dt(message.created_at)}\n"
f"[Jump to message]({message.jump_url})\n"
"\n"
)
@@ -581,6 +595,7 @@ class ModLog(Cog, name="ModLog"):
f"**Author:** {format_user(author)}\n"
f"**Channel:** #{channel.name} (`{channel.id}`)\n"
f"**Message ID:** `{message.id}`\n"
+ f"**Sent at:** {format_dt(message.created_at)}\n"
f"[Jump to message]({message.jump_url})\n"
"\n"
)
@@ -608,7 +623,7 @@ class ModLog(Cog, name="ModLog"):
channel_id=Channels.message_log
)
- async def log_uncached_deleted_message(self, event: disnake.RawMessageDeleteEvent) -> None:
+ async def log_uncached_deleted_message(self, event: discord.RawMessageDeleteEvent) -> None:
"""
Log the message's details to message change log.
@@ -629,6 +644,7 @@ class ModLog(Cog, name="ModLog"):
response = (
f"**Channel:** {channel.category}/#{channel.name} (`{channel.id}`)\n"
f"**Message ID:** `{event.message_id}`\n"
+ f"**Sent at:** {format_dt(snowflake_time(event.message_id))}\n"
"\n"
"This message was not cached, so the message content cannot be displayed."
)
@@ -636,6 +652,7 @@ class ModLog(Cog, name="ModLog"):
response = (
f"**Channel:** #{channel.name} (`{channel.id}`)\n"
f"**Message ID:** `{event.message_id}`\n"
+ f"**Sent at:** {format_dt(snowflake_time(event.message_id))}\n"
"\n"
"This message was not cached, so the message content cannot be displayed."
)
@@ -648,7 +665,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_raw_message_delete(self, event: disnake.RawMessageDeleteEvent) -> None:
+ async def on_raw_message_delete(self, event: discord.RawMessageDeleteEvent) -> None:
"""Log message deletions to message change log."""
if event.cached_message is not None:
await self.log_cached_deleted_message(event.cached_message)
@@ -656,7 +673,7 @@ class ModLog(Cog, name="ModLog"):
await self.log_uncached_deleted_message(event)
@Cog.listener()
- async def on_message_edit(self, msg_before: disnake.Message, msg_after: disnake.Message) -> None:
+ async def on_message_edit(self, msg_before: discord.Message, msg_after: discord.Message) -> None:
"""Log message edit event to message change log."""
if self.is_message_blacklisted(msg_before):
return
@@ -727,7 +744,7 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_raw_message_edit(self, event: disnake.RawMessageUpdateEvent) -> None:
+ async def on_raw_message_edit(self, event: discord.RawMessageUpdateEvent) -> None:
"""Log raw message edit event to message change log."""
if event.guild_id is None:
return # ignore DM edits
@@ -736,7 +753,7 @@ class ModLog(Cog, name="ModLog"):
try:
channel = self.bot.get_channel(int(event.data["channel_id"]))
message = await channel.fetch_message(event.message_id)
- except disnake.NotFound: # Was deleted before we got the event
+ except discord.NotFound: # Was deleted before we got the event
return
if self.is_message_blacklisted(message):
@@ -836,13 +853,8 @@ class ModLog(Cog, name="ModLog"):
)
@Cog.listener()
- async def on_thread_join(self, thread: Thread) -> None:
+ async def on_thread_create(self, thread: Thread) -> None:
"""Log thread creation."""
- # If we are in the thread already we can most probably assume we already logged it?
- # We don't really have a better way of doing this since the API doesn't make any difference between the two
- if thread.me:
- return
-
if self.is_channel_ignored(thread.id):
log.trace("Ignoring creation of thread %s (%d)", thread.mention, thread.id)
return
@@ -860,9 +872,9 @@ class ModLog(Cog, name="ModLog"):
@Cog.listener()
async def on_voice_state_update(
self,
- member: disnake.Member,
- before: disnake.VoiceState,
- after: disnake.VoiceState
+ member: discord.Member,
+ before: discord.VoiceState,
+ after: discord.VoiceState
) -> None:
"""Log member voice state changes to the voice log channel."""
if (
@@ -932,6 +944,6 @@ class ModLog(Cog, name="ModLog"):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the ModLog cog."""
- bot.add_cog(ModLog(bot))
+ await bot.add_cog(ModLog(bot))