Add replies and reposts to outbox collection

This commit is contained in:
silverpill 2023-04-22 01:01:52 +00:00 committed by Rafael Caricio
parent b6e7fa5d13
commit b77d4a9bdf
Signed by: rafaelcaricio
GPG key ID: 3C86DBCE8E93C947
4 changed files with 37 additions and 34 deletions

View file

@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Ignore errors when importing activities from outbox. - Ignore errors when importing activities from outbox.
- Make activity limit in outbox fetcher adjustable. - Make activity limit in outbox fetcher adjustable.
- Updated actix to latest version. MSRV changed to 1.57. - Updated actix to latest version. MSRV changed to 1.57.
- Add replies and reposts to outbox collection.
### Fixed ### Fixed

View file

@ -25,7 +25,7 @@ use crate::activitypub::{
}; };
#[derive(Serialize)] #[derive(Serialize)]
struct Announce { pub struct Announce {
#[serde(rename = "@context")] #[serde(rename = "@context")]
context: Context, context: Context,
@ -41,18 +41,17 @@ struct Announce {
cc: Vec<String>, cc: Vec<String>,
} }
fn build_announce( pub fn build_announce(
instance_url: &str, instance_url: &str,
sender_username: &str,
repost: &Post, repost: &Post,
) -> Announce { ) -> Announce {
let actor_id = local_actor_id(instance_url, sender_username); let actor_id = local_actor_id(instance_url, &repost.author.username);
let post = repost.repost_of.as_ref() let post = repost.repost_of.as_ref()
.expect("repost_of field should be populated"); .expect("repost_of field should be populated");
let object_id = post_object_id(instance_url, post); let object_id = post_object_id(instance_url, post);
let activity_id = local_object_id(instance_url, &repost.id); let activity_id = local_object_id(instance_url, &repost.id);
let recipient_id = profile_actor_id(instance_url, &post.author); let recipient_id = profile_actor_id(instance_url, &post.author);
let followers = local_actor_followers(instance_url, sender_username); let followers = local_actor_followers(instance_url, &repost.author.username);
Announce { Announce {
context: build_default_context(), context: build_default_context(),
activity_type: ANNOUNCE.to_string(), activity_type: ANNOUNCE.to_string(),
@ -91,7 +90,9 @@ pub async fn prepare_announce(
sender: &User, sender: &User,
repost: &Post, repost: &Post,
) -> Result<OutgoingActivity, DatabaseError> { ) -> Result<OutgoingActivity, DatabaseError> {
let post = repost.repost_of.as_ref().unwrap(); assert_eq!(sender.id, repost.author.id);
let post = repost.repost_of.as_ref()
.expect("repost_of field should be populated");
let (recipients, _) = get_announce_recipients( let (recipients, _) = get_announce_recipients(
db_client, db_client,
&instance.url(), &instance.url(),
@ -100,7 +101,6 @@ pub async fn prepare_announce(
).await?; ).await?;
let activity = build_announce( let activity = build_announce(
&instance.url(), &instance.url(),
&sender.profile.username,
repost, repost,
); );
Ok(OutgoingActivity::new( Ok(OutgoingActivity::new(
@ -140,14 +140,13 @@ mod tests {
..Default::default() ..Default::default()
}; };
let repost = Post { let repost = Post {
author: repost_author.clone(), author: repost_author,
repost_of_id: Some(post.id), repost_of_id: Some(post.id),
repost_of: Some(Box::new(post)), repost_of: Some(Box::new(post)),
..Default::default() ..Default::default()
}; };
let activity = build_announce( let activity = build_announce(
INSTANCE_URL, INSTANCE_URL,
&repost_author.username,
&repost, &repost,
); );
assert_eq!( assert_eq!(

View file

@ -1,5 +1,5 @@
use serde::Serialize; use serde::Serialize;
use serde_json::{json, Value}; use serde_json::{Value as JsonValue};
use super::types::{build_default_context, Context}; use super::types::{build_default_context, Context};
use super::vocabulary::{ORDERED_COLLECTION, ORDERED_COLLECTION_PAGE}; use super::vocabulary::{ORDERED_COLLECTION, ORDERED_COLLECTION_PAGE};
@ -38,8 +38,6 @@ impl OrderedCollection {
} }
} }
pub const COLLECTION_PAGE_SIZE: u16 = 10;
#[derive(Serialize)] #[derive(Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct OrderedCollectionPage { pub struct OrderedCollectionPage {
@ -51,21 +49,19 @@ pub struct OrderedCollectionPage {
#[serde(rename = "type")] #[serde(rename = "type")]
pub object_type: String, pub object_type: String,
ordered_items: Vec<Value>, ordered_items: Vec<JsonValue>,
} }
impl OrderedCollectionPage { impl OrderedCollectionPage {
pub fn new( pub fn new(
collection_page_id: String, collection_page_id: String,
items: Vec<impl Serialize>, items: Vec<JsonValue>,
) -> Self { ) -> Self {
let ordered_items = items.into_iter()
.map(|item| json!(item)).collect();
Self { Self {
context: build_default_context(), context: build_default_context(),
id: collection_page_id, id: collection_page_id,
object_type: ORDERED_COLLECTION_PAGE.to_string(), object_type: ORDERED_COLLECTION_PAGE.to_string(),
ordered_items, ordered_items: items,
} }
} }
} }

View file

@ -30,13 +30,15 @@ use crate::web_client::urls::{
get_tag_page_url, get_tag_page_url,
}; };
use super::actors::types::{get_local_actor, get_instance_actor}; use super::actors::types::{get_local_actor, get_instance_actor};
use super::builders::create_note::{ use super::builders::{
build_emoji_tag, announce::build_announce,
build_note, create_note::{
build_create_note, build_emoji_tag,
build_note,
build_create_note,
},
}; };
use super::collections::{ use super::collections::{
COLLECTION_PAGE_SIZE,
OrderedCollection, OrderedCollection,
OrderedCollectionPage, OrderedCollectionPage,
}; };
@ -171,26 +173,31 @@ async fn outbox(
let db_client = &**get_database_client(&db_pool).await?; let db_client = &**get_database_client(&db_pool).await?;
let user = get_user_by_name(db_client, &username).await?; let user = get_user_by_name(db_client, &username).await?;
// Posts are ordered by creation date // Posts are ordered by creation date
const COLLECTION_PAGE_SIZE: u16 = 20;
let mut posts = get_posts_by_author( let mut posts = get_posts_by_author(
db_client, db_client,
&user.id, &user.id,
None, // include only public posts None, // include only public posts
false, // exclude replies true, // include replies
false, // exclude reposts true, // include reposts
None, None,
COLLECTION_PAGE_SIZE, COLLECTION_PAGE_SIZE,
).await?; ).await?;
add_related_posts(db_client, posts.iter_mut().collect()).await?; add_related_posts(db_client, posts.iter_mut().collect()).await?;
let activities: Vec<_> = posts.iter().filter_map(|post| { let activities = posts.iter().map(|post| {
if post.in_reply_to_id.is_some() || post.repost_of_id.is_some() { if post.repost_of_id.is_some() {
return None; let activity = build_announce(&instance.url(), post);
}; serde_json::to_value(activity)
let activity = build_create_note( .expect("activity should be serializable")
&instance.hostname(), } else {
&instance.url(), let activity = build_create_note(
post, &instance.hostname(),
); &instance.url(),
Some(activity) post,
);
serde_json::to_value(activity)
.expect("activity should be serializable")
}
}).collect(); }).collect();
let collection_page = OrderedCollectionPage::new( let collection_page = OrderedCollectionPage::new(
first_page_id, first_page_id,