From 2fb83b0e8fb438219e308ac806587e38d3e531e3 Mon Sep 17 00:00:00 2001 From: "Martin B." <55140357+martinbndr@users.noreply.github.com> Date: Fri, 19 Dec 2025 17:07:43 +0100 Subject: [PATCH 1/3] Fixes thread_auto_close execution when disabled. This fixes the issue #3290 which caused threads to be auto-closed even if `thread_auto_close` has been disabled. There was also an issue that closed the thread when the user has responded to mods. The thread should stay open and only auto close when the staff has replied back. --- cogs/utility.py | 14 ++++++++++++++ core/thread.py | 2 ++ 2 files changed, 16 insertions(+) diff --git a/cogs/utility.py b/cogs/utility.py index d14aa97baa..0bb555b488 100644 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -873,6 +873,20 @@ async def config_remove(self, ctx, *, key: str.lower): color=self.bot.main_color, description=f"`{key}` had been reset to default.", ) + + # Cancel exsisting active closures from thread_auto_close due to being disabled. + if key == "thread_auto_close": + closures = self.bot.config["closures"] + for recipient_id, items in tuple(closures.items()): + if items.get("auto_close", False) is True: + self.bot.config["closures"].pop(recipient_id) + await self.config.update() + thread = await self.bot.threads.find(recipient_id=int(recipient_id)) + if thread: + await thread.cancel_closure(all=True) + else: + self.bot.config["closures"].pop(recipient_id) + await self.config.update() else: embed = discord.Embed( title="Error", diff --git a/core/thread.py b/core/thread.py index 09263b197d..a6a8a86a63 100644 --- a/core/thread.py +++ b/core/thread.py @@ -1811,6 +1811,8 @@ async def send( if not note and from_mod: self.bot.loop.create_task(self._restart_close_timer()) # Start or restart thread auto close + elif not note and not from_mod: + await self.cancel_closure(all=True) if self.close_task is not None: # cancel closing if a thread message is sent. From 03ed1a78a7205e963e6f73886e225586a407e8a3 Mon Sep 17 00:00:00 2001 From: lorenzo132 Date: Sat, 20 Dec 2025 10:48:21 +0100 Subject: [PATCH 2/3] fix: prevent autoclosing when close has been cancelled. This solves the thread from autoclosing if the closure has been cancelled earlier in a thread. --- core/thread.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/thread.py b/core/thread.py index a6a8a86a63..45a6cb9c71 100644 --- a/core/thread.py +++ b/core/thread.py @@ -67,6 +67,7 @@ def __init__( self.wait_tasks = [] self.close_task = None self.auto_close_task = None + self.auto_close_cancelled = False # Track if auto-close was explicitly cancelled self._cancelled = False self._dm_menu_msg_id = None self._dm_menu_channel_id = None @@ -1078,6 +1079,7 @@ async def close( self.auto_close_task = task else: self.close_task = task + self.auto_close_cancelled = False # Reset flag when manually closing else: await self._close(closer, silent, delete_channel, message) @@ -1278,6 +1280,7 @@ async def cancel_closure(self, auto_close: bool = False, all: bool = False) -> N if self.auto_close_task is not None and (auto_close or all): self.auto_close_task.cancel() self.auto_close_task = None + self.auto_close_cancelled = True # Mark auto-close as explicitly cancelled to_update = self.bot.config["closures"].pop(str(self.id), None) if to_update is not None: @@ -1810,7 +1813,9 @@ async def send( return await destination.send(embed=embed) if not note and from_mod: - self.bot.loop.create_task(self._restart_close_timer()) # Start or restart thread auto close + # Only restart auto-close if it wasn't explicitly cancelled + if not self.auto_close_cancelled: + self.bot.loop.create_task(self._restart_close_timer()) # Start or restart thread auto close elif not note and not from_mod: await self.cancel_closure(all=True) From aaf2fc7950c211d386a2f22c05ac8b3223c0f2bd Mon Sep 17 00:00:00 2001 From: lorenzo132 Date: Sat, 20 Dec 2025 13:07:51 +0100 Subject: [PATCH 3/3] fix: AttributeError / lower mongo calls. I had added a small bugfix aswell for pagination when an invalid config var was given. This happened to occur upon removing the `thread_auto_close` config. --- cogs/utility.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cogs/utility.py b/cogs/utility.py index 0bb555b488..6d619f781f 100644 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -880,21 +880,26 @@ async def config_remove(self, ctx, *, key: str.lower): for recipient_id, items in tuple(closures.items()): if items.get("auto_close", False) is True: self.bot.config["closures"].pop(recipient_id) - await self.config.update() thread = await self.bot.threads.find(recipient_id=int(recipient_id)) if thread: await thread.cancel_closure(all=True) else: self.bot.config["closures"].pop(recipient_id) - await self.config.update() + # Only update config once after processing all closures + await self.bot.config.update() else: - embed = discord.Embed( - title="Error", - color=self.bot.error_color, - description=f"{key} is an invalid key.", - ) - valid_keys = [f"`{k}`" for k in sorted(keys)] - embed.add_field(name="Valid keys", value=", ".join(valid_keys)) + embeds = [] + for names in zip_longest(*(iter(sorted(keys)),) * 15): + description = "\n".join(f"`{name}`" for name in takewhile(lambda x: x is not None, names)) + embed = discord.Embed( + title="Error - Invalid Key", + color=self.bot.error_color, + description=f"`{key}` is an invalid key.\n\n**Valid configuration keys:**\n{description}", + ) + embeds.append(embed) + + session = EmbedPaginatorSession(ctx, *embeds) + return await session.run() return await ctx.send(embed=embed)