Add no links rule
This commit is contained in:
@@ -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?",
|
||||
|
||||
@@ -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),
|
||||
]
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user