]> Untitled Git - lemmy.git/blob - crates/utils/src/utils/mention.rs
1dcace37bb6eafd2133056dce4e2e7d5ba5e45b3
[lemmy.git] / crates / utils / src / utils / mention.rs
1 use itertools::Itertools;
2 use once_cell::sync::Lazy;
3 use regex::Regex;
4
5 static MENTIONS_REGEX: Lazy<Regex> = Lazy::new(|| {
6   Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").expect("compile regex")
7 });
8 // TODO nothing is done with community / group webfingers yet, so just ignore those for now
9 #[derive(Clone, PartialEq, Eq, Hash)]
10 pub struct MentionData {
11   pub name: String,
12   pub domain: String,
13 }
14
15 impl MentionData {
16   pub fn is_local(&self, hostname: &str) -> bool {
17     hostname.eq(&self.domain)
18   }
19   pub fn full_name(&self) -> String {
20     format!("@{}@{}", &self.name, &self.domain)
21   }
22 }
23
24 pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
25   let mut out: Vec<MentionData> = Vec::new();
26   for caps in MENTIONS_REGEX.captures_iter(text) {
27     if let Some(name) = caps.name("name").map(|c| c.as_str().to_string()) {
28       if let Some(domain) = caps.name("domain").map(|c| c.as_str().to_string()) {
29         out.push(MentionData { name, domain });
30       }
31     }
32   }
33   out.into_iter().unique().collect()
34 }
35
36 #[cfg(test)]
37 mod test {
38   use crate::utils::mention::scrape_text_for_mentions;
39
40   #[test]
41   fn test_mentions_regex() {
42     let text = "Just read a great blog post by [@tedu@honk.teduangst.com](/u/test). And another by !test_community@fish.teduangst.com . Another [@lemmy@lemmy-alpha:8540](/u/fish)";
43     let mentions = scrape_text_for_mentions(text);
44
45     assert_eq!(mentions[0].name, "tedu".to_string());
46     assert_eq!(mentions[0].domain, "honk.teduangst.com".to_string());
47     assert_eq!(mentions[1].domain, "lemmy-alpha:8540".to_string());
48   }
49 }