refactor (backend-rs): check_word_mute

Co-authored-by: naskya <m@naskya.net>
This commit is contained in:
sup39 2024-02-19 22:53:12 +09:00 committed by naskya
parent a7fc8f22c1
commit 9cd3d474ae
Signed by: naskya
GPG key ID: 712D413B3A9FED5C

View file

@ -1,10 +1,10 @@
use crate::database::JsDbConn; use crate::database::JsDbConn;
use crate::model::entity::{drive_file, note}; use crate::model::entity::{drive_file, note};
use crate::prelude::*;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use sea_orm::prelude::*; use sea_orm::prelude::*;
// FIXME: remove this type
#[napi_derive::napi(object)] #[napi_derive::napi(object)]
pub struct NoteLike { pub struct NoteLike {
pub file_ids: Vec<String>, pub file_ids: Vec<String>,
@ -15,82 +15,76 @@ pub struct NoteLike {
pub reply_id: Option<String>, pub reply_id: Option<String>,
} }
async fn full_text(conn: &JsDbConn, note: NoteLike) -> String { async fn all_texts(conn: &JsDbConn, note: NoteLike) -> napi::Result<Vec<String>> {
let mut to_return = format!( let mut texts: Vec<String> = vec![];
"{}\n{}\n",
note.text.unwrap_or_default(), if let Some(text) = note.text {
note.cw.unwrap_or_default(), texts.push(text);
); }
if let Some(cw) = note.cw {
texts.push(cw);
}
for file_id in note.file_ids { for file_id in note.file_ids {
if let Some(alt_text) = drive_file::Entity::find_by_id(file_id) if let Some(alt_text) = drive_file::Entity::find_by_id(file_id)
.one(conn.inner()) .one(conn.inner())
.await .await
.expect("Failed to connect to the database") .map_err(to_napi_error)?
.expect("file_id is invalid") .ok_or_else(|| to_napi_error("file_id is invalid"))?
.comment .comment
{ {
to_return.push_str(alt_text.as_str()); texts.push(alt_text);
to_return.push('\n');
} }
} }
if note.renote_id.is_some() { if let Some(renote_id) = note.renote_id {
to_return.push_str( if let Some(text) = note::Entity::find_by_id(renote_id)
note::Entity::find_by_id(note.renote_id.unwrap()) .one(conn.inner())
.one(conn.inner()) .await
.await .map_err(to_napi_error)?
.expect("Failed to connect to the database") .ok_or_else(|| to_napi_error("renote_id is invalid"))?
.expect("renote_id is invalid") .text
.text {
.unwrap_or_default() texts.push(text);
.as_str(), }
);
to_return.push('\n');
} }
if note.reply_id.is_some() { if let Some(reply_id) = note.reply_id {
to_return.push_str( if let Some(text) = note::Entity::find_by_id(reply_id)
note::Entity::find_by_id(note.reply_id.unwrap()) .one(conn.inner())
.one(conn.inner()) .await
.await .map_err(to_napi_error)?
.expect("Failed to connect to the database") .ok_or_else(|| to_napi_error("reply_id is invalid"))?
.expect("reply_id is invalid") .text
.text {
.unwrap_or_default() texts.push(text);
.as_str(), }
);
} }
to_return.trim().to_owned() Ok(texts)
} }
// FIXME: remove this funtion fn convert_regex(js_regex: &str) -> String {
fn convert_regex(js_regex: String) -> String {
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^/(.+)/(.*)$").unwrap()); static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^/(.+)/(.*)$").unwrap());
RE.replace(&js_regex, "(?$2)$1").to_string() RE.replace(js_regex, "(?$2)$1").to_string()
} }
async fn check_word_mute_impl( fn check_word_mute_impl(
text: String, texts: &[String],
muted_word_lists: Vec<Vec<String>>, muted_word_lists: &[Vec<String>],
muted_patterns: Vec<String>, muted_patterns: &[String],
) -> bool { ) -> bool {
if text.is_empty() { muted_word_lists.iter().any(|muted_word_list| {
return false; texts.iter().any(|text| {
} let text_lower = text.to_lowercase();
muted_word_list
let text_lowercase = text.to_lowercase(); .iter()
.all(|muted_word| text_lower.contains(muted_word))
muted_word_lists.into_iter().any(|muted_word_list| { })
muted_word_list }) || muted_patterns.iter().any(|muted_pattern| {
.into_iter() Regex::new(convert_regex(muted_pattern).as_str())
.all(|muted_word| text_lowercase.contains(&muted_word.to_lowercase())) .map(|re| texts.iter().any(|text| re.is_match(text)))
}) || muted_patterns.into_iter().any(|muted_patten| { .unwrap_or(false)
match Regex::new(convert_regex(muted_patten).as_str()) {
Ok(re) => re.is_match(&text),
Err(_) => false,
}
}) })
} }
@ -100,15 +94,14 @@ pub async fn check_word_mute(
note: NoteLike, note: NoteLike,
muted_word_lists: Vec<Vec<String>>, muted_word_lists: Vec<Vec<String>>,
muted_patterns: Vec<String>, muted_patterns: Vec<String>,
) -> bool { ) -> napi::Result<bool> {
if muted_word_lists.is_empty() && muted_patterns.is_empty() { if muted_word_lists.is_empty() && muted_patterns.is_empty() {
false Ok(false)
} else { } else {
check_word_mute_impl( Ok(check_word_mute_impl(
full_text(conn, note).await, &all_texts(conn, note).await?,
muted_word_lists, &muted_word_lists,
muted_patterns, &muted_patterns,
) ))
.await
} }
} }