diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/exts/filters/antispam.py | 1 | ||||
| -rw-r--r-- | bot/exts/filters/filtering.py | 7 | ||||
| -rw-r--r-- | bot/exts/moderation/modlog.py | 2 | ||||
| -rw-r--r-- | bot/exts/utils/bot.py | 17 | ||||
| -rw-r--r-- | bot/exts/utils/thread_bumper.py | 147 | 
5 files changed, 156 insertions, 18 deletions
| diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py index ddfd11231..bcd845a43 100644 --- a/bot/exts/filters/antispam.py +++ b/bot/exts/filters/antispam.py @@ -103,6 +103,7 @@ class DeletionContext:              mod_alert_message += content          await modlog.send_log_message( +            content=", ".join(str(m.id) for m in self.members),  # quality-of-life improvement for mobile moderators              icon_url=Icons.filtering,              colour=Colour(Colours.soft_red),              title="Spam detected!", diff --git a/bot/exts/filters/filtering.py b/bot/exts/filters/filtering.py index 1f83acf9b..f44b28125 100644 --- a/bot/exts/filters/filtering.py +++ b/bot/exts/filters/filtering.py @@ -256,6 +256,7 @@ class Filtering(Cog):              )              await self.mod_log.send_log_message( +                content=str(member.id),  # quality-of-life improvement for mobile moderators                  icon_url=Icons.token_removed,                  colour=Colours.soft_red,                  title="Username filtering alert", @@ -423,9 +424,12 @@ class Filtering(Cog):              # Allow specific filters to override ping_everyone              ping_everyone = Filter.ping_everyone and _filter.get("ping_everyone", True) -        # If we are going to autoban, we don't want to ping +        content = str(msg.author.id)  # quality-of-life improvement for mobile moderators + +        # If we are going to autoban, we don't want to ping and don't need the user ID          if reason and "[autoban]" in reason:              ping_everyone = False +            content = None          eval_msg = "using !eval " if is_eval else ""          footer = f"Reason: {reason}" if reason else None @@ -439,6 +443,7 @@ class Filtering(Cog):          # Send pretty mod log embed to mod-alerts          await self.mod_log.send_log_message( +            content=content,              icon_url=Icons.filtering,              colour=Colour(Colours.soft_red),              title=f"{_filter['type'].title()} triggered!", diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py index 54a08738c..32ea0dc6a 100644 --- a/bot/exts/moderation/modlog.py +++ b/bot/exts/moderation/modlog.py @@ -116,7 +116,7 @@ class ModLog(Cog, name="ModLog"):          if ping_everyone:              if content: -                content = f"<@&{Roles.moderators}>\n{content}" +                content = f"<@&{Roles.moderators}> {content}"              else:                  content = f"<@&{Roles.moderators}>" diff --git a/bot/exts/utils/bot.py b/bot/exts/utils/bot.py index 788692777..8f0094bc9 100644 --- a/bot/exts/utils/bot.py +++ b/bot/exts/utils/bot.py @@ -1,7 +1,6 @@ -from contextlib import suppress  from typing import Optional -from discord import Embed, Forbidden, TextChannel, Thread +from discord import Embed, TextChannel  from discord.ext.commands import Cog, Context, command, group, has_any_role  from bot.bot import Bot @@ -17,20 +16,6 @@ class BotCog(Cog, name="Bot"):      def __init__(self, bot: Bot):          self.bot = bot -    @Cog.listener() -    async def on_thread_join(self, thread: Thread) -> None: -        """ -        Try to join newly created threads. - -        Despite the event name being misleading, this is dispatched when new threads are created. -        """ -        if thread.me: -            # We have already joined this thread -            return - -        with suppress(Forbidden): -            await thread.join() -      @group(invoke_without_command=True, name="bot", hidden=True)      async def botinfo_group(self, ctx: Context) -> None:          """Bot informational commands.""" diff --git a/bot/exts/utils/thread_bumper.py b/bot/exts/utils/thread_bumper.py new file mode 100644 index 000000000..35057f1fe --- /dev/null +++ b/bot/exts/utils/thread_bumper.py @@ -0,0 +1,147 @@ +import typing as t + +import discord +from async_rediscache import RedisCache +from discord.ext import commands + +from bot import constants +from bot.bot import Bot +from bot.log import get_logger +from bot.pagination import LinePaginator +from bot.utils import channel, scheduling + +log = get_logger(__name__) + + +class ThreadBumper(commands.Cog): +    """Cog that allow users to add the current thread to a list that get reopened on archive.""" + +    # RedisCache[discord.Thread.id, "sentinel"] +    threads_to_bump = RedisCache() + +    def __init__(self, bot: Bot): +        self.bot = bot +        self.init_task = scheduling.create_task(self.ensure_bumped_threads_are_active(), event_loop=self.bot.loop) + +    async def unarchive_threads_not_manually_archived(self, threads: list[discord.Thread]) -> None: +        """ +        Iterate through and unarchive any threads that weren't manually archived recently. + +        This is done by extracting the manually archived threads from the audit log. + +        Only the last 200 thread_update logs are checked, +        as this is assumed to be more than enough to cover bot downtime. +        """ +        guild = self.bot.get_guild(constants.Guild.id) + +        recent_manually_archived_thread_ids = [] +        async for thread_update in guild.audit_logs(limit=200, action=discord.AuditLogAction.thread_update): +            if getattr(thread_update.after, "archived", False): +                recent_manually_archived_thread_ids.append(thread_update.target.id) + +        for thread in threads: +            if thread.id in recent_manually_archived_thread_ids: +                log.info( +                    "#%s (%d) was manually archived. Leaving archived, and removing from bumped threads.", +                    thread.name, +                    thread.id +                ) +                await self.threads_to_bump.delete(thread.id) +            else: +                await thread.edit(archived=False) + +    async def ensure_bumped_threads_are_active(self) -> None: +        """Ensure bumped threads are active, since threads could have been archived while the bot was down.""" +        await self.bot.wait_until_guild_available() + +        threads_to_maybe_bump = [] +        for thread_id, _ in await self.threads_to_bump.items(): +            try: +                thread = await channel.get_or_fetch_channel(thread_id) +            except discord.NotFound: +                log.info("Thread %d has been deleted, removing from bumped threads.", thread_id) +                await self.threads_to_bump.delete(thread_id) +                continue + +            if thread.archived: +                threads_to_maybe_bump.append(thread) + +        await self.unarchive_threads_not_manually_archived(threads_to_maybe_bump) + +    @commands.group(name="bump") +    async def thread_bump_group(self, ctx: commands.Context) -> None: +        """A group of commands to manage the bumping of threads.""" +        if not ctx.invoked_subcommand: +            await ctx.send_help(ctx.command) + +    @thread_bump_group.command(name="add", aliases=("a",)) +    async def add_thread_to_bump_list(self, ctx: commands.Context, thread: t.Optional[discord.Thread]) -> None: +        """Add a thread to the bump list.""" +        await self.init_task + +        if not thread: +            if isinstance(ctx.channel, discord.Thread): +                thread = ctx.channel +            else: +                raise commands.BadArgument("You must provide a thread, or run this command within a thread.") + +        if await self.threads_to_bump.contains(thread.id): +            raise commands.BadArgument("This thread is already in the bump list.") + +        await self.threads_to_bump.set(thread.id, "sentinel") +        await ctx.send(f":ok_hand:{thread.mention} has been added to the bump list.") + +    @thread_bump_group.command(name="remove", aliases=("r", "rem", "d", "del", "delete")) +    async def remove_thread_from_bump_list(self, ctx: commands.Context, thread: t.Optional[discord.Thread]) -> None: +        """Remove a thread from the bump list.""" +        await self.init_task + +        if not thread: +            if isinstance(ctx.channel, discord.Thread): +                thread = ctx.channel +            else: +                raise commands.BadArgument("You must provide a thread, or run this command within a thread.") + +        if not await self.threads_to_bump.contains(thread.id): +            raise commands.BadArgument("This thread is not in the bump list.") + +        await self.threads_to_bump.delete(thread.id) +        await ctx.send(f":ok_hand: {thread.mention} has been removed from the bump list.") + +    @thread_bump_group.command(name="list", aliases=("get",)) +    async def list_all_threads_in_bump_list(self, ctx: commands.Context) -> None: +        """List all the threads in the bump list.""" +        await self.init_task + +        lines = [f"<#{k}>" for k, _ in await self.threads_to_bump.items()] +        embed = discord.Embed( +            title="Threads in the bump list", +            colour=constants.Colours.blue +        ) +        await LinePaginator.paginate(lines, ctx, embed) + +    @commands.Cog.listener() +    async def on_thread_update(self, _: discord.Thread, after: discord.Thread) -> None: +        """ +        Listen for thread updates and check if the thread has been archived. + +        If the thread has been archived, and is in the bump list, un-archive it. +        """ +        await self.init_task + +        if not after.archived: +            return + +        if await self.threads_to_bump.contains(after.id): +            await self.unarchive_threads_not_manually_archived([after]) + +    async def cog_check(self, ctx: commands.Context) -> bool: +        """Only allow staff & partner roles to invoke the commands in this cog.""" +        return await commands.has_any_role( +            *constants.STAFF_PARTNERS_COMMUNITY_ROLES +        ).predicate(ctx) + + +def setup(bot: Bot) -> None: +    """Load the ThreadBumper cog.""" +    bot.add_cog(ThreadBumper(bot)) | 
