Use mention tag name instead of href when parsing incoming notes
This commit is contained in:
parent
2df7f7ced7
commit
d31d315517
3 changed files with 36 additions and 16 deletions
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue