Add support for banned word exceptions
This commit is contained in:
Generated
+1
-1
@@ -1431,7 +1431,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "payphone"
|
name = "payphone"
|
||||||
version = "4.0.9"
|
version = "4.0.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "payphone"
|
name = "payphone"
|
||||||
version = "4.0.9"
|
version = "4.0.11"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
default-run = "payphone"
|
default-run = "payphone"
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
tasks:
|
tasks:
|
||||||
- name: Bump Version
|
- name: Bump Version
|
||||||
ansible.builtin.shell: >
|
ansible.builtin.shell: >
|
||||||
cargo release commit --execute --no-confirm && \
|
cargo set-version --bump patch
|
||||||
cargo release patch --no-verify --no-publish --execute --no-confirm
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Get Cargo Project Metadata
|
- name: Get Cargo Project Metadata
|
||||||
|
|||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
uv run ansible-playbook -i inventory.ini playbooks/08-payphone.yml --vault-password-file playbooks/00-vault-pwd.txt
|
||||||
@@ -59,7 +59,7 @@ huz
|
|||||||
slut
|
slut
|
||||||
dldo
|
dldo
|
||||||
dildo
|
dildo
|
||||||
goon
|
goon / go on
|
||||||
gooning
|
gooning
|
||||||
i will fuh you
|
i will fuh you
|
||||||
i will fuck you
|
i will fuck you
|
||||||
|
|||||||
+187
-47
@@ -247,7 +247,7 @@ fn regex_from_phrase(phrase: &str) -> String {
|
|||||||
///
|
///
|
||||||
/// Returns:
|
/// Returns:
|
||||||
/// [`Regex`] - The merged regex for the phrases.
|
/// [`Regex`] - The merged regex for the phrases.
|
||||||
fn regex_from_phrases_list(phrases: &[&str]) -> Regex {
|
fn regex_from_phrases_list(phrases: &[String]) -> Regex {
|
||||||
let mut pattern = String::new();
|
let mut pattern = String::new();
|
||||||
|
|
||||||
for phrase in phrases {
|
for phrase in phrases {
|
||||||
@@ -405,31 +405,43 @@ pub trait Rule: Send + Sync {
|
|||||||
/// * `file_content` - The content of the file to parse.
|
/// * `file_content` - The content of the file to parse.
|
||||||
///
|
///
|
||||||
/// Returns:
|
/// Returns:
|
||||||
/// [`Vec<&str>`] - The list of phrases found in the file.
|
/// [`(Vec<String>, Vec<String>)`] - The list of phrases found in the file.
|
||||||
fn parse_phrases_file(file_content: &str) -> Vec<&str> {
|
fn parse_phrases_file(file_content: &str) -> (Vec<String>, Vec<String>) {
|
||||||
file_content
|
let mut banned = vec![];
|
||||||
.lines()
|
let mut exceptions = vec![];
|
||||||
.filter_map(|line| {
|
|
||||||
let trimmed = line.trim();
|
for line in file_content.lines() {
|
||||||
if !trimmed.is_empty() && !trimmed.starts_with("//") {
|
let trimmed = line.trim().to_ascii_lowercase();
|
||||||
Some(trimmed)
|
|
||||||
|
if !trimmed.is_empty() && !trimmed.starts_with("//") {
|
||||||
|
if let Some((phrase, phrase_exceptions)) = trimmed.split_once("/") {
|
||||||
|
banned.push(phrase.trim().to_string());
|
||||||
|
exceptions.extend(phrase_exceptions.split(',').map(|s| s.trim().to_string()));
|
||||||
} else {
|
} else {
|
||||||
None
|
banned.push(trimmed.to_string());
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect()
|
}
|
||||||
|
|
||||||
|
(banned, exceptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HateSpeechAndSlursRule(Regex);
|
struct HateSpeechAndSlursRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl HateSpeechAndSlursRule {
|
impl HateSpeechAndSlursRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> =
|
let (phrases, exceptions) =
|
||||||
parse_phrases_file(include_str!("lists/hate-speech-and-slurs.txt"));
|
parse_phrases_file(include_str!("lists/hate-speech-and-slurs.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,24 +457,43 @@ impl Rule for HateSpeechAndSlursRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ThreatsAndSelfHarmRule(Regex);
|
struct ThreatsAndSelfHarmRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ThreatsAndSelfHarmRule {
|
impl ThreatsAndSelfHarmRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> =
|
let (phrases, exceptions) =
|
||||||
parse_phrases_file(include_str!("lists/threats-and-self-harm.txt"));
|
parse_phrases_file(include_str!("lists/threats-and-self-harm.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,24 +509,43 @@ impl Rule for ThreatsAndSelfHarmRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExplicitSexualLanguageRule(Regex);
|
struct ExplicitSexualLanguageRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ExplicitSexualLanguageRule {
|
impl ExplicitSexualLanguageRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> =
|
let (phrases, exceptions) =
|
||||||
parse_phrases_file(include_str!("lists/explicit-sexual-language.txt"));
|
parse_phrases_file(include_str!("lists/explicit-sexual-language.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,23 +561,43 @@ impl Rule for ExplicitSexualLanguageRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SuggestiveLanguageRule(Regex);
|
struct SuggestiveLanguageRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl SuggestiveLanguageRule {
|
impl SuggestiveLanguageRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> = parse_phrases_file(include_str!("lists/suggestive-language.txt"));
|
let (phrases, exceptions) =
|
||||||
|
parse_phrases_file(include_str!("lists/suggestive-language.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,9 +613,22 @@ impl Rule for SuggestiveLanguageRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -580,17 +663,23 @@ impl Rule for AdvertisingRule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SensitiveTopicsAndTriggeringContentRule(Regex);
|
struct SensitiveTopicsAndTriggeringContentRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl SensitiveTopicsAndTriggeringContentRule {
|
impl SensitiveTopicsAndTriggeringContentRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> = parse_phrases_file(include_str!(
|
let (phrases, exceptions) = parse_phrases_file(include_str!(
|
||||||
"lists/sensitive-topics-and-triggering-content.txt"
|
"lists/sensitive-topics-and-triggering-content.txt"
|
||||||
));
|
));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,23 +695,42 @@ impl Rule for SensitiveTopicsAndTriggeringContentRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MildSwearWordsRule(Regex);
|
pub struct MildSwearWordsRule {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MildSwearWordsRule {
|
impl MildSwearWordsRule {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> = parse_phrases_file(include_str!("lists/mild-swear-words.txt"));
|
let (phrases, exceptions) = parse_phrases_file(include_str!("lists/mild-swear-words.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,24 +746,43 @@ impl Rule for MildSwearWordsRule {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CasualInsultsAndTeasing(Regex);
|
pub struct CasualInsultsAndTeasing {
|
||||||
|
pattern: Regex,
|
||||||
|
exceptions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl CasualInsultsAndTeasing {
|
impl CasualInsultsAndTeasing {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let phrases: Vec<&str> =
|
let (phrases, exceptions) =
|
||||||
parse_phrases_file(include_str!("lists/casual-insults-and-teasing.txt"));
|
parse_phrases_file(include_str!("lists/casual-insults-and-teasing.txt"));
|
||||||
|
|
||||||
let regex = regex_from_phrases_list(&phrases);
|
let regex = regex_from_phrases_list(&phrases);
|
||||||
|
|
||||||
Self(regex)
|
Self {
|
||||||
|
pattern: regex,
|
||||||
|
exceptions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,9 +798,22 @@ impl Rule for CasualInsultsAndTeasing {
|
|||||||
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
|
||||||
(
|
(
|
||||||
vec![],
|
vec![],
|
||||||
self.0
|
self.pattern
|
||||||
.find_iter(normalized)
|
.find_iter(normalized)
|
||||||
.map(|m| normalized[m.start()..m.end()].to_string())
|
.filter_map(|m| {
|
||||||
|
let string = normalized[m.start()..m.end()].to_string();
|
||||||
|
|
||||||
|
if self.exceptions.contains(
|
||||||
|
&string
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.collect::<String>()
|
||||||
|
.to_ascii_lowercase(),
|
||||||
|
) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(string)
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user