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.""" | 
