diff options
| author | 2019-11-27 18:37:16 +0100 | |
|---|---|---|
| committer | 2019-11-27 18:37:16 +0100 | |
| commit | 461826cff98c66646d6f545fc1e711675ac6492f (patch) | |
| tree | 1c0172d9fba0cfc189f0b6503879efd74f40c8d7 | |
| parent | Re-indent arguments (diff) | |
Move attachments re-uploading to DeletionContext.add()
So they are re-uploaded before being deleted
| -rw-r--r-- | bot/cogs/antispam.py | 41 | ||||
| -rw-r--r-- | bot/cogs/moderation/modlog.py | 30 |
2 files changed, 47 insertions, 24 deletions
diff --git a/bot/cogs/antispam.py b/bot/cogs/antispam.py index a450c18ce..8009c9d42 100644 --- a/bot/cogs/antispam.py +++ b/bot/cogs/antispam.py @@ -1,11 +1,13 @@ +import asyncio 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, Member, Message, NotFound, Object, TextChannel from discord.ext.commands import Bot, Cog from bot import rules @@ -40,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) @@ -56,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()) @@ -68,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" @@ -180,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 @@ -242,6 +252,9 @@ class AntiSpam(Cog): async def _process_deletion_context(self, context_id: int) -> None: """Processes the Deletion Context queue.""" + log.trace("Sleeping before processing message deletion queue.") + await asyncio.sleep(10) + if context_id not in self.message_deletion_queue: log.error(f"Started processing deletion queue for context `{context_id}`, but it was not found!") return @@ -250,6 +263,24 @@ 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: + 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) + 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 945d7822b..9251b79fb 100644 --- a/bot/cogs/moderation/modlog.py +++ b/bot/cogs/moderation/modlog.py @@ -2,7 +2,6 @@ import asyncio import logging import typing as t from datetime import datetime -from io import BytesIO import discord from dateutil.relativedelta import relativedelta @@ -35,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. @@ -43,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={ @@ -55,9 +62,9 @@ class ModLog(Cog, name="ModLog"): 'channel_id': message.channel.id, 'content': message.content, 'embeds': [embed.to_dict() for embed in message.embeds], - 'attachments': await self.reupload_attachments(message) if message.attachments else [], + 'attachments': attachment, } - for message in messages + for message, attachment in zip(messages, attachments) ] } ) @@ -118,21 +125,6 @@ class ModLog(Cog, name="ModLog"): return await self.bot.get_context(log_message) # Optionally return for use with antispam - async def reupload_attachments( - self, - message: discord.Message, - channel_id: int = GuildConstant.attachment_repost - ) -> t.List[str]: - """Re-upload message's attachments to the the channel_id and return the list of re-posted attachments URLs.""" - channel = self.bot.get_channel(channel_id) - out = [] - for attachment in message.attachments: - with BytesIO() as buffer: - await attachment.save(buffer, use_cached=True) - reupload: discord.Message = await channel.send(file=discord.File(buffer, filename=attachment.filename)) - out.append(reupload.attachments[0].url) - return out - @Cog.listener() async def on_guild_channel_create(self, channel: GUILD_CHANNEL) -> None: """Log channel create event to mod log.""" |