aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/antispam.py43
-rw-r--r--bot/cogs/moderation/modlog.py15
-rw-r--r--bot/constants.py1
-rw-r--r--config-default.yml1
4 files changed, 52 insertions, 8 deletions
diff --git a/bot/cogs/antispam.py b/bot/cogs/antispam.py
index 1340eb608..6444b1f14 100644
--- a/bot/cogs/antispam.py
+++ b/bot/cogs/antispam.py
@@ -3,10 +3,11 @@ import logging
from collections.abc import Mapping
from dataclasses import dataclass, field
from datetime import datetime, timedelta
+from io import BytesIO
from operator import itemgetter
from typing import Dict, Iterable, List, Set
-from discord import Colour, Member, Message, NotFound, Object, TextChannel
+from discord import Colour, File, HTTPException, Member, Message, NotFound, Object, TextChannel
from discord.ext.commands import Bot, Cog
from bot import rules
@@ -41,11 +42,13 @@ class DeletionContext:
"""Represents a Deletion Context for a single spam event."""
channel: TextChannel
+ bot: Bot
members: Dict[int, Member] = field(default_factory=dict)
rules: Set[str] = field(default_factory=set)
messages: Dict[int, Message] = field(default_factory=dict)
+ attachments: List[List[str]] = field(default_factory=list)
- def add(self, rule_name: str, members: Iterable[Member], messages: Iterable[Message]) -> None:
+ async def add(self, rule_name: str, members: Iterable[Member], messages: Iterable[Message]) -> None:
"""Adds new rule violation events to the deletion context."""
self.rules.add(rule_name)
@@ -57,6 +60,9 @@ class DeletionContext:
if message.id not in self.messages:
self.messages[message.id] = message
+ # Re-upload attachments :
+ self.attachments.append(await reupload_attachments(self.bot, message))
+
async def upload_messages(self, actor_id: int, modlog: ModLog) -> None:
"""Method that takes care of uploading the queue and posting modlog alert."""
triggered_by_users = ", ".join(f"{m} (`{m.id}`)" for m in self.members.values())
@@ -69,7 +75,7 @@ class DeletionContext:
# For multiple messages or those with excessive newlines, use the logs API
if len(self.messages) > 1 or 'newlines' in self.rules:
- url = await modlog.upload_log(self.messages.values(), actor_id)
+ url = await modlog.upload_log(self.messages.values(), actor_id, attachments=self.attachments)
mod_alert_message += f"A complete log of the offending messages can be found [here]({url})"
else:
mod_alert_message += "Message:\n"
@@ -181,13 +187,16 @@ class AntiSpam(Cog):
# If there's no spam event going on for this channel, start a new Message Deletion Context
if message.channel.id not in self.message_deletion_queue:
log.trace(f"Creating queue for channel `{message.channel.id}`")
- self.message_deletion_queue[message.channel.id] = DeletionContext(channel=message.channel)
+ self.message_deletion_queue[message.channel.id] = DeletionContext(
+ channel=message.channel,
+ bot=self.bot
+ )
self.queue_consumption_tasks = self.bot.loop.create_task(
self._process_deletion_context(message.channel.id)
)
# Add the relevant of this trigger to the Deletion Context
- self.message_deletion_queue[message.channel.id].add(
+ await self.message_deletion_queue[message.channel.id].add(
rule_name=rule_name,
members=members,
messages=relevant_messages
@@ -254,6 +263,30 @@ class AntiSpam(Cog):
await deletion_context.upload_messages(self.bot.user.id, self.mod_log)
+async def reupload_attachments(
+ bot: Bot,
+ message: Message,
+ channel_id: int = GuildConfig.attachment_repost
+) -> List[str]:
+ """Re-upload message's attachments to the the channel_id and return the list of re-posted attachments URLs."""
+ if not message.attachments:
+ return []
+ channel = bot.get_channel(channel_id)
+ out = []
+ for attachment in message.attachments:
+ try:
+ with BytesIO() as buffer:
+ await attachment.save(buffer, use_cached=True)
+ reupload: Message = await channel.send(file=File(buffer, filename=attachment.filename))
+ out.append(reupload.attachments[0].url)
+ except HTTPException:
+ log.warning(
+ f"Tried to re-upload attachment {attachment.filename} "
+ f"with ID {attachment.id} from message {message.id}, but it has failed."
+ )
+ return out
+
+
def validate_config(rules: Mapping = AntiSpamConfig.rules) -> Dict[str, str]:
"""Validates the antispam configs."""
validation_errors = {}
diff --git a/bot/cogs/moderation/modlog.py b/bot/cogs/moderation/modlog.py
index 88f2b6c67..9251b79fb 100644
--- a/bot/cogs/moderation/modlog.py
+++ b/bot/cogs/moderation/modlog.py
@@ -34,7 +34,12 @@ class ModLog(Cog, name="ModLog"):
self._cached_deletes = []
self._cached_edits = []
- async def upload_log(self, messages: t.List[discord.Message], actor_id: int) -> str:
+ async def upload_log(
+ self,
+ messages: t.List[discord.Message],
+ actor_id: int,
+ attachments: t.List[t.List[str]] = None
+ ) -> str:
"""
Uploads the log data to the database via an API endpoint for uploading logs.
@@ -42,6 +47,9 @@ class ModLog(Cog, name="ModLog"):
Returns a URL that can be used to view the log.
"""
+ if attachments is None:
+ attachments = []
+
response = await self.bot.api_client.post(
'bot/deleted-messages',
json={
@@ -53,9 +61,10 @@ class ModLog(Cog, name="ModLog"):
'author': message.author.id,
'channel_id': message.channel.id,
'content': message.content,
- 'embeds': [embed.to_dict() for embed in message.embeds]
+ 'embeds': [embed.to_dict() for embed in message.embeds],
+ 'attachments': attachment,
}
- for message in messages
+ for message, attachment in zip(messages, attachments)
]
}
)
diff --git a/bot/constants.py b/bot/constants.py
index 45f42cf81..0fee51df9 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -405,6 +405,7 @@ class Guild(metaclass=YAMLGetter):
id: int
ignored: List[int]
staff_channels: List[int]
+ attachment_repost: int
class Keys(metaclass=YAMLGetter):
diff --git a/config-default.yml b/config-default.yml
index ee9f8a06b..608e5660c 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -134,6 +134,7 @@ guild:
staff_channels: [*ADMINS, *ADMIN_SPAM, *MOD_SPAM, *MODS, *HELPERS, *ORGANISATION, *DEFCON]
ignored: [*ADMINS, *MESSAGE_LOG, *MODLOG]
+ attachment_repost: 649243850006855680
roles:
admin: &ADMIN_ROLE 267628507062992896