8802779ebcb7d4726342c28944c06e17b4a38e82 / frogue / src / activitypub / outbox.rs
Raw
//! ActivityPub outbox serving.
//!
//! Serves the outbox collection and individual pages for an actor.
use sea_orm::{
ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder,
QuerySelect,
};
use crate::activitypub::types::{CONTEXT, OrderedCollection, OrderedCollectionPage};
use crate::entities::ap_activities;
use crate::entities::prelude::ApActivities;
/// Serves the outbox collection for an actor.
pub async fn get_outbox(
db: &DatabaseConnection,
actor_id: i64,
outbox_url: &str,
page: Option<u64>,
) -> Result<serde_json::Value, sea_orm::DbErr> {
// Count total activities
let total = ApActivities::find()
.filter(ap_activities::Column::ActorId.eq(actor_id))
.count(db)
.await?;
// If no page parameter, return the collection
let Some(page_num) = page else {
let collection = OrderedCollection {
context: CONTEXT.to_vec(),
id: outbox_url.to_string(),
kind: "OrderedCollection",
total_items: total,
first: if total > 0 {
Some(format!("{}?page=1", outbox_url))
} else {
None
},
ordered_items: None,
};
return Ok(serde_json::to_value(collection).unwrap());
};
// Otherwise, return the page
const PAGE_SIZE: u64 = 20;
let offset = (page_num - 1) * PAGE_SIZE;
let activities = ApActivities::find()
.filter(ap_activities::Column::ActorId.eq(actor_id))
.order_by_desc(ap_activities::Column::CreatedAt)
.offset(offset)
.limit(PAGE_SIZE)
.all(db)
.await?;
let items: Vec<serde_json::Value> = activities
.iter()
.filter_map(|a| serde_json::from_str(&a.activity_json).ok())
.collect();
let next_page = if offset + PAGE_SIZE < total {
Some(format!("{}?page={}", outbox_url, page_num + 1))
} else {
None
};
let page_url = format!("{}?page={}", outbox_url, page_num);
let page_obj = OrderedCollectionPage {
context: CONTEXT.to_vec(),
id: page_url,
kind: "OrderedCollectionPage",
total_items: total,
part_of: outbox_url.to_string(),
next: next_page,
ordered_items: items,
};
Ok(serde_json::to_value(page_obj).unwrap())
}