diff --git a/upub/routes/src/activitypub/object/mod.rs b/upub/routes/src/activitypub/object/mod.rs index 15c2e2f..e4b413c 100644 --- a/upub/routes/src/activitypub/object/mod.rs +++ b/upub/routes/src/activitypub/object/mod.rs @@ -1,9 +1,9 @@ pub mod replies; pub mod context; -use apb::{BaseMut, CollectionMut, ObjectMut, LD}; +use apb::{BaseMut, Object, ObjectMut, LD}; use axum::extract::{Path, Query, State}; -use sea_orm::{ColumnTrait, QueryFilter, QuerySelect, SelectColumns, TransactionTrait}; +use sea_orm::{ColumnTrait, QueryFilter, TransactionTrait}; use upub::{model, selector::{BatchFillable, RichActivity}, traits::Fetcher, Context}; use crate::{builders::JsonLD, AuthIdentity}; @@ -27,7 +27,9 @@ pub async fn view( } } - let item = upub::Query::objects(auth.my_id()) + let replies_url = upub::url!(ctx, "/objects/{id}/replies"); + + let item_model = upub::Query::objects(auth.my_id()) .filter(auth.filter_objects()) .filter(model::object::Column::Id.eq(&oid)) .into_model::() @@ -41,31 +43,17 @@ pub async fn view( .with_batched::(ctx.db()) .await?; - let mut replies = apb::Node::Empty; - - if ctx.cfg().security.show_reply_ids { - let replies_ids = upub::Query::objects(auth.my_id()) - .filter(auth.filter_objects()) - .filter(model::object::Column::InReplyTo.eq(oid)) - .select_only() - .select_column(model::object::Column::Id) - .into_tuple::() - .all(ctx.db()) - .await?; + let mut item = ctx.ap(item_model); - replies = apb::Node::object( - apb::new() - .set_id(Some(upub::url!(ctx, "/objects/{id}/replies"))) - .set_first(apb::Node::link(upub::url!(ctx, "/objects/{id}/replies/page"))) - .set_collection_type(Some(apb::CollectionType::Collection)) - .set_total_items(item.object.as_ref().map(|x| x.replies as u64)) - .set_items(apb::Node::links(replies_ids)) - ); - } - - Ok(JsonLD( - item.object_ap() - .set_replies(replies) - .ld_context() - )) + let replies_patched = + apb::Node::object( + item.replies() + .into_inner() + .unwrap() + .set_id(Some(replies_url)) + ); + + item = item.set_replies(replies_patched); + + Ok(JsonLD(item.ld_context())) } diff --git a/upub/routes/src/activitypub/object/replies.rs b/upub/routes/src/activitypub/object/replies.rs index 861d811..2174699 100644 --- a/upub/routes/src/activitypub/object/replies.rs +++ b/upub/routes/src/activitypub/object/replies.rs @@ -1,9 +1,9 @@ -use apb::{BaseMut, CollectionMut, LD}; +use apb::{BaseMut, CollectionMut, CollectionPageMut, LD}; use axum::extract::{Path, Query, State}; -use sea_orm::{ColumnTrait, Condition, QueryFilter, QuerySelect, SelectColumns}; +use sea_orm::{ColumnTrait, ConnectionTrait, PaginatorTrait, QueryFilter, QuerySelect, SelectColumns}; use upub::{model, traits::Fetcher, Context}; -use crate::{activitypub::{Pagination, TryFetch}, builders::JsonLD, AuthIdentity}; +use crate::{activitypub::{Pagination, TryFetch}, builders::JsonLD, ApiResult, AuthIdentity, Identity}; pub async fn get( State(ctx): State, @@ -21,22 +21,21 @@ pub async fn get( ctx.fetch_thread(&oid, ctx.db()).await?; } - let replies_ids = upub::Query::objects(auth.my_id()) - .filter(auth.filter_objects()) - .filter(model::object::Column::InReplyTo.eq(ctx.oid(&id))) - .select_only() - .select_column(model::object::Column::Id) - .into_tuple::() - .all(ctx.db()) - .await?; + let replies_count = total_replies(&oid, &auth, ctx.db()).await?; + let replies_ids = replies_ids(&oid, &auth, ctx.db(), 20, 0).await?; + + let first = apb::new() + .set_id(Some(upub::url!(ctx, "/objects/{id}/replies/page"))) + .set_collection_type(Some(apb::CollectionType::OrderedCollectionPage)) + .set_next(apb::Node::link(upub::url!(ctx, "/objects/{id}/replies/page?offset=20"))) + .set_ordered_items(apb::Node::links(replies_ids)); Ok(JsonLD( apb::new() .set_id(Some(upub::url!(ctx, "/objects/{id}/replies"))) .set_collection_type(Some(apb::CollectionType::Collection)) - .set_first(apb::Node::link(upub::url!(ctx, "/objects/{id}/replies/page"))) - .set_total_items(Some(replies_ids.len() as u64)) - .set_items(apb::Node::links(replies_ids)) + .set_total_items(Some(replies_count)) + .set_first(apb::Node::object(first)) .ld_context() )) } @@ -49,19 +48,40 @@ pub async fn page( ) -> crate::ApiResult> { let page_id = upub::url!(ctx, "/objects/{id}/replies/page"); let oid = ctx.oid(&id); + let (limit, offset) = page.pagination(); // TODO kinda weird ignoring this but its weirder to exclude replies from replies view... page.replies = Some(true); - crate::builders::paginate_feed( - page_id, - Condition::all() - .add(auth.filter_activities()) - .add(model::object::Column::InReplyTo.eq(oid)), - ctx.db(), - page, - auth.my_id(), - false, + let replies_ids = replies_ids(&oid, &auth, ctx.db(), limit, offset).await?; + + crate::builders::collection_page( + &page_id, + offset, + limit, + apb::Node::links(replies_ids) ) - .await +} + +async fn replies_ids(oid: &str, auth: &Identity, db: &impl ConnectionTrait, limit: u64, offset: u64) -> ApiResult> { + let res = upub::Query::objects(auth.my_id()) + .limit(limit) + .offset(offset) + .filter(auth.filter_objects()) + .filter(model::object::Column::InReplyTo.eq(oid)) + .select_only() + .select_column(model::object::Column::Id) + .into_tuple::() + .all(db) + .await?; + Ok(res) +} + +async fn total_replies(oid: &str, auth: &Identity, db: &impl ConnectionTrait) -> ApiResult { + let count = upub::Query::objects(None) + .filter(auth.filter_objects()) + .filter(model::object::Column::InReplyTo.eq(oid)) + .count(db) + .await?; + Ok(count) }