diff options
| author | 2020-06-02 11:59:00 +0200 | |
|---|---|---|
| committer | 2020-06-02 11:59:00 +0200 | |
| commit | d0c0836a8afab9a650097983c0ed7556269f6ecf (patch) | |
| tree | e2bde0166d613ad21416ab098b73c88611a50dad | |
| parent | Merge branch 'master' into stop_sending_avatar_hash (diff) | |
| parent | Merge pull request #974 from python-discord/multichannel_purge (diff) | |
Merge branch 'master' into stop_sending_avatar_hash
| -rw-r--r-- | bot/cogs/clean.py | 75 | 
1 files changed, 34 insertions, 41 deletions
| diff --git a/bot/cogs/clean.py b/bot/cogs/clean.py index b5d9132cb..368d91c85 100644 --- a/bot/cogs/clean.py +++ b/bot/cogs/clean.py @@ -1,16 +1,16 @@  import logging  import random  import re -from typing import Optional +from typing import Iterable, Optional  from discord import Colour, Embed, Message, TextChannel, User +from discord.ext import commands  from discord.ext.commands import Cog, Context, group  from bot.bot import Bot  from bot.cogs.moderation import ModLog  from bot.constants import ( -    Channels, CleanMessages, Colours, Event, -    Icons, MODERATION_ROLES, NEGATIVE_REPLIES +    Channels, CleanMessages, Colours, Event, Icons, MODERATION_ROLES, NEGATIVE_REPLIES  )  from bot.decorators import with_role @@ -41,10 +41,10 @@ class Clean(Cog):          self,          amount: int,          ctx: Context, +        channels: Iterable[TextChannel],          bots_only: bool = False,          user: User = None,          regex: Optional[str] = None, -        channel: Optional[TextChannel] = None      ) -> None:          """A helper function that does the actual message cleaning."""          def predicate_bots_only(message: Message) -> bool: @@ -110,48 +110,39 @@ class Clean(Cog):              predicate = None                     # Delete all messages          # Default to using the invoking context's channel -        if not channel: -            channel = ctx.channel +        if not channels: +            channels = [ctx.channel] + +        # Delete the invocation first +        self.mod_log.ignore(Event.message_delete, ctx.message.id) +        await ctx.message.delete() -        # Look through the history and retrieve message data          messages = []          message_ids = []          self.cleaning = True -        invocation_deleted = False - -        # To account for the invocation message, we index `amount + 1` messages. -        async for message in channel.history(limit=amount + 1): -            # If at any point the cancel command is invoked, we should stop. -            if not self.cleaning: -                return +        # Find the IDs of the messages to delete. IDs are needed in order to ignore mod log events. +        for channel in channels: +            async for message in channel.history(limit=amount): -            # Always start by deleting the invocation -            if not invocation_deleted: -                self.mod_log.ignore(Event.message_delete, message.id) -                await message.delete() -                invocation_deleted = True -                continue +                # If at any point the cancel command is invoked, we should stop. +                if not self.cleaning: +                    return -            # If the message passes predicate, let's save it. -            if predicate is None or predicate(message): -                message_ids.append(message.id) -                messages.append(message) +                # If the message passes predicate, let's save it. +                if predicate is None or predicate(message): +                    message_ids.append(message.id)          self.cleaning = False -        # We should ignore the ID's we stored, so we don't get mod-log spam. +        # Now let's delete the actual messages with purge.          self.mod_log.ignore(Event.message_delete, *message_ids) - -        # Use bulk delete to actually do the cleaning. It's far faster. -        await channel.purge( -            limit=amount, -            check=predicate -        ) +        for channel in channels: +            messages += await channel.purge(limit=amount, check=predicate)          # Reverse the list to restore chronological order          if messages: -            messages = list(reversed(messages)) +            messages = reversed(messages)              log_url = await self.mod_log.upload_log(messages, ctx.author.id)          else:              # Can't build an embed, nothing to clean! @@ -163,8 +154,10 @@ class Clean(Cog):              return          # Build the embed and send it +        target_channels = ", ".join(channel.mention for channel in channels) +          message = ( -            f"**{len(message_ids)}** messages deleted in <#{channel.id}> by **{ctx.author.name}**\n\n" +            f"**{len(message_ids)}** messages deleted in {target_channels} by **{ctx.author.name}**\n\n"              f"A log of the deleted messages can be found [here]({log_url})."          ) @@ -189,10 +182,10 @@ class Clean(Cog):          ctx: Context,          user: User,          amount: Optional[int] = 10, -        channel: TextChannel = None +        channels: commands.Greedy[TextChannel] = None      ) -> None:          """Delete messages posted by the provided user, stop cleaning after traversing `amount` messages.""" -        await self._clean_messages(amount, ctx, user=user, channel=channel) +        await self._clean_messages(amount, ctx, user=user, channels=channels)      @clean_group.command(name="all", aliases=["everything"])      @with_role(*MODERATION_ROLES) @@ -200,10 +193,10 @@ class Clean(Cog):          self,          ctx: Context,          amount: Optional[int] = 10, -        channel: TextChannel = None +        channels: commands.Greedy[TextChannel] = None      ) -> None:          """Delete all messages, regardless of poster, stop cleaning after traversing `amount` messages.""" -        await self._clean_messages(amount, ctx, channel=channel) +        await self._clean_messages(amount, ctx, channels=channels)      @clean_group.command(name="bots", aliases=["bot"])      @with_role(*MODERATION_ROLES) @@ -211,10 +204,10 @@ class Clean(Cog):          self,          ctx: Context,          amount: Optional[int] = 10, -        channel: TextChannel = None +        channels: commands.Greedy[TextChannel] = None      ) -> None:          """Delete all messages posted by a bot, stop cleaning after traversing `amount` messages.""" -        await self._clean_messages(amount, ctx, bots_only=True, channel=channel) +        await self._clean_messages(amount, ctx, bots_only=True, channels=channels)      @clean_group.command(name="regex", aliases=["word", "expression"])      @with_role(*MODERATION_ROLES) @@ -223,10 +216,10 @@ class Clean(Cog):          ctx: Context,          regex: str,          amount: Optional[int] = 10, -        channel: TextChannel = None +        channels: commands.Greedy[TextChannel] = None      ) -> None:          """Delete all messages that match a certain regex, stop cleaning after traversing `amount` messages.""" -        await self._clean_messages(amount, ctx, regex=regex, channel=channel) +        await self._clean_messages(amount, ctx, regex=regex, channels=channels)      @clean_group.command(name="stop", aliases=["cancel", "abort"])      @with_role(*MODERATION_ROLES) | 
