From 7d84cb875553cb99342323f25d2ce155fb27c0f9 Mon Sep 17 00:00:00 2001 From: wookie184 Date: Tue, 16 Apr 2024 15:00:49 +0100 Subject: Make watched_users a dict, not a defaultdict This prevents accidentally creating new values when accessing a key --- bot/exts/moderation/watchchannels/_watchchannel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 71600e9df..7668f4e24 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -62,7 +62,7 @@ class WatchChannel(metaclass=CogABCMeta): self.log = logger # Logger of the child cog for a correct name in the logs self._consume_task = None - self.watched_users = defaultdict(dict) + self.watched_users = {} self.message_queue = defaultdict(lambda: defaultdict(deque)) self.consumption_queue = {} self.retries = 5 @@ -154,7 +154,7 @@ class WatchChannel(metaclass=CogABCMeta): self.log.exception("Failed to fetch the watched users from the API", exc_info=err) return False - self.watched_users = defaultdict(dict) + self.watched_users.clear() for entry in data: user_id = entry.pop("user") -- cgit v1.2.3 From fb2101826d552f7412cbb0e1b9a2e46264e9ceee Mon Sep 17 00:00:00 2001 From: wookie184 Date: Tue, 16 Apr 2024 15:07:55 +0100 Subject: Check if user is watched before sending message instead of popping from message queues when unwatching This prevents the message queues being modified as they are being iterated over which caused errors --- bot/exts/moderation/watchchannels/_watchchannel.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 7668f4e24..16d2fdcbf 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -185,13 +185,16 @@ class WatchChannel(metaclass=CogABCMeta): self.consumption_queue = self.message_queue.copy() self.message_queue.clear() - for user_channel_queues in self.consumption_queue.values(): - for channel_queue in user_channel_queues.values(): + for user_id, channel_queues in self.consumption_queue.values(): + for channel_queue in channel_queues.values(): while channel_queue: msg = channel_queue.popleft() - self.log.trace(f"Consuming message {msg.id} ({len(msg.attachments)} attachments)") - await self.relay_message(msg) + if watch_info := self.watched_users.get(user_id, None): + self.log.trace(f"Consuming message {msg.id} ({len(msg.attachments)} attachments)") + await self.relay_message(msg) + else: + self.log.trace(f"Not consuming message {msg.id} as user {user_id} is no longer watched.") self.consumption_queue.clear() @@ -366,8 +369,6 @@ class WatchChannel(metaclass=CogABCMeta): def _remove_user(self, user_id: int) -> None: """Removes a user from a watch channel.""" self.watched_users.pop(user_id, None) - self.message_queue.pop(user_id, None) - self.consumption_queue.pop(user_id, None) async def cog_unload(self) -> None: """Takes care of unloading the cog and canceling the consumption task.""" -- cgit v1.2.3 From 36f335ff67686f1cd63c86a4c7d072b16b033d11 Mon Sep 17 00:00:00 2001 From: wookie184 Date: Tue, 16 Apr 2024 15:27:34 +0100 Subject: Pass watch info through to functions to avoid KeyError if user is unwatched --- bot/exts/moderation/watchchannels/_watchchannel.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 16d2fdcbf..2a460e316 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -192,7 +192,7 @@ class WatchChannel(metaclass=CogABCMeta): if watch_info := self.watched_users.get(user_id, None): self.log.trace(f"Consuming message {msg.id} ({len(msg.attachments)} attachments)") - await self.relay_message(msg) + await self.relay_message(msg, watch_info) else: self.log.trace(f"Not consuming message {msg.id} as user {user_id} is no longer watched.") @@ -221,7 +221,7 @@ class WatchChannel(metaclass=CogABCMeta): exc_info=exc ) - async def relay_message(self, msg: Message) -> None: + async def relay_message(self, msg: Message, watch_info: dict) -> None: """Relays the message to the relevant watch channel.""" limit = BigBrotherConfig.header_message_limit @@ -232,7 +232,7 @@ class WatchChannel(metaclass=CogABCMeta): ): self.message_history = MessageHistory(last_author=msg.author.id, last_channel=msg.channel.id) - await self.send_header(msg) + await self.send_header(msg, watch_info) if DiscordTokenFilter.find_token_in_message(msg.content) or WEBHOOK_URL_RE.search(msg.content): cleaned_content = "Content is censored because it contains a bot or webhook token." @@ -271,21 +271,19 @@ class WatchChannel(metaclass=CogABCMeta): self.message_history.message_count += 1 - async def send_header(self, msg: Message) -> None: + async def send_header(self, msg: Message, watch_info: dict) -> None: """Sends a header embed with information about the relayed messages to the watch channel.""" if self.disable_header: return - user_id = msg.author.id - guild = self.bot.get_guild(GuildConfig.id) - actor = await get_or_fetch_member(guild, self.watched_users[user_id]["actor"]) - actor = actor.display_name if actor else self.watched_users[user_id]["actor"] + actor = await get_or_fetch_member(guild, watch_info["actor"]) + actor = actor.display_name if actor else watch_info["actor"] - inserted_at = self.watched_users[user_id]["inserted_at"] + inserted_at = watch_info["inserted_at"] time_delta = time.format_relative(inserted_at) - reason = self.watched_users[user_id]["reason"] + reason = watch_info["reason"] if isinstance(msg.channel, DMChannel): # If a watched user DMs the bot there won't be a channel name or jump URL -- cgit v1.2.3 From bfd9e446d4d242dd8948057ed3e29faaa699267f Mon Sep 17 00:00:00 2001 From: wookie184 Date: Tue, 16 Apr 2024 15:31:50 +0100 Subject: Fix: dict.values() -> dict.items() --- bot/exts/moderation/watchchannels/_watchchannel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 2a460e316..768d0afb3 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -185,7 +185,7 @@ class WatchChannel(metaclass=CogABCMeta): self.consumption_queue = self.message_queue.copy() self.message_queue.clear() - for user_id, channel_queues in self.consumption_queue.values(): + for user_id, channel_queues in self.consumption_queue.items(): for channel_queue in channel_queues.values(): while channel_queue: msg = channel_queue.popleft() -- cgit v1.2.3 From 25acba42f18b7f5ef813dd7ed5d62cead9f3940b Mon Sep 17 00:00:00 2001 From: wookie184 Date: Thu, 18 Jul 2024 23:04:28 +0200 Subject: Copy watched_users into list to prevent modification while iterating --- bot/exts/moderation/watchchannels/_watchchannel.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 768d0afb3..44c0be2a7 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -344,12 +344,13 @@ class WatchChannel(metaclass=CogABCMeta): update_cache = False list_data["updated"] = update_cache - watched_iter = self.watched_users.items() + # Copy into list to prevent issues if it is modified elsewhere while it's being iterated over. + watched_list = list(self.watched_users.items()) if oldest_first: - watched_iter = reversed(watched_iter) + watched_list.reverse() list_data["info"] = {} - for user_id, user_data in watched_iter: + for user_id, user_data in watched_list: member = await get_or_fetch_member(ctx.guild, user_id) line = f"- `{user_id}`" if member: -- cgit v1.2.3