From d638336f52f40576e57de17e3794ded1d9b9fa4c Mon Sep 17 00:00:00 2001 From: eldiablotyPY Date: Sat, 17 Oct 2026 22:27:55 +0200 Subject: [PATCH 1/2] Add silence and unsilence commands for threads This PR allows users to silence and unsilence commands for threads by locking and unlocking the channel. --- bot/exts/moderation/silence.py | 91 ++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py index 131d8410d7..edf7d963ee 100644 --- a/bot/exts/moderation/silence.py +++ b/bot/exts/moderation/silence.py @@ -32,7 +32,7 @@ ) MSG_UNSILENCE_SUCCESS = f"{constants.Emojis.check_mark} unsilenced {{channel}}." -TextOrVoiceChannel = TextChannel | VoiceChannel +TextOrVoiceChannel = TextChannel | VoiceChannel | Thread VOICE_CHANNELS = { constants.Channels.code_help_voice_0: constants.Channels.code_help_chat_0, @@ -181,13 +181,16 @@ async def silence( # Since threads don't have specific overrides, we cannot silence them individually. # The parent channel has to be muted or the thread should be archived. if isinstance(channel, Thread): - await ctx.send(":x: Threads cannot be silenced.") - return - - if not await self._set_silence_overwrites(channel, kick=kick): - log.info("Tried to silence channel %s but the channel was already silenced.", channel_info) + if not channel.locked: + await channel.edit(locked=True) + else: + log.info("Thread already silenced!") await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) - return + else: + if not await self._set_silence_overwrites(channel, kick=kick): + log.info("Tried to silence channel %s but the channel was already silenced.", channel_info) + await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) + return if isinstance(channel, VoiceChannel): if kick: @@ -215,7 +218,7 @@ def parse_silence_args( ) -> tuple[TextOrVoiceChannel, int | None]: """Helper method to parse the arguments of the silence command.""" if duration_or_channel: - if isinstance(duration_or_channel, TextChannel | VoiceChannel): + if isinstance(duration_or_channel, TextChannel | VoiceChannel | Thread): channel = duration_or_channel else: channel = ctx.channel @@ -322,54 +325,68 @@ async def _unsilence(self, channel: TextOrVoiceChannel) -> bool: """ # Get stored overwrites, and return if channel is unsilenced prev_overwrites = await self.previous_overwrites.get(channel.id) - if channel.id not in self.scheduler and prev_overwrites is None: - log.info("Tried to unsilence channel #%s (%s) but the channel was not silenced.", channel, channel.id) - return False + if isinstance (channel, Thread): + if not channel.locked and channel.id not in self.scheduler: + log.info("You are trying to unsilence a thread but it's not silenced") + return False + else: + if channel.id not in self.scheduler and prev_overwrites is None: + log.info("Tried to unsilence channel #%s (%s) but the channel was not silenced.", channel, channel.id) + return False # Select the role based on channel type, and get current overwrites - if isinstance(channel, TextChannel): + if isinstance(channel, Thread): + await channel.edit(locked = False) + else: + if isinstance(channel, TextChannel): role = self._everyone_role overwrite = channel.overwrites_for(role) permissions = "`Send Messages` and `Add Reactions`" - else: + else: role = self._verified_voice_role overwrite = channel.overwrites_for(role) permissions = "`Speak` and `Connect`" - + + + # Check if old overwrites were not stored - if prev_overwrites is None: - log.info("Missing previous overwrites for #%s (%s); defaulting to None.", channel, channel.id) - overwrite.update( - send_messages=None, - add_reactions=None, - create_private_threads=None, - create_public_threads=None, - send_messages_in_threads=None, - speak=None, - connect=None - ) - else: - overwrite.update(**json.loads(prev_overwrites)) + + if prev_overwrites is None: + log.info("Missing previous overwrites for #%s (%s); defaulting to None.", channel, channel.id) + overwrite.update( + send_messages=None, + add_reactions=None, + create_private_threads=None, + create_public_threads=None, + send_messages_in_threads=None, + speak=None, + connect=None + ) + else: + overwrite.update(**json.loads(prev_overwrites)) + # Update Permissions - await channel.set_permissions(role, overwrite=overwrite) - if isinstance(channel, VoiceChannel): + await channel.set_permissions(role, overwrite=overwrite) + if isinstance(channel, VoiceChannel): await self._force_voice_sync(channel) - log.info("Unsilenced channel #%s (%s).", channel, channel.id) + log.info("Unsilenced channel #%s (%s).", channel, channel.id) self.scheduler.cancel(channel.id) self.notifier.remove_channel(channel) - await self.previous_overwrites.delete(channel.id) + if not isinstance(channel, Thread): + await self.previous_overwrites.delete(channel.id) await self.unsilence_timestamps.delete(channel.id) # Alert Admin team if old overwrites were not available - if prev_overwrites is None: - await self._mod_alerts_channel.send( - f"<@&{constants.Roles.admins}> Restored overwrites with default values after unsilencing " - f"{channel.mention}. Please check that the {permissions} " - f"overwrites for {role.mention} are at their desired values." - ) + if not isinstance(channel, Thread): + if prev_overwrites is None: + await self._mod_alerts_channel.send( + f"<@&{constants.Roles.admins}> Restored overwrites with default values after unsilencing " + f"{channel.mention}. Please check that the {permissions} " + f"overwrites for {role.mention} are at their desired values." + ) return True From bce34a20fdd394489ee91b3375a2f86df0591672 Mon Sep 17 00:00:00 2001 From: eldiablotyPY Date: Sun, 18 Oct 2026 07:11:54 +0200 Subject: [PATCH 2/2] Fix review suggestions in silence.py Mainly identention and embelishing the code. --- bot/exts/moderation/silence.py | 68 ++++++++++++++++------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py index edf7d963ee..4dc1ab4d73 100644 --- a/bot/exts/moderation/silence.py +++ b/bot/exts/moderation/silence.py @@ -182,15 +182,14 @@ async def silence( # The parent channel has to be muted or the thread should be archived. if isinstance(channel, Thread): if not channel.locked: - await channel.edit(locked=True) + await channel.edit(locked=True) else: - log.info("Thread already silenced!") + log.info("Thread already silenced!") + await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) + elif not await self._set_silence_overwrites(channel, kick=kick): + log.info("Tried to silence channel %s but the channel was already silenced.", channel_info) await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) - else: - if not await self._set_silence_overwrites(channel, kick=kick): - log.info("Tried to silence channel %s but the channel was already silenced.", channel_info) - await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) - return + return if isinstance(channel, VoiceChannel): if kick: @@ -325,7 +324,7 @@ async def _unsilence(self, channel: TextOrVoiceChannel) -> bool: """ # Get stored overwrites, and return if channel is unsilenced prev_overwrites = await self.previous_overwrites.get(channel.id) - if isinstance (channel, Thread): + if isinstance(channel, Thread): if not channel.locked and channel.id not in self.scheduler: log.info("You are trying to unsilence a thread but it's not silenced") return False @@ -336,13 +335,12 @@ async def _unsilence(self, channel: TextOrVoiceChannel) -> bool: # Select the role based on channel type, and get current overwrites if isinstance(channel, Thread): - await channel.edit(locked = False) - else: - if isinstance(channel, TextChannel): + await channel.edit(locked=False) + elif isinstance(channel, TextChannel): role = self._everyone_role overwrite = channel.overwrites_for(role) permissions = "`Send Messages` and `Add Reactions`" - else: + else: role = self._verified_voice_role overwrite = channel.overwrites_for(role) permissions = "`Speak` and `Connect`" @@ -351,27 +349,26 @@ async def _unsilence(self, channel: TextOrVoiceChannel) -> bool: # Check if old overwrites were not stored - if prev_overwrites is None: - log.info("Missing previous overwrites for #%s (%s); defaulting to None.", channel, channel.id) - overwrite.update( - send_messages=None, - add_reactions=None, - create_private_threads=None, - create_public_threads=None, - send_messages_in_threads=None, - speak=None, - connect=None - ) - else: - overwrite.update(**json.loads(prev_overwrites)) + if prev_overwrites is None: + log.info("Missing previous overwrites for #%s (%s); defaulting to None.", channel, channel.id) + overwrite.update( + send_messages=None, + add_reactions=None, + create_private_threads=None, + create_public_threads=None, + send_messages_in_threads=None, + speak=None, + connect=None + ) + else: + overwrite.update(**json.loads(prev_overwrites)) - # Update Permissions - await channel.set_permissions(role, overwrite=overwrite) - if isinstance(channel, VoiceChannel): + # Update Permissions + await channel.set_permissions(role, overwrite=overwrite) + if isinstance(channel, VoiceChannel): await self._force_voice_sync(channel) - - log.info("Unsilenced channel #%s (%s).", channel, channel.id) + log.info("Unsilenced channel #%s (%s).", channel, channel.id) self.scheduler.cancel(channel.id) self.notifier.remove_channel(channel) @@ -380,12 +377,11 @@ async def _unsilence(self, channel: TextOrVoiceChannel) -> bool: await self.unsilence_timestamps.delete(channel.id) # Alert Admin team if old overwrites were not available - if not isinstance(channel, Thread): - if prev_overwrites is None: - await self._mod_alerts_channel.send( - f"<@&{constants.Roles.admins}> Restored overwrites with default values after unsilencing " - f"{channel.mention}. Please check that the {permissions} " - f"overwrites for {role.mention} are at their desired values." + if not isinstance(channel, Thread) and prev_overwrites is None: + await self._mod_alerts_channel.send( + f"<@&{constants.Roles.admins}> Restored overwrites with default values after unsilencing " + f"{channel.mention}. Please check that the {permissions} " + f"overwrites for {role.mention} are at their desired values." ) return True