Allow brackets around hashtags and mentions

This commit is contained in:
silverpill 2022-08-03 20:25:04 +00:00
parent 272ee9997b
commit ce694cb88c
2 changed files with 51 additions and 40 deletions

View file

@ -10,8 +10,8 @@ use crate::models::profiles::types::DbActorProfile;
// See also: USERNAME_RE in models::profiles::validators // See also: USERNAME_RE in models::profiles::validators
const MENTION_RE: &str = r"@?(?P<user>[\w\.-]+)@(?P<instance>.+)"; const MENTION_RE: &str = r"@?(?P<user>[\w\.-]+)@(?P<instance>.+)";
const MENTION_SEARCH_RE: &str = r"(?m)(?P<before>^|\s)@(?P<user>[\w\.-]+)@(?P<instance>\S+)"; const MENTION_SEARCH_RE: &str = r"(?m)(?P<before>^|\s|[\(])@(?P<user>[\w\.-]+)@(?P<instance>\S+)";
const MENTION_SEARCH_SECONDARY_RE: &str = r"^(?P<instance>[\w\.-]+\w)(?P<after>(\.|<br>|\.<br>)?)$"; const MENTION_SEARCH_SECONDARY_RE: &str = r"^(?P<instance>[\w\.-]+\w)(?P<after>[\.,:?\)]?(<br>)?)$";
/// Finds everything that looks like a mention /// Finds everything that looks like a mention
fn find_mentions( fn find_mentions(
@ -109,22 +109,24 @@ mod tests {
const INSTANCE_HOST: &str = "server1.com"; const INSTANCE_HOST: &str = "server1.com";
const INSTANCE_URL: &str = "https://server1.com"; const INSTANCE_URL: &str = "https://server1.com";
const TEXT_WITH_MENTIONS: &str = concat!(
"@user1@server1.com ",
"(@user2@server2.com boosted) ",
"@user3@server2.com.\n",
"@@invalid@server2.com ",
"@test@server3.com@nospace@server4.com ",
"@notmention email@unknown.org ",
"@user2@server2.com copy ",
"some text",
);
#[test] #[test]
fn test_find_mentions() { fn test_find_mentions() {
let text = concat!( let results = find_mentions(INSTANCE_HOST, TEXT_WITH_MENTIONS);
"@user1@server1.com ",
"@user2@server2.com ",
"@@invalid@server2.com ",
"@test@server3.com@nospace@server4.com ",
"@notmention ",
"@user2@server2.com copy ",
"some text",
);
let results = find_mentions(INSTANCE_HOST, text);
assert_eq!(results, vec![ assert_eq!(results, vec![
"user1", "user1",
"user2@server2.com", "user2@server2.com",
"user3@server2.com",
]); ]);
} }
@ -135,7 +137,7 @@ mod tests {
username: "user1".to_string(), username: "user1".to_string(),
..Default::default() ..Default::default()
}; };
// Remote actor // Remote actors
let profile_2 = DbActorProfile { let profile_2 = DbActorProfile {
username: "user2".to_string(), username: "user2".to_string(),
actor_json: Some(Actor { actor_json: Some(Actor {
@ -145,20 +147,33 @@ mod tests {
}), }),
..Default::default() ..Default::default()
}; };
let text = concat!( let profile_3 = DbActorProfile {
"@user1@server1.com @user2@server2.com.\n", username: "user3".to_string(),
"sometext @notmention @test@unknown.org" actor_json: Some(Actor {
); id: "https://server2.com/actors/user3".to_string(),
url: Some("https://server2.com/@user3".to_string()),
..Default::default()
}),
..Default::default()
};
let mention_map = HashMap::from([ let mention_map = HashMap::from([
("user1".to_string(), profile_1), ("user1".to_string(), profile_1),
("user2@server2.com".to_string(), profile_2), ("user2@server2.com".to_string(), profile_2),
("user3@server2.com".to_string(), profile_3),
]); ]);
let result = replace_mentions(&mention_map, INSTANCE_HOST, INSTANCE_URL, text); let result = replace_mentions(
&mention_map,
INSTANCE_HOST,
INSTANCE_URL,
TEXT_WITH_MENTIONS,
);
let expected_result = concat!( let expected_result = concat!(
r#"<span class="h-card"><a class="u-url mention" href="https://server1.com/users/user1">@user1</a></span> "#, r#"<span class="h-card"><a class="u-url mention" href="https://server1.com/users/user1">@user1</a></span> "#,
r#"<span class="h-card"><a class="u-url mention" href="https://server2.com/@user2">@user2</a></span>."#, "\n", r#"(<span class="h-card"><a class="u-url mention" href="https://server2.com/@user2">@user2</a></span> boosted) "#,
r#"sometext @notmention @test@unknown.org"#, r#"<span class="h-card"><a class="u-url mention" href="https://server2.com/@user3">@user3</a></span>."#, "\n",
r#"@@invalid@server2.com @test@server3.com@nospace@server4.com "#,
r#"@notmention email@unknown.org <span class="h-card"><a class="u-url mention" href="https://server2.com/@user2">@user2</a></span> copy some text"#,
); );
assert_eq!(result, expected_result); assert_eq!(result, expected_result);
} }

View file

@ -3,8 +3,8 @@ use regex::{Captures, Regex};
use crate::errors::ValidationError; 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+)";
const HASHTAG_SECONDARY_RE: &str = r"^(?P<tag>[0-9A-Za-z]+)(?P<after>[\.,:?]?(<br>)?)$"; const HASHTAG_SECONDARY_RE: &str = r"^(?P<tag>[0-9A-Za-z]+)(?P<after>[\.,:?\)]?(<br>)?)$";
const HASHTAG_NAME_RE: &str = r"^\w+$"; const HASHTAG_NAME_RE: &str = r"^\w+$";
/// Finds anything that looks like a hashtag /// Finds anything that looks like a hashtag
@ -63,16 +63,16 @@ mod tests {
use super::*; use super::*;
const INSTANCE_URL: &str = "https://example.com"; const INSTANCE_URL: &str = "https://example.com";
const TEXT_WITH_TAGS: &str = concat!(
"@user1@server1 some text #TestTag.\n",
"#TAG1 #tag1 #test_underscore #test*special ",
"more text (#tag2) text #tag3, #tag4:<br>\n",
"end with #tag5",
);
#[test] #[test]
fn test_find_tags() { fn test_find_tags() {
let text = concat!( let tags = find_tags(TEXT_WITH_TAGS);
"@user1@server1 some text #TestTag.\n",
"#TAG1 #tag1 #test_underscore #test*special ",
"more text #tag2, #tag3:<br>\n",
"end with #tag4",
);
let tags = find_tags(text);
assert_eq!(tags, vec![ assert_eq!(tags, vec![
"testtag", "testtag",
@ -80,27 +80,23 @@ mod tests {
"tag2", "tag2",
"tag3", "tag3",
"tag4", "tag4",
"tag5",
]); ]);
} }
#[test] #[test]
fn test_replace_tags() { fn test_replace_tags() {
let text = concat!( let tags = find_tags(TEXT_WITH_TAGS);
"@user1@server1 some text #TestTag.\n", let output = replace_tags(INSTANCE_URL, TEXT_WITH_TAGS, &tags);
"#TAG1 #tag1 #test_underscore #test*special ",
"more text #tag2, #tag3:<br>\n",
"end with #tag4",
);
let tags = find_tags(text);
let output = replace_tags(INSTANCE_URL, &text, &tags);
let expected_output = concat!( let expected_output = concat!(
r#"@user1@server1 some text <a class="hashtag" href="https://example.com/tag/testtag">#TestTag</a>."#, "\n", r#"@user1@server1 some text <a class="hashtag" href="https://example.com/tag/testtag">#TestTag</a>."#, "\n",
r#"<a class="hashtag" href="https://example.com/tag/tag1">#TAG1</a> <a class="hashtag" href="https://example.com/tag/tag1">#tag1</a> "#, r#"<a class="hashtag" href="https://example.com/tag/tag1">#TAG1</a> <a class="hashtag" href="https://example.com/tag/tag1">#tag1</a> "#,
r#"#test_underscore #test*special "#, r#"#test_underscore #test*special "#,
r#"more text <a class="hashtag" href="https://example.com/tag/tag2">#tag2</a>, "#, r#"more text (<a class="hashtag" href="https://example.com/tag/tag2">#tag2</a>) text "#,
r#"<a class="hashtag" href="https://example.com/tag/tag3">#tag3</a>:<br>"#, "\n", r#"<a class="hashtag" href="https://example.com/tag/tag3">#tag3</a>, "#,
r#"end with <a class="hashtag" href="https://example.com/tag/tag4">#tag4</a>"#, r#"<a class="hashtag" href="https://example.com/tag/tag4">#tag4</a>:<br>"#, "\n",
r#"end with <a class="hashtag" href="https://example.com/tag/tag5">#tag5</a>"#,
); );
assert_eq!(output, expected_output); assert_eq!(output, expected_output);
} }