diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index e43eaa7..4ff3bd6 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -220,31 +220,6 @@ pub fn create_activity_undo_announce( ) } -pub fn create_activity_follow( - instance_url: &str, - actor_profile: &DbActorProfile, - follow_request_id: &Uuid, - target_actor_id: &str, -) -> Activity { - let object = Object { - context: Some(json!(AP_CONTEXT)), - id: target_actor_id.to_owned(), - object_type: PERSON.to_string(), - ..Default::default() - }; - let activity_id = get_object_url(instance_url, follow_request_id); - let activity = create_activity( - instance_url, - &actor_profile.username, - FOLLOW, - activity_id, - object, - vec![target_actor_id.to_string()], - vec![], - ); - activity -} - pub fn create_activity_accept_follow( instance_url: &str, actor_profile: &DbActorProfile, @@ -298,39 +273,6 @@ mod tests { assert_eq!(activity.to.unwrap(), json!([AP_PUBLIC, note_author_id])); } - #[test] - fn test_create_activity_follow() { - let follower = DbActorProfile { - username: "follower".to_string(), - ..Default::default() - }; - let follow_request_id = new_uuid(); - let target_actor_id = "https://test.remote/actor/test"; - let activity = create_activity_follow( - INSTANCE_URL, - &follower, - &follow_request_id, - target_actor_id, - ); - - assert_eq!( - activity.id, - format!("{}/objects/{}", INSTANCE_URL, follow_request_id), - ); - assert_eq!(activity.activity_type, "Follow"); - assert_eq!( - activity.actor, - format!("{}/users/{}", INSTANCE_URL, follower.username), - ); - assert_eq!(activity.object["id"], target_actor_id); - assert_eq!(activity.object["type"], "Person"); - assert_eq!(activity.object["actor"], Value::Null); - assert_eq!(activity.object["object"], Value::Null); - assert_eq!(activity.object["content"], Value::Null); - assert_eq!(activity.to.unwrap(), json!([target_actor_id])); - assert_eq!(activity.cc.unwrap(), json!([])); - } - #[test] fn test_create_activity_accept_follow() { let target = DbActorProfile { diff --git a/src/activitypub/builders/follow.rs b/src/activitypub/builders/follow.rs new file mode 100644 index 0000000..7da3b4c --- /dev/null +++ b/src/activitypub/builders/follow.rs @@ -0,0 +1,102 @@ +use serde_json::json; +use uuid::Uuid; + +use crate::activitypub::{ + activity::{create_activity, Activity, Object}, + actor::Actor, + constants::AP_CONTEXT, + deliverer::OutgoingActivity, + views::get_object_url, + vocabulary::{FOLLOW, PERSON}, +}; +use crate::config::Instance; +use crate::models::profiles::types::DbActorProfile; +use crate::models::users::types::User; + +fn build_follow( + instance_url: &str, + actor_profile: &DbActorProfile, + target_actor_id: &str, + follow_request_id: &Uuid, +) -> Activity { + let object = Object { + context: Some(json!(AP_CONTEXT)), + id: target_actor_id.to_owned(), + object_type: PERSON.to_string(), + ..Default::default() + }; + let activity_id = get_object_url(instance_url, follow_request_id); + let activity = create_activity( + instance_url, + &actor_profile.username, + FOLLOW, + activity_id, + object, + vec![target_actor_id.to_string()], + vec![], + ); + activity +} + +pub fn prepare_follow( + instance: Instance, + user: &User, + target_actor: &Actor, + follow_request_id: &Uuid, +) -> OutgoingActivity { + let activity = build_follow( + &instance.url(), + &user.profile, + &target_actor.id, + follow_request_id, + ); + let recipients = vec![target_actor.clone()]; + OutgoingActivity { + instance, + sender: user.clone(), + activity, + recipients, + } +} + +#[cfg(test)] +mod tests { + use serde_json::{json, Value}; + use crate::utils::id::new_uuid; + use super::*; + + const INSTANCE_URL: &str = "https://example.com"; + + #[test] + fn test_build_follow() { + let follower = DbActorProfile { + username: "follower".to_string(), + ..Default::default() + }; + let follow_request_id = new_uuid(); + let target_actor_id = "https://test.remote/actor/test"; + let activity = build_follow( + INSTANCE_URL, + &follower, + target_actor_id, + &follow_request_id, + ); + + assert_eq!( + activity.id, + format!("{}/objects/{}", INSTANCE_URL, follow_request_id), + ); + assert_eq!(activity.activity_type, "Follow"); + assert_eq!( + activity.actor, + format!("{}/users/{}", INSTANCE_URL, follower.username), + ); + assert_eq!(activity.object["id"], target_actor_id); + assert_eq!(activity.object["type"], "Person"); + assert_eq!(activity.object["actor"], Value::Null); + assert_eq!(activity.object["object"], Value::Null); + assert_eq!(activity.object["content"], Value::Null); + assert_eq!(activity.to.unwrap(), json!([target_actor_id])); + assert_eq!(activity.cc.unwrap(), json!([])); + } +} diff --git a/src/activitypub/builders/mod.rs b/src/activitypub/builders/mod.rs index 0269d32..81088ea 100644 --- a/src/activitypub/builders/mod.rs +++ b/src/activitypub/builders/mod.rs @@ -1,5 +1,6 @@ pub mod create_note; pub mod delete_note; pub mod delete_person; +pub mod follow; pub mod undo_follow; pub mod update_person; diff --git a/src/activitypub/builders/undo_follow.rs b/src/activitypub/builders/undo_follow.rs index bd5592b..cd30688 100644 --- a/src/activitypub/builders/undo_follow.rs +++ b/src/activitypub/builders/undo_follow.rs @@ -16,8 +16,8 @@ use crate::models::users::types::User; fn build_undo_follow( instance_url: &str, actor_profile: &DbActorProfile, - follow_request_id: &Uuid, target_actor_id: &str, + follow_request_id: &Uuid, ) -> Activity { let follow_activity_id = get_object_url( instance_url, @@ -57,8 +57,8 @@ pub fn prepare_undo_follow( let activity = build_undo_follow( &instance.url(), &user.profile, - follow_request_id, &target_actor.id, + follow_request_id, ); let recipients = vec![target_actor.clone()]; OutgoingActivity { diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index 95f182a..f4b418b 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -2,12 +2,11 @@ use actix_web::{get, post, patch, web, HttpResponse, Scope}; use actix_web_httpauth::extractors::bearer::BearerAuth; use uuid::Uuid; -use crate::activitypub::activity::create_activity_follow; use crate::activitypub::builders::{ + follow::prepare_follow, undo_follow::prepare_undo_follow, update_person::prepare_update_person, }; -use crate::activitypub::deliverer::deliver_activity; use crate::config::Config; use crate::database::{Pool, get_database_client}; use crate::errors::{DatabaseError, HttpError, ValidationError}; @@ -334,14 +333,13 @@ async fn follow_account( if let Some(remote_actor) = target.actor_json { // Create follow request if target is remote match create_follow_request(db_client, ¤t_user.id, &target.id).await { - Ok(request) => { - let activity = create_activity_follow( - &config.instance_url(), - ¤t_user.profile, - &request.id, - &remote_actor.id, - ); - deliver_activity(&config, ¤t_user, activity, vec![remote_actor]); + Ok(follow_request) => { + prepare_follow( + config.instance(), + ¤t_user, + &remote_actor, + &follow_request.id, + ).spawn_deliver(); }, Err(DatabaseError::AlreadyExists(_)) => (), // already following Err(other_error) => return Err(other_error.into()),