Use mention tag name instead of href when parsing incoming notes

This commit is contained in:
silverpill 2021-12-18 01:09:43 +00:00
parent 2df7f7ced7
commit d31d315517
3 changed files with 36 additions and 16 deletions

View file

@ -9,7 +9,7 @@ use crate::config::{Config, Instance};
use crate::database::{Pool, get_database_client}; use crate::database::{Pool, get_database_client};
use crate::errors::{DatabaseError, HttpError, ValidationError}; use crate::errors::{DatabaseError, HttpError, ValidationError};
use crate::models::attachments::queries::create_attachment; use crate::models::attachments::queries::create_attachment;
use crate::models::posts::types::{Post, PostCreateData, Visibility}; use crate::models::posts::mentions::mention_to_acct;
use crate::models::posts::queries::{ use crate::models::posts::queries::{
create_post, create_post,
get_post_by_id, get_post_by_id,
@ -17,6 +17,7 @@ use crate::models::posts::queries::{
delete_post, delete_post,
}; };
use crate::models::posts::tags::normalize_tag; use crate::models::posts::tags::normalize_tag;
use crate::models::posts::types::{Post, PostCreateData, Visibility};
use crate::models::profiles::queries::{ use crate::models::profiles::queries::{
get_profile_by_actor_id, get_profile_by_actor_id,
get_profile_by_acct, get_profile_by_acct,
@ -241,13 +242,9 @@ pub async fn process_note(
tags.push(tag_name); tags.push(tag_name);
}; };
} else if tag.tag_type == MENTION { } else if tag.tag_type == MENTION {
if let Some(href) = tag.href { // Ignore invalid mentions
let profile = get_or_fetch_profile_by_actor_id( if let Ok(acct) = mention_to_acct(&instance.host(), &tag.name) {
db_client, let profile = get_profile_by_acct(db_client, &acct).await?;
&instance,
&href,
&config.media_dir(),
).await?;
if !mentions.contains(&profile.id) { if !mentions.contains(&profile.id) {
mentions.push(profile.id); mentions.push(profile.id);
}; };

View file

@ -3,11 +3,12 @@ use std::collections::HashMap;
use regex::{Captures, Regex}; use regex::{Captures, Regex};
use tokio_postgres::GenericClient; use tokio_postgres::GenericClient;
use crate::errors::DatabaseError; use crate::errors::{DatabaseError, ValidationError};
use crate::models::profiles::queries::get_profiles_by_accts; use crate::models::profiles::queries::get_profiles_by_accts;
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
const MENTION_RE: &str = r"(?m)(?P<space>^|\s)@(?P<user>\w+)@(?P<instance>\S+)"; const MENTION_RE: &str = r"@?(?P<user>\w+)@(?P<instance>.+)";
const MENTION_SEARCH_RE: &str = r"(?m)(?P<space>^|\s)@(?P<user>\w+)@(?P<instance>\S+)";
fn pattern_to_acct(caps: &Captures, instance_host: &str) -> String { fn pattern_to_acct(caps: &Captures, instance_host: &str) -> String {
if &caps["instance"] == instance_host { if &caps["instance"] == instance_host {
@ -22,7 +23,7 @@ fn find_mentions(
instance_host: &str, instance_host: &str,
text: &str, text: &str,
) -> Vec<String> { ) -> Vec<String> {
let mention_re = Regex::new(MENTION_RE).unwrap(); let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap();
let mut mentions = vec![]; let mut mentions = vec![];
for caps in mention_re.captures_iter(text) { for caps in mention_re.captures_iter(text) {
let acct = pattern_to_acct(&caps, instance_host); let acct = pattern_to_acct(&caps, instance_host);
@ -53,12 +54,13 @@ pub fn replace_mentions(
instance_url: &str, instance_url: &str,
text: &str, text: &str,
) -> String { ) -> String {
let mention_re = Regex::new(MENTION_RE).unwrap(); let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap();
let result = mention_re.replace_all(text, |caps: &Captures| { let result = mention_re.replace_all(text, |caps: &Captures| {
let acct = pattern_to_acct(caps, instance_host); let acct = pattern_to_acct(caps, instance_host);
match mention_map.get(&acct) { match mention_map.get(&acct) {
Some(profile) => { Some(profile) => {
// Replace with a link // Replace with a link to profile.
// Actor URL may differ from actor ID.
let url = profile.actor_url(instance_url).unwrap(); let url = profile.actor_url(instance_url).unwrap();
format!( format!(
// https://microformats.org/wiki/h-card // https://microformats.org/wiki/h-card
@ -74,6 +76,17 @@ pub fn replace_mentions(
result.to_string() result.to_string()
} }
pub fn mention_to_acct(
instance_host: &str,
mention: &str,
) -> Result<String, ValidationError> {
let mention_re = Regex::new(MENTION_RE).unwrap();
let mention_caps = mention_re.captures(mention)
.ok_or(ValidationError("invalid mention tag"))?;
let acct = pattern_to_acct(&mention_caps, instance_host);
Ok(acct)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::json; use serde_json::json;
@ -131,4 +144,14 @@ mod tests {
); );
assert_eq!(result, expected_result); assert_eq!(result, expected_result);
} }
#[test]
fn test_mention_to_acct() {
let mention = "@user@example.com";
let acct_1 = mention_to_acct("example.com", mention).unwrap();
assert_eq!(acct_1, "user");
let acct_2 = mention_to_acct("server.info", mention).unwrap();
assert_eq!(acct_2, "user@example.com");
}
} }

View file

@ -1,6 +1,6 @@
use regex::{Captures, Regex}; use regex::{Captures, Regex};
use crate::errors::ConversionError; use crate::errors::ValidationError;
use crate::frontend::get_tag_page_url; use crate::frontend::get_tag_page_url;
const HASHTAG_RE: &str = r"(?m)(?P<before>^|\s)#(?P<tag>\S+)"; const HASHTAG_RE: &str = r"(?m)(?P<before>^|\s)#(?P<tag>\S+)";
@ -52,11 +52,11 @@ pub fn replace_tags(instance_url: &str, text: &str, tags: &[String]) -> String {
result.to_string() result.to_string()
} }
pub fn normalize_tag(tag: &str) -> Result<String, ConversionError> { pub fn normalize_tag(tag: &str) -> Result<String, ValidationError> {
let hashtag_name_re = Regex::new(HASHTAG_NAME_RE).unwrap(); let hashtag_name_re = Regex::new(HASHTAG_NAME_RE).unwrap();
let tag_name = tag.trim_start_matches('#'); let tag_name = tag.trim_start_matches('#');
if !hashtag_name_re.is_match(tag_name) { if !hashtag_name_re.is_match(tag_name) {
return Err(ConversionError); return Err(ValidationError("invalid tag name"));
}; };
Ok(tag_name.to_lowercase()) Ok(tag_name.to_lowercase())
} }