diff --git a/.cargo/config.toml b/.cargo/config.toml index 3a7d564..124fd11 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -7,4 +7,5 @@ rustflags = [ "-Aclippy::or_fun_call", "-Aclippy::redundant_field_names", "-Aclippy::unused_unit", + "-Aclippy::enum_variant_names", ] diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index b35b1c8..c94cada 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -1,15 +1,9 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use uuid::Uuid; -use crate::models::profiles::types::DbActorProfile; -use super::constants::{AP_CONTEXT, AP_PUBLIC}; -use super::views::{ - get_actor_url, - get_followers_url, - get_object_url, -}; +use super::constants::AP_CONTEXT; +use super::views::get_actor_url; use super::vocabulary::*; #[derive(Deserialize, Serialize)] @@ -128,59 +122,3 @@ pub fn create_activity( cc: Some(json!(secondary_audience)), } } - -pub fn create_activity_undo_announce( - instance_url: &str, - actor_profile: &DbActorProfile, - repost_id: &Uuid, - recipient_id: &str, -) -> Activity { - let object_id = get_object_url( - instance_url, - repost_id, - ); - let activity_id = format!("{}/undo", object_id); - let primary_audience = vec![ - AP_PUBLIC.to_string(), - recipient_id.to_string(), - ]; - create_activity( - instance_url, - &actor_profile.username, - UNDO, - activity_id, - object_id, - primary_audience, - vec![get_followers_url(instance_url, &actor_profile.username)], - ) -} - -#[cfg(test)] -mod tests { - use crate::utils::id::new_uuid; - use super::*; - - const INSTANCE_URL: &str = "https://example.com"; - - #[test] - fn test_create_activity_undo_announce() { - let announcer = DbActorProfile::default(); - let post_author_id = "https://example.com/users/test"; - let repost_id = new_uuid(); - let activity = create_activity_undo_announce( - INSTANCE_URL, - &announcer, - &repost_id, - post_author_id, - ); - assert_eq!( - activity.id, - format!("{}/objects/{}/undo", INSTANCE_URL, repost_id), - ); - assert_eq!( - activity.object, - format!("{}/objects/{}", INSTANCE_URL, repost_id), - ); - assert_eq!(activity.to.unwrap(), json!([AP_PUBLIC, post_author_id])); - } -} diff --git a/src/activitypub/builders/mod.rs b/src/activitypub/builders/mod.rs index e2487b8..43fae4e 100644 --- a/src/activitypub/builders/mod.rs +++ b/src/activitypub/builders/mod.rs @@ -5,6 +5,7 @@ pub mod delete_note; pub mod delete_person; pub mod follow; pub mod like_note; +pub mod undo_announce_note; pub mod undo_follow; pub mod undo_like_note; pub mod update_person; diff --git a/src/activitypub/builders/undo_announce_note.rs b/src/activitypub/builders/undo_announce_note.rs new file mode 100644 index 0000000..e51d011 --- /dev/null +++ b/src/activitypub/builders/undo_announce_note.rs @@ -0,0 +1,97 @@ +use tokio_postgres::GenericClient; +use uuid::Uuid; + +use crate::activitypub::{ + activity::{create_activity, Activity}, + constants::AP_PUBLIC, + deliverer::OutgoingActivity, + views::{get_followers_url, get_object_url}, + vocabulary::UNDO, +}; +use crate::config::Instance; +use crate::errors::DatabaseError; +use crate::mastodon_api::statuses::helpers::{get_announce_recipients, Audience}; +use crate::models::posts::types::Post; +use crate::models::profiles::types::DbActorProfile; +use crate::models::users::types::User; + +fn build_undo_announce( + instance_url: &str, + actor_profile: &DbActorProfile, + repost_id: &Uuid, + recipient_id: &str, +) -> Activity { + let object_id = get_object_url( + instance_url, + repost_id, + ); + let activity_id = format!("{}/undo", object_id); + let primary_audience = vec![ + AP_PUBLIC.to_string(), + recipient_id.to_string(), + ]; + create_activity( + instance_url, + &actor_profile.username, + UNDO, + activity_id, + object_id, + primary_audience, + vec![get_followers_url(instance_url, &actor_profile.username)], + ) +} + +pub async fn prepare_undo_announce_note( + db_client: &impl GenericClient, + instance: Instance, + user: &User, + post: &Post, + repost_id: &Uuid, +) -> Result { + assert_ne!(&post.id, repost_id); + let Audience { recipients, primary_recipient } = + get_announce_recipients(db_client, &instance.url(), user, post).await?; + let activity = build_undo_announce( + &instance.url(), + &user.profile, + repost_id, + &primary_recipient, + ); + Ok(OutgoingActivity { + instance, + sender: user.clone(), + activity, + recipients, + }) +} + +#[cfg(test)] +mod tests { + use serde_json::json; + use crate::utils::id::new_uuid; + use super::*; + + const INSTANCE_URL: &str = "https://example.com"; + + #[test] + fn test_build_undo_announce() { + let announcer = DbActorProfile::default(); + let post_author_id = "https://example.com/users/test"; + let repost_id = new_uuid(); + let activity = build_undo_announce( + INSTANCE_URL, + &announcer, + &repost_id, + post_author_id, + ); + assert_eq!( + activity.id, + format!("{}/objects/{}/undo", INSTANCE_URL, repost_id), + ); + assert_eq!( + activity.object, + format!("{}/objects/{}", INSTANCE_URL, repost_id), + ); + assert_eq!(activity.to.unwrap(), json!([AP_PUBLIC, post_author_id])); + } +} diff --git a/src/activitypub/deliverer.rs b/src/activitypub/deliverer.rs index ee4ab7c..958c767 100644 --- a/src/activitypub/deliverer.rs +++ b/src/activitypub/deliverer.rs @@ -1,7 +1,7 @@ use actix_web::http::Method; use rsa::RsaPrivateKey; -use crate::config::{Config, Instance}; +use crate::config::Instance; use crate::http_signatures::create::{create_http_signature, SignatureError}; use crate::models::users::types::User; use crate::utils::crypto::deserialize_private_key; @@ -140,17 +140,3 @@ impl OutgoingActivity { }); } } - -pub fn deliver_activity( - config: &Config, - sender: &User, - activity: Activity, - recipients: Vec, -) -> () { - OutgoingActivity { - instance: config.instance(), - sender: sender.clone(), - activity, - recipients, - }.spawn_deliver(); -} diff --git a/src/activitypub/mod.rs b/src/activitypub/mod.rs index 141d600..4530527 100644 --- a/src/activitypub/mod.rs +++ b/src/activitypub/mod.rs @@ -1,9 +1,9 @@ -pub mod activity; +mod activity; pub mod actor; pub mod builders; mod collections; pub mod constants; -pub mod deliverer; +mod deliverer; pub mod fetcher; pub mod handlers; mod receiver; diff --git a/src/mastodon_api/statuses/views.rs b/src/mastodon_api/statuses/views.rs index 67ec833..d8b1556 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -5,17 +5,14 @@ use actix_web::{delete, get, post, web, HttpResponse, Scope}; use actix_web_httpauth::extractors::bearer::BearerAuth; use uuid::Uuid; -use crate::activitypub::activity::{ - create_activity_undo_announce, -}; use crate::activitypub::builders::{ announce_note::prepare_announce_note, create_note::prepare_create_note, delete_note::prepare_delete_note, like_note::prepare_like_note, + undo_announce_note::prepare_undo_announce_note, undo_like_note::prepare_undo_like_note, }; -use crate::activitypub::deliverer::deliver_activity; use crate::config::Config; use crate::database::{Pool, get_database_client}; use crate::errors::{DatabaseError, HttpError, ValidationError}; @@ -44,8 +41,6 @@ use crate::models::reactions::queries::{ use super::helpers::{ build_status, build_status_list, - get_announce_recipients, - Audience, }; use super::types::{Status, StatusData, TransactionData}; @@ -345,15 +340,13 @@ async fn unreblog( let post = get_post_by_id(db_client, &status_id).await?; // Federate - let Audience { recipients, primary_recipient } = - get_announce_recipients(db_client, &config.instance_url(), ¤t_user, &post).await?; - let activity = create_activity_undo_announce( - &config.instance_url(), - ¤t_user.profile, + prepare_undo_announce_note( + db_client, + config.instance(), + ¤t_user, + &post, repost_id, - &primary_recipient, - ); - deliver_activity(&config, ¤t_user, activity, recipients); + ).await?.spawn_deliver(); let status = build_status( db_client,