Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 69 additions & 9 deletions src/bot/cogs/logging/logging_message_delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import datetime
import logging
import os
from io import BytesIO

import discord
from discord.ext import commands
Expand All @@ -19,8 +20,8 @@ def embed_message_delete(some_member, some_message, some_moderator=None):
embed = discord.Embed(
title="<:red_circle:1043616578744357085> Deleted Message",
description=f"{some_moderator.mention if some_moderator is not None else some_member.mention} deleted a message"
f"\nIn {some_message.channel}\nMessage "
f"author: {some_member.mention}",
f"\nIn {some_message.channel}\n"
f"Message author: {some_member.mention}",
color=discord.Color.red(),
timestamp=datetime.datetime.now(datetime.timezone.utc),
)
Expand All @@ -33,8 +34,20 @@ def embed_message_delete(some_member, some_message, some_moderator=None):
the_message = some_message.content[0:1020] + "..."
else:
the_message = some_message.content

if not the_message:
the_message = "*No text content*"
embed.add_field(name="Message: ", value=the_message, inline=True)

if some_message.attachments:
embed.add_field(
name="Attachments: ",
value="\n".join(
attachment.filename for attachment in some_message.attachments
)[0:1020],
inline=False,
)

return embed


Expand All @@ -46,18 +59,61 @@ class LoggingMessageDelete(commands.Cog):

def __init__(self, bot):
self.bot = bot
self.staff_channel = self.bot.api.get_one_setting("3")["setting"][
"value"
] # Staff Channel ID
setting = self.bot.api.get_one_setting("3") # Staff Channel ID
if setting["status"] != "ok":
raise RuntimeError("Failed to fetch staff channel setting from API.")
self.staff_channel = setting["setting"]["value"]

self.chat_log = self.bot.api.get_one_log_setting("3") # chat_log
if self.chat_log["status"] != "ok":
raise RuntimeError("Failed to fetch chat log setting from API.")

async def build_image_file(self, attachment: discord.Attachment) -> discord.File:
"""
Return a File for the attachment, so it can be re-uploaded with the log embed.
"""
data = await attachment.read()
return discord.File(BytesIO(data), filename=attachment.filename)

async def collect_image_files(self, message) -> list[discord.File]:
"""
Re-download every image attachment on the deleted message.

Discord purges the CDN copy shortly after a delete, so anything we
fail to fetch is simply left out of the log rather than raising.
"""
size_limit = message.guild.filesize_limit
files = []
for attachment in message.attachments:
if not (
attachment.content_type and attachment.content_type.startswith("image/")
):
continue
if attachment.size > size_limit:
logger.debug(
f"Image attachment {attachment.filename} is too large to re-upload "
f"({attachment.size} > {size_limit}). Skipping."
)
continue
logger.debug(
f"Image attachment detected in deleted message, "
f"{attachment.filename}:{attachment.url}"
)
try:
files.append(await self.build_image_file(attachment))
except discord.HTTPException as err:
logger.warning(
f"Could not fetch deleted attachment {attachment.filename} -> {err}"
)
return files

@commands.Cog.listener()
async def on_message_delete(self, message):
async def on_message_delete(self, message) -> None:
"""
If a mod deletes, take the audit log event. If a user deletes, handle it normally.
"""
if (
message.author.guild.id != int(os.getenv("MASTER_GUILD"))
message.author.guild.id != int(os.getenv("MASTER_GUILD", 0))
or message.author.guild.id is None
):
logger.warning(
Expand All @@ -80,15 +136,19 @@ async def on_message_delete(self, message):
self.chat_log["log_setting"]["value"]
)

image_files = await self.collect_image_files(message)

if str(audit_log.action) == "AuditLogAction.message_delete":
# Then a moderator deleted a message.
embed = embed_message_delete(audit_log.target, message, audit_log.user)
await logs_channel.send(embed=embed)
await logs_channel.send(embed=embed, files=image_files)

else:
# Otherwise, the author deleted it.
username = message.author
await logs_channel.send(embed=embed_message_delete(username, message))
await logs_channel.send(
embed=embed_message_delete(username, message), files=image_files
)
else:
logger.critical(f"API error. API response not ok. -> {self.chat_log}")

Expand Down
Loading