diff options
Diffstat (limited to 'bot/exts/moderation/modlog.py')
-rw-r--r-- | bot/exts/moderation/modlog.py | 136 |
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)) |