diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index fc97158..53e13c4 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -99,10 +99,11 @@ fn create_activity( activity } -pub fn create_activity_note( +pub fn create_note( config: &Config, post: &Post, -) -> Activity { + in_reply_to: Option<&Post>, +) -> Object { let object_id = get_object_url( &config.instance_url(), &post.id, @@ -121,7 +122,18 @@ pub fn create_activity_note( url, } }).collect(); - let object = Object { + let in_reply_to_object_id = match post.in_reply_to_id { + Some(in_reply_to_id) => { + let post = in_reply_to.unwrap(); + assert_eq!(post.id, in_reply_to_id); + match post.author.actor_json { + Some(_) => None, // TODO: store object ID for remote posts + None => Some(get_object_url(&config.instance_url(), &post.id)), + } + }, + None => None, + }; + Object { context: Some(json!(AP_CONTEXT)), id: object_id, object_type: NOTE.to_string(), @@ -130,10 +142,18 @@ pub fn create_activity_note( object: None, published: Some(post.created_at), attributed_to: Some(actor_id.clone()), - in_reply_to: None, + in_reply_to: in_reply_to_object_id, content: Some(post.content.clone()), to: Some(json!(AP_PUBLIC)), - }; + } +} + +pub fn create_activity_note( + config: &Config, + post: &Post, + in_reply_to: Option<&Post>, +) -> Activity { + let object = create_note(config, post, in_reply_to); let activity = create_activity( &config.instance_url(), &post.author.username, diff --git a/src/mastodon_api/statuses/views.rs b/src/mastodon_api/statuses/views.rs index 8fc1aff..c49ff15 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -36,9 +36,15 @@ async fn create_status( let mut post_data = PostCreateData::from(data.into_inner()); post_data.validate()?; let post = create_post(db_client, ¤t_user.id, post_data).await?; - let status = Status::from_post(post.clone(), &config.instance_url()); // Federate - let activity = create_activity_note(&config, &post); + let in_reply_to = match post.in_reply_to_id { + Some(in_reply_to_id) => { + let in_reply_to = get_post_by_id(db_client, &in_reply_to_id).await?; + Some(in_reply_to) + }, + None => None, + }; + let activity = create_activity_note(&config, &post, in_reply_to.as_ref()); let followers = get_followers(db_client, ¤t_user.id).await?; let mut recipients: Vec = Vec::new(); for follower in followers { @@ -49,14 +55,16 @@ async fn create_status( recipients.push(actor); }; }; + let config_clone = config.clone(); actix_rt::spawn(async move { deliver_activity( - &config, + &config_clone, ¤t_user, activity, recipients, ).await; }); + let status = Status::from_post(post, &config.instance_url()); Ok(HttpResponse::Created().json(status)) } diff --git a/src/models/posts/queries.rs b/src/models/posts/queries.rs index ac8a37c..7f33c36 100644 --- a/src/models/posts/queries.rs +++ b/src/models/posts/queries.rs @@ -166,6 +166,8 @@ pub async fn get_post_by_id( Ok(post) } +/// Given a post ID, finds all items in thread. +/// Results are sorted by tree path. pub async fn get_thread( db_client: &impl GenericClient, post_id: &Uuid,