Add no links rule

This commit is contained in:
2025-08-14 23:36:37 -03:00
parent 25b96cdc2a
commit deb76941ea
2 changed files with 85 additions and 34 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ pub fn first_warning_embed(
)
)
.title("Warning")
.description("You broke [Payphone's code of conduct](https://payphone.lat/code-of-conduct) during a call. Since it's your first offense, we assumed you didn't read the rules and made this a warning instead. Read the code of conduct to prevent getting banned.")
.description("You broke [Payphone's code of conduct](https://payphone.lat/code-of-conduct) during a call. Read the code of conduct to prevent getting banned.")
.field(EmbedFieldBuilder::new("What message broke the rules?", ellipse(message.content.clone(), 500)))
.field(EmbedFieldBuilder::new(
"What rules did you break?",
+84 -33
View File
@@ -85,6 +85,7 @@
use std::{collections::HashMap, sync::Arc};
use linkify::LinkFinder;
use once_cell::sync::Lazy;
use regex::Regex;
use twilight_model::gateway::payload::incoming::MessageCreate;
@@ -260,6 +261,10 @@ fn regex_from_phrases_list(phrases: &[&str]) -> Regex {
Regex::new(&pattern).expect("Failed to compile regex")
}
/// The results of the analysis of a rule, including all detections (on the original message first,
/// on the normalized message later) and the associated rule.
type RuleAnalysis = ((Vec<String>, Vec<String>), Arc<dyn Rule>);
/// Scans all rules on the message and returns the results for each rule which gave detections.
///
/// Arguments:
@@ -267,15 +272,18 @@ fn regex_from_phrases_list(phrases: &[&str]) -> Regex {
/// * `normalized` - The normalized version of the message.
///
/// Returns:
/// [`Vec<(Vec<String>, Arc<dyn Rule>)>`] - The results of the analysis, including all detections
/// and their associated rules.
pub fn analyze_message(original: &str, normalized: &str) -> Vec<(Vec<String>, Arc<dyn Rule>)> {
/// [`Vec<RuleAnalysis>`] - The results of the analysis, including all detections (on the original
/// message first, on the normalized message later) and their associated rules.
pub fn analyze_message(
original: &str,
normalized: &str,
) -> Vec<RuleAnalysis> {
let mut results = Vec::new();
for rule in RULES.iter() {
let detections = rule.detect(original, normalized);
if !detections.is_empty() {
results.push((detections, rule.clone()));
let (original_detections, normalized_detections) = rule.detect(original, normalized);
if !normalized_detections.is_empty() || !original_detections.is_empty() {
results.push(((original_detections, normalized_detections), rule.clone()));
}
}
@@ -295,15 +303,15 @@ pub fn analyze_message(original: &str, normalized: &str) -> Vec<(Vec<String>, Ar
pub fn censor_message(
original: &str,
normalized: NormalizedMessage,
analysis: &[(Vec<String>, Arc<dyn Rule>)],
analysis: &[RuleAnalysis],
) -> String {
let mut censored = original.to_string();
// Collect all ranges to censor
let mut ranges = Vec::new();
for (findings, _) in analysis {
for finding in findings {
for ((original_findings, normalized_findings), _) in analysis {
for finding in normalized_findings {
for (index, _) in normalized.message.match_indices(finding) {
let start_index = normalized.mappings.get(index).cloned().unwrap_or(0);
let end_index = normalized
@@ -315,6 +323,15 @@ pub fn censor_message(
ranges.push((start_index, end_index));
}
}
for finding in original_findings {
for (index, _) in original.match_indices(finding) {
let start_index = index;
let end_index = index + finding.len();
ranges.push((start_index, end_index));
}
}
}
// Sort ranges in reverse order to avoid shifting indices
@@ -380,10 +397,9 @@ pub trait Rule: Send + Sync {
/// * `normalized` - The normalized version of the message.
///
/// Returns:
/// [`Vec<String>`] - The list of detected rule violations in the normalized message.
///
/// TODO: Support detecting violations in the original message.
fn detect(&self, original: &str, normalized: &str) -> Vec<String>;
/// [`(Vec<String>, Vec<String>)`] - The list of detected rule violations in the original
/// (first vector) and normalized (second vector) message.
fn detect(&self, original: &str, normalized: &str) -> (Vec<String>, Vec<String>);
}
/// Parses a file containing phrases to be detected by rules.
@@ -429,11 +445,14 @@ impl Rule for HateSpeechAndSlursRule {
&Action::BlockAndPenalty
}
fn detect(&self, _original: &str, normalized: &str) -> Vec<String> {
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect()
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
(
vec![],
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect(),
)
}
}
@@ -459,11 +478,14 @@ impl Rule for ThreatsAndSelfHarmRule {
&Action::BlockAndPenalty
}
fn detect(&self, _original: &str, normalized: &str) -> Vec<String> {
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect()
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
(
vec![],
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect(),
)
}
}
@@ -489,11 +511,14 @@ impl Rule for ExplicitSexualLanguageRule {
"Explicit Sexual Language"
}
fn detect(&self, _original: &str, normalized: &str) -> Vec<String> {
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect()
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
(
vec![],
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect(),
)
}
}
@@ -518,11 +543,36 @@ impl Rule for SuggestiveLanguageRule {
"Suggestive Language"
}
fn detect(&self, _original: &str, normalized: &str) -> Vec<String> {
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect()
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
(
vec![],
self.0
.find_iter(normalized)
.map(|m| normalized[m.start()..m.end()].to_string())
.collect(),
)
}
}
struct LinksRule;
impl Rule for LinksRule {
fn name(&self) -> &'static str {
"Links"
}
fn action(&self) -> &'static Action {
&Action::SoftCensorAndWarn
}
fn detect(&self, original: &str, _normalized: &str) -> (Vec<String>, Vec<String>) {
let mut detections = Vec::new();
for link in LinkFinder::new().url_must_have_scheme(false).links(original) {
detections.push(link.as_str().to_string());
}
(detections, vec![])
}
}
@@ -533,5 +583,6 @@ pub static RULES: Lazy<Vec<Arc<dyn Rule>>> = Lazy::new(|| {
Arc::new(ThreatsAndSelfHarmRule::new()),
Arc::new(SuggestiveLanguageRule::new()),
Arc::new(ExplicitSexualLanguageRule::new()),
Arc::new(LinksRule),
]
});