diff --git a/src/activitypub/builders/create_note.rs b/src/activitypub/builders/create_note.rs index 9a976a7..89fcdee 100644 --- a/src/activitypub/builders/create_note.rs +++ b/src/activitypub/builders/create_note.rs @@ -37,6 +37,7 @@ use crate::models::{ relationships::queries::{get_followers, get_subscribers}, users::types::User, }; +use crate::webfinger::types::ActorAddress; #[allow(dead_code)] #[derive(Serialize)] @@ -134,7 +135,11 @@ pub fn build_note( let mut tags = vec![]; for profile in &post.mentions { - let tag_name = format!("@{}", profile.actor_address(instance_hostname)); + let actor_address = ActorAddress::from_profile( + instance_hostname, + profile, + ); + let tag_name = format!("@{}", actor_address); let actor_id = profile_actor_id(instance_url, profile); if !primary_audience.contains(&actor_id) { primary_audience.push(actor_id.clone()); diff --git a/src/atom/feeds.rs b/src/atom/feeds.rs index bfe3e22..e50ef60 100644 --- a/src/atom/feeds.rs +++ b/src/atom/feeds.rs @@ -9,6 +9,7 @@ use crate::models::{ posts::types::Post, profiles::types::DbActorProfile, }; +use crate::webfinger::types::ActorAddress; const ENTRY_TITLE_MAX_LENGTH: usize = 75; @@ -56,7 +57,10 @@ pub fn make_feed( let actor_id = local_actor_id(&instance.url(), &profile.username); let actor_name = profile.display_name.as_ref() .unwrap_or(&profile.username); - let actor_address = profile.actor_address(&instance.hostname()); + let actor_address = ActorAddress::from_profile( + &instance.hostname(), + profile, + ); let feed_url = get_feed_url(&instance.url(), &profile.username); let feed_title = format!("{} (@{})", actor_name, actor_address); let mut entries = vec![]; diff --git a/src/mastodon_api/settings/helpers.rs b/src/mastodon_api/settings/helpers.rs index 1d5d11f..04d27a6 100644 --- a/src/mastodon_api/settings/helpers.rs +++ b/src/mastodon_api/settings/helpers.rs @@ -37,7 +37,10 @@ fn export_profiles_to_csv( ) -> String { let mut csv = String::new(); for profile in profiles { - let actor_address = profile.actor_address(local_hostname); + let actor_address = ActorAddress::from_profile( + local_hostname, + &profile, + ); csv += &format!("{}\n", actor_address); }; csv diff --git a/src/models/profiles/types.rs b/src/models/profiles/types.rs index f03cf73..b2682a3 100644 --- a/src/models/profiles/types.rs +++ b/src/models/profiles/types.rs @@ -22,7 +22,6 @@ use crate::database::{ }; use crate::errors::ValidationError; use crate::models::emojis::types::DbEmoji; -use crate::webfinger::types::ActorAddress; use super::validators::{ validate_username, validate_display_name, @@ -398,16 +397,6 @@ impl DbActorProfile { self.actor_json.is_none() } - pub fn actor_address(&self, local_hostname: &str) -> ActorAddress { - assert_eq!(self.hostname.is_none(), self.is_local()); - ActorAddress { - username: self.username.clone(), - hostname: self.hostname.as_deref() - .unwrap_or(local_hostname) - .to_string(), - } - } - pub fn possibly_outdated(&self) -> bool { if self.is_local() { false @@ -560,8 +549,6 @@ mod tests { use crate::activitypub::actors::types::Actor; use super::*; - const INSTANCE_HOSTNAME: &str = "example.com"; - #[test] fn test_identity_proof_serialization() { let json_data = r#"{"issuer":"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a","proof_type":1,"value":"dbfe"}"#; @@ -602,39 +589,6 @@ mod tests { assert_eq!(serialized, r#"{"payment_type":2,"chain_id":"eip155:1"}"#); } - #[test] - fn test_local_actor_address() { - let local_profile = DbActorProfile { - username: "user".to_string(), - hostname: None, - acct: "user".to_string(), - actor_json: None, - ..Default::default() - }; - assert_eq!( - local_profile.actor_address(INSTANCE_HOSTNAME).to_string(), - "user@example.com", - ); - } - - #[test] - fn test_remote_actor_address() { - let remote_profile = DbActorProfile { - username: "test".to_string(), - hostname: Some("remote.com".to_string()), - acct: "test@remote.com".to_string(), - actor_json: Some(Actor { - id: "https://test".to_string(), - ..Default::default() - }), - ..Default::default() - }; - assert_eq!( - remote_profile.actor_address(INSTANCE_HOSTNAME).to_string(), - remote_profile.acct, - ); - } - #[test] fn test_clean_profile_create_data() { let mut profile_data = ProfileCreateData { diff --git a/src/webfinger/types.rs b/src/webfinger/types.rs index 65d2721..cec6cb1 100644 --- a/src/webfinger/types.rs +++ b/src/webfinger/types.rs @@ -9,6 +9,7 @@ use regex::Regex; use serde::{Serialize, Deserialize}; use crate::errors::ValidationError; +use crate::models::profiles::types::DbActorProfile; // See also: USERNAME_RE in models::profiles::validators const ACTOR_ADDRESS_RE: &str = r"^(?P[\w\.-]+)@(?P[\w\.-]+)$"; @@ -27,6 +28,19 @@ pub struct ActorAddress { } impl ActorAddress { + pub fn from_profile( + local_hostname: &str, + profile: &DbActorProfile, + ) -> Self { + assert_eq!(profile.hostname.is_none(), profile.is_local()); + Self { + username: profile.username.clone(), + hostname: profile.hostname.as_deref() + .unwrap_or(local_hostname) + .to_string(), + } + } + /// Returns acct string, as used in Mastodon pub fn acct(&self, local_hostname: &str) -> String { if self.hostname == local_hostname { @@ -80,8 +94,52 @@ pub struct JsonResourceDescriptor { #[cfg(test)] mod tests { + use crate::activitypub::actors::types::Actor; use super::*; + #[test] + fn test_local_actor_address() { + let local_hostname = "example.com"; + let local_profile = DbActorProfile { + username: "user".to_string(), + hostname: None, + acct: "user".to_string(), + actor_json: None, + ..Default::default() + }; + let actor_address = ActorAddress::from_profile( + local_hostname, + &local_profile, + ); + assert_eq!( + actor_address.to_string(), + "user@example.com", + ); + } + + #[test] + fn test_remote_actor_address() { + let local_hostname = "example.com"; + let remote_profile = DbActorProfile { + username: "test".to_string(), + hostname: Some("remote.com".to_string()), + acct: "test@remote.com".to_string(), + actor_json: Some(Actor { + id: "https://test".to_string(), + ..Default::default() + }), + ..Default::default() + }; + let actor_address = ActorAddress::from_profile( + local_hostname, + &remote_profile, + ); + assert_eq!( + actor_address.to_string(), + remote_profile.acct, + ); + } + #[test] fn test_actor_address_parse_address() { let value = "user_1@example.com";