diff options
-rw-r--r-- | bot/exts/filtering/_filter_context.py | 4 | ||||
-rw-r--r-- | bot/exts/filtering/_filter_lists/antispam.py | 18 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/actions/remove_context.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_ui/ui.py | 17 |
4 files changed, 28 insertions, 13 deletions
diff --git a/bot/exts/filtering/_filter_context.py b/bot/exts/filtering/_filter_context.py index 9faa16b53..f5f635f9c 100644 --- a/bot/exts/filtering/_filter_context.py +++ b/bot/exts/filtering/_filter_context.py @@ -44,11 +44,13 @@ class FilterContext: matches: list[str] = field(default_factory=list) # What exactly was found notification_domain: str = "" # A domain to send the user for context filter_info: dict['Filter', str] = field(default_factory=dict) # Additional info from a filter. + messages_deletion: bool = False # Whether the messages were deleted. Can't upload deletion log otherwise. # Additional actions to perform additional_actions: list[Callable[[FilterContext], Coroutine]] = field(default_factory=list) - related_messages: set[Message] = field(default_factory=set) + related_messages: set[Message] = field(default_factory=set) # Deletion will include these. related_channels: set[TextChannel | Thread | DMChannel] = field(default_factory=set) attachments: dict[int, list[str]] = field(default_factory=dict) # Message ID to attachment URLs. + upload_deletion_logs: bool = True # Whether it's allowed to upload deletion logs. @classmethod def from_message( diff --git a/bot/exts/filtering/_filter_lists/antispam.py b/bot/exts/filtering/_filter_lists/antispam.py index 147998c1c..c5ce292e3 100644 --- a/bot/exts/filtering/_filter_lists/antispam.py +++ b/bot/exts/filtering/_filter_lists/antispam.py @@ -77,17 +77,23 @@ class AntispamList(UniquesListBase): self.message_deletion_queue[ctx.author] = DeletionContext() ctx.additional_actions.append(self._create_deletion_context_handler(ctx.author)) ctx.related_channels |= {msg.channel for msg in ctx.related_messages} - else: # The additional messages found are already part of the deletion context + else: # The additional messages found are already part of a deletion context ctx.related_messages = set() current_infraction = self.message_deletion_queue[ctx.author].current_infraction + # In case another filter wants an alert, prevent deleted messages from being uploaded now and also for + # the spam alert (upload happens during alerting). + # Deleted messages API doesn't accept duplicates and will error. + # Additional messages are necessarily part of the deletion. + ctx.upload_deletion_logs = False self.message_deletion_queue[ctx.author].add(ctx, triggers) - current_actions = sublist.merge_actions(triggers) if triggers else None + current_actions = sublist.merge_actions(triggers) # Don't alert yet. current_actions.pop("ping", None) current_actions.pop("send_alert", None) + new_infraction = current_actions["infraction_and_notification"].copy() - # Smaller infraction value = higher in hierarchy. + # Smaller infraction value => higher in hierarchy. if not current_infraction or new_infraction.infraction_type.value < current_infraction.value: # Pick the first triggered filter for the reason, there's no good way to decide between them. new_infraction.infraction_reason = ( @@ -161,11 +167,13 @@ class DeletionContext: new_ctx.action_descriptions[-1] += f" (+{descriptions_num - 20} other actions)" new_ctx.related_messages = reduce( or_, (other_ctx.related_messages for other_ctx in other_contexts), ctx.related_messages - ) + ) | {ctx.message for ctx in other_contexts} new_ctx.related_channels = reduce( or_, (other_ctx.related_channels for other_ctx in other_contexts), ctx.related_channels - ) + ) | {ctx.channel for ctx in other_contexts} new_ctx.attachments = reduce(or_, (other_ctx.attachments for other_ctx in other_contexts), ctx.attachments) + new_ctx.upload_deletion_logs = True + new_ctx.messages_deletion = all(ctx.messages_deletion for ctx in self.contexts) rules = list(self.rules) actions = antispam_list[ListType.DENY].merge_actions(rules) diff --git a/bot/exts/filtering/_settings_types/actions/remove_context.py b/bot/exts/filtering/_settings_types/actions/remove_context.py index e030f06d2..a34822542 100644 --- a/bot/exts/filtering/_settings_types/actions/remove_context.py +++ b/bot/exts/filtering/_settings_types/actions/remove_context.py @@ -59,6 +59,8 @@ class RemoveContext(ActionEntry): if not ctx.message or not ctx.message.guild: return + # If deletion somehow fails at least this will allow scheduling for deletion. + ctx.messages_deletion = True channel_messages = defaultdict(set) # Duplicates will cause batch deletion to fail. for message in {ctx.message} | ctx.related_messages: channel_messages[message.channel].add(message) diff --git a/bot/exts/filtering/_ui/ui.py b/bot/exts/filtering/_ui/ui.py index dc996faf7..24fb507e3 100644 --- a/bot/exts/filtering/_ui/ui.py +++ b/bot/exts/filtering/_ui/ui.py @@ -57,22 +57,25 @@ T = TypeVar('T') async def _build_alert_message_content(ctx: FilterContext, current_message_length: int) -> str: """Build the content section of the alert.""" # For multiple messages and those with attachments or excessive newlines, use the logs API - if any(( + if ctx.messages_deletion and ctx.upload_deletion_logs and any(( ctx.related_messages, len(ctx.attachments) > 0, ctx.content.count('\n') > 15 )): url = await upload_log(ctx.related_messages, bot.instance.user.id, ctx.attachments) - alert_content = f"A complete log of the offending messages can be found [here]({url})" - else: - alert_content = escape_markdown(ctx.content) - remaining_chars = MAX_EMBED_DESCRIPTION - current_message_length + return f"A complete log of the offending messages can be found [here]({url})" + + alert_content = escape_markdown(ctx.content) + remaining_chars = MAX_EMBED_DESCRIPTION - current_message_length - if len(alert_content) > remaining_chars: + if len(alert_content) > remaining_chars: + if ctx.messages_deletion and ctx.upload_deletion_logs: url = await upload_log([ctx.message], bot.instance.user.id, ctx.attachments) log_site_msg = f"The full message can be found [here]({url})" # 7 because that's the length of "[...]\n\n" - alert_content = alert_content[:remaining_chars - (7 + len(log_site_msg))] + "[...]\n\n" + log_site_msg + return alert_content[:remaining_chars - (7 + len(log_site_msg))] + "[...]\n\n" + log_site_msg + else: + return alert_content[:remaining_chars - 5] + "[...]" return alert_content |