diff --git a/upub/core/src/selector/batch.rs b/upub/core/src/selector/batch.rs index 00aeab3..3892cd6 100644 --- a/upub/core/src/selector/batch.rs +++ b/upub/core/src/selector/batch.rs @@ -1,7 +1,7 @@ use std::collections::{hash_map::Entry, HashMap}; use sea_orm::{ConnectionTrait, DbErr, EntityTrait, FromQueryResult, ModelTrait, QueryFilter}; -use super::{RichActivity, RichObject}; +use super::RichActivity; #[async_trait::async_trait] pub trait BatchFillable: Sized { @@ -9,8 +9,7 @@ pub trait BatchFillable: Sized { where E: BatchFillableComparison + EntityTrait, E::Model: BatchFillableKey + Send + FromQueryResult + ModelTrait, - RichActivity: BatchFillableAcceptor>, - RichObject: BatchFillableAcceptor>; + RichActivity: BatchFillableAcceptor>; } @@ -22,7 +21,6 @@ impl BatchFillable for Vec { E: BatchFillableComparison + EntityTrait, E::Model: BatchFillableKey + Send + FromQueryResult + ModelTrait, RichActivity: BatchFillableAcceptor>, - RichObject: BatchFillableAcceptor> { let ids : Vec = self.iter().filter_map(|x| Some(x.object.as_ref()?.internal)).collect(); let batch = E::find() @@ -47,37 +45,6 @@ impl BatchFillable for Vec { } } -#[async_trait::async_trait] -impl BatchFillable for Vec { - // TODO 3 iterations... can we make it in less passes? - async fn with_batched(mut self, tx: &impl ConnectionTrait) -> Result - where - E: BatchFillableComparison + EntityTrait, - E::Model: BatchFillableKey + Send + FromQueryResult + ModelTrait, - RichActivity: BatchFillableAcceptor>, - RichObject: BatchFillableAcceptor> - { - let ids : Vec = self.iter().map(|x| x.object.internal).collect(); - let batch = E::find() - .filter(E::comparison(ids)) - .all(tx) - .await?; - let mut map : HashMap> = HashMap::new(); - for element in batch { - match map.entry(element.key()) { - Entry::Occupied(mut x) => { x.get_mut().push(element); }, - Entry::Vacant(x) => { x.insert(vec![element]); }, - } - } - for element in self.iter_mut() { - if let Some(v) = map.remove(&element.object.internal) { - element.accept(v, tx).await?; - } - } - Ok(self) - } -} - #[async_trait::async_trait] impl BatchFillable for RichActivity { async fn with_batched(mut self, tx: &impl ConnectionTrait) -> Result @@ -85,7 +52,6 @@ impl BatchFillable for RichActivity { E: BatchFillableComparison + EntityTrait, E::Model: BatchFillableKey + Send + FromQueryResult + ModelTrait, RichActivity: BatchFillableAcceptor>, - RichObject: BatchFillableAcceptor> { if let Some(ref obj) = self.object { let batch =E::find() @@ -98,24 +64,6 @@ impl BatchFillable for RichActivity { } } -#[async_trait::async_trait] -impl BatchFillable for RichObject { - async fn with_batched(mut self, tx: &impl ConnectionTrait) -> Result - where - E: BatchFillableComparison + EntityTrait, - E::Model: BatchFillableKey + Send + FromQueryResult + ModelTrait, - RichActivity: BatchFillableAcceptor>, - RichObject: BatchFillableAcceptor> - { - let batch = E::find() - .filter(E::comparison(vec![self.object.internal])) - .all(tx) - .await?; - self.accept(batch, tx).await?; - Ok(self) - } -} - // welcome to interlocking trait hell, enjoy your stay mod hell { @@ -207,42 +155,7 @@ use crate::selector::rich::{RichHashtag, RichMention}; Ok(()) } } - - #[async_trait::async_trait] - impl BatchFillableAcceptor> for super::RichObject { - async fn accept(&mut self, batch: Vec, _tx: &impl ConnectionTrait) -> Result<(), DbErr> { - self.attachments = Some(batch); - Ok(()) - } - } - - #[async_trait::async_trait] - impl BatchFillableAcceptor> for super::RichObject { - async fn accept(&mut self, batch: Vec, _tx: &impl ConnectionTrait) -> Result<(), DbErr> { - self.hashtags = Some(batch.into_iter().map(|x| RichHashtag { hash: x }).collect()); - Ok(()) - } - } - - #[async_trait::async_trait] - impl BatchFillableAcceptor> for super::RichObject { - async fn accept(&mut self, batch: Vec, tx: &impl ConnectionTrait) -> Result<(), DbErr> { - // TODO batch load users from mentions rather than doing for loop - let mut mentions = Vec::new(); - for row in batch { - // TODO filter only needed rows - if let Some(user) = crate::model::actor::Entity::find_by_id(row.actor).one(tx).await? { - mentions.push(RichMention { - mention: row, - fqn: format!("@{}@{}", user.preferred_username, user.domain), - id: user.id, - }); - } - } - self.mentions = Some(mentions); - Ok(()) - } - } } + use hell::*; diff --git a/upub/core/src/selector/mod.rs b/upub/core/src/selector/mod.rs index 6652c97..5b2e3a8 100644 --- a/upub/core/src/selector/mod.rs +++ b/upub/core/src/selector/mod.rs @@ -5,7 +5,7 @@ mod query; pub use query::Query; mod rich; -pub use rich::{RichObject, RichActivity}; +pub use rich::RichActivity; diff --git a/upub/core/src/selector/query.rs b/upub/core/src/selector/query.rs index 501f23d..16df43f 100644 --- a/upub/core/src/selector/query.rs +++ b/upub/core/src/selector/query.rs @@ -4,13 +4,13 @@ use crate::model; pub struct Query; impl Query { - pub fn activities(my_id: Option) -> Select { + pub fn feed(my_id: Option) -> Select { let mut select = model::addressing::Entity::find() .distinct_on([ (model::addressing::Entity, model::addressing::Column::Published).into_column_ref(), (model::activity::Entity, model::activity::Column::Internal).into_column_ref(), ]) - .join(sea_orm::JoinType::InnerJoin, model::addressing::Relation::Activities.def()) + .join(sea_orm::JoinType::LeftJoin, model::addressing::Relation::Activities.def()) .join(sea_orm::JoinType::LeftJoin, model::addressing::Relation::Objects.def()) .filter( // TODO ghetto double inner join because i want to filter out tombstones @@ -43,34 +43,6 @@ impl Query { select } - pub fn objects(my_id: Option) -> Select { - let mut select = model::addressing::Entity::find() - .distinct_on([ - (model::addressing::Entity, model::addressing::Column::Published).into_column_ref(), - (model::object::Entity, model::object::Column::Internal).into_column_ref(), - ]) - .join(sea_orm::JoinType::InnerJoin, model::addressing::Relation::Objects.def()) - .order_by(model::addressing::Column::Published, Order::Desc) - .order_by(model::object::Column::Internal, Order::Desc) - .select_only(); - - for col in model::object::Column::iter() { - select = select.select_column_as(col, format!("{}{}", model::object::Entity.table_name(), col.to_string())); - } - - if let Some(uid) = my_id { - select = select - .join( - sea_orm::JoinType::LeftJoin, - model::object::Relation::Likes.def() - .on_condition(move |_l, _r| model::like::Column::Actor.eq(uid).into_condition()), - ) - .select_column_as(model::like::Column::Actor, format!("{}{}", model::like::Entity.table_name(), model::like::Column::Actor.to_string())); - } - - select - } - pub fn related(from: Option, to: Option, pending: bool) -> Select { let mut condition = Condition::all(); diff --git a/upub/core/src/selector/rich.rs b/upub/core/src/selector/rich.rs index 5c83d15..b095061 100644 --- a/upub/core/src/selector/rich.rs +++ b/upub/core/src/selector/rich.rs @@ -31,7 +31,7 @@ impl RichHashtag { } pub struct RichActivity { - pub activity: crate::model::activity::Model, + pub activity: Option, pub object: Option, pub liked: Option, pub attachments: Option>, @@ -42,21 +42,27 @@ pub struct RichActivity { impl FromQueryResult for RichActivity { fn from_query_result(res: &QueryResult, _pre: &str) -> Result { Ok(RichActivity { - activity: crate::model::activity::Model::from_query_result(res, crate::model::activity::Entity.table_name())?, - object: crate::model::object::Model::from_query_result(res, crate::model::object::Entity.table_name()).ok(), - liked: res.try_get(crate::model::like::Entity.table_name(), &crate::model::like::Column::Actor.to_string()).ok(), attachments: None, hashtags: None, mentions: None, + liked: res.try_get(crate::model::like::Entity.table_name(), &crate::model::like::Column::Actor.to_string()).ok(), + object: crate::model::object::Model::from_query_result(res, crate::model::object::Entity.table_name()).ok(), + activity: crate::model::activity::Model::from_query_result(res, crate::model::activity::Entity.table_name()).ok(), }) } } +// TODO avoid repeating the tags code twice impl RichActivity { pub fn ap(self) -> serde_json::Value { use apb::ObjectMut; - let object = match self.object { - None => apb::Node::maybe_link(self.activity.object.clone()), - Some(o) => { - // TODO can we avoid repeating this tags code? + match (self.activity, self.object) { + (None, None) => serde_json::Value::Null, + + (Some(activity), None) => { + let obj = apb::Node::maybe_link(activity.object.clone()); + activity.ap().set_object(obj) + }, + + (None, Some(object)) => { let mut tags = Vec::new(); if let Some(mentions) = self.mentions { for mention in mentions { @@ -68,64 +74,44 @@ impl RichActivity { tags.push(hash.ap()); } } + object.ap() + .set_liked_by_me(if self.liked.is_some() { Some(true) } else { None }) + .set_tag(apb::Node::maybe_array(tags)) + .set_attachment(match self.attachments { + None => apb::Node::Empty, + Some(vec) => apb::Node::array( + vec.into_iter().map(|x| x.ap()).collect() + ), + }) + }, + + (Some(activity), Some(object)) => { + let mut tags = Vec::new(); + if let Some(mentions) = self.mentions { + for mention in mentions { + tags.push(mention.ap()); + } + } + if let Some(hashtags) = self.hashtags { + for hash in hashtags { + tags.push(hash.ap()); + } + } + activity.ap() + .set_object( apb::Node::object( - o.ap() - .set_liked_by_me(if self.liked.is_some() { Some(true) } else { None }) - .set_tag(apb::Node::array(tags)) - .set_attachment(match self.attachments { - None => apb::Node::Empty, - Some(vec) => apb::Node::array( - vec.into_iter().map(|x| x.ap()).collect() - ), - }) + object.ap() + .set_liked_by_me(if self.liked.is_some() { Some(true) } else { None }) + .set_tag(apb::Node::maybe_array(tags)) + .set_attachment(match self.attachments { + None => apb::Node::Empty, + Some(vec) => apb::Node::array( + vec.into_iter().map(|x| x.ap()).collect() + ), + }) + ) ) }, - }; - self.activity.ap().set_object(object) - } -} - -pub struct RichObject { - pub object: crate::model::object::Model, - pub liked: Option, - pub attachments: Option>, - pub hashtags: Option>, - pub mentions: Option>, -} - -impl FromQueryResult for RichObject { - fn from_query_result(res: &QueryResult, _pre: &str) -> Result { - Ok(RichObject { - object: crate::model::object::Model::from_query_result(res, crate::model::object::Entity.table_name())?, - liked: res.try_get(crate::model::like::Entity.table_name(), &crate::model::like::Column::Actor.to_string()).ok(), - attachments: None, hashtags: None, mentions: None, - }) - } -} - -impl RichObject { - pub fn ap(self) -> serde_json::Value { - use apb::ObjectMut; - // TODO can we avoid repeating this tags code? - let mut tags = Vec::new(); - if let Some(mentions) = self.mentions { - for mention in mentions { - tags.push(mention.ap()); - } } - if let Some(hashtags) = self.hashtags { - for hash in hashtags { - tags.push(hash.ap()); - } - } - self.object.ap() - .set_liked_by_me(if self.liked.is_some() { Some(true) } else { None }) - .set_tag(apb::Node::array(tags)) - .set_attachment(match self.attachments { - None => apb::Node::Empty, - Some(vec) => apb::Node::array( - vec.into_iter().map(|x| x.ap()).collect() - ) - }) } } diff --git a/upub/routes/src/activitypub/activity.rs b/upub/routes/src/activitypub/activity.rs index af6d003..97d0cd3 100644 --- a/upub/routes/src/activitypub/activity.rs +++ b/upub/routes/src/activitypub/activity.rs @@ -23,7 +23,7 @@ pub async fn view( } } - let row = upub::Query::activities(auth.my_id()) + let row = upub::Query::feed(auth.my_id()) .filter(model::activity::Column::Id.eq(&aid)) .filter(auth.filter_activities()) .into_model::() diff --git a/upub/routes/src/activitypub/actor/feed.rs b/upub/routes/src/activitypub/actor/feed.rs deleted file mode 100644 index b8de2dc..0000000 --- a/upub/routes/src/activitypub/actor/feed.rs +++ /dev/null @@ -1,47 +0,0 @@ -use axum::extract::{Path, Query, State}; -use sea_orm::{sea_query::IntoCondition, ColumnTrait}; - -use upub::Context; - -use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity, Identity}; - -pub async fn get( - State(ctx): State, - Path(id): Path, - AuthIdentity(auth): AuthIdentity, -) -> crate::ApiResult> { - match auth { - Identity::Anonymous => Err(crate::ApiError::forbidden()), - Identity::Remote { .. } => Err(crate::ApiError::forbidden()), - Identity::Local { id: user, .. } => if ctx.uid(&id) == user { - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/feed"), None) - } else { - Err(crate::ApiError::forbidden()) - }, - } -} - -pub async fn page( - State(ctx): State, - Path(id): Path, - AuthIdentity(auth): AuthIdentity, - Query(page): Query, -) -> crate::ApiResult> { - let Identity::Local { id: uid, internal } = &auth else { - // local inbox is only for local users - return Err(crate::ApiError::forbidden()); - }; - if uid != &ctx.uid(&id) { - return Err(crate::ApiError::forbidden()); - } - - crate::builders::paginate_objects( - upub::url!(ctx, "/actors/{id}/feed/page"), - upub::model::addressing::Column::Actor.eq(*internal).into_condition(), - ctx.db(), - page, - auth.my_id(), - false, - ) - .await -} diff --git a/upub/routes/src/activitypub/actor/inbox.rs b/upub/routes/src/activitypub/actor/inbox.rs index 5c5974c..98cd81f 100644 --- a/upub/routes/src/activitypub/actor/inbox.rs +++ b/upub/routes/src/activitypub/actor/inbox.rs @@ -35,7 +35,7 @@ pub async fn page( return Err(crate::ApiError::forbidden()); } - crate::builders::paginate_activities( + crate::builders::paginate_feed( upub::url!(ctx, "/actors/{id}/inbox/page"), upub::model::addressing::Column::Actor.eq(*internal).into_condition(), ctx.db(), diff --git a/upub/routes/src/activitypub/actor/mod.rs b/upub/routes/src/activitypub/actor/mod.rs index 4886772..66fc271 100644 --- a/upub/routes/src/activitypub/actor/mod.rs +++ b/upub/routes/src/activitypub/actor/mod.rs @@ -1,8 +1,6 @@ pub mod inbox; pub mod outbox; pub mod following; -pub mod feed; -pub mod streams; use axum::extract::{Path, Query, State}; @@ -58,7 +56,6 @@ pub async fn view( let mut user = user_model.ap() .set_inbox(Node::link(upub::url!(ctx, "/actors/{id}/inbox"))) .set_outbox(Node::link(upub::url!(ctx, "/actors/{id}/outbox"))) - .set_streams(Node::link(upub::url!(ctx, "/actors/{id}/streams"))) .set_following(Node::link(upub::url!(ctx, "/actors/{id}/following"))) .set_followers(Node::link(upub::url!(ctx, "/actors/{id}/followers"))) .set_following_me(following_me) @@ -93,8 +90,6 @@ pub async fn view( user_model.ap() .set_following_me(following_me) .set_followed_by_me(followed_by_me) - // TODO should we set streams?? we offer this collection but actor is remote - .set_streams(Node::link(upub::url!(ctx, "/actors/{id}/streams"))) .ld_context() )), None => Err(crate::ApiError::not_found()), diff --git a/upub/routes/src/activitypub/actor/outbox.rs b/upub/routes/src/activitypub/actor/outbox.rs index c84901f..949f707 100644 --- a/upub/routes/src/activitypub/actor/outbox.rs +++ b/upub/routes/src/activitypub/actor/outbox.rs @@ -19,7 +19,7 @@ pub async fn page( AuthIdentity(auth): AuthIdentity, ) -> crate::ApiResult> { let uid = ctx.uid(&id); - crate::builders::paginate_activities( + crate::builders::paginate_feed( upub::url!(ctx, "/actors/{id}/outbox/page"), Condition::all() .add(auth.filter_activities()) diff --git a/upub/routes/src/activitypub/actor/streams.rs b/upub/routes/src/activitypub/actor/streams.rs deleted file mode 100644 index 68d6c6b..0000000 --- a/upub/routes/src/activitypub/actor/streams.rs +++ /dev/null @@ -1,32 +0,0 @@ -use axum::extract::{Path, Query, State}; -use sea_orm::{ColumnTrait, Condition}; - -use upub::Context; - -use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity}; - -pub async fn get( - State(ctx): State, - Path(id): Path, -) -> crate::ApiResult> { - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/streams"), None) -} - -pub async fn page( - State(ctx): State, - Path(id): Path, - AuthIdentity(auth): AuthIdentity, - Query(page): Query, -) -> crate::ApiResult> { - crate::builders::paginate_objects( - upub::url!(ctx, "/actors/{id}/streams/page"), - Condition::all() - .add(auth.filter_objects()) - .add(upub::model::object::Column::AttributedTo.eq(ctx.uid(&id))), - ctx.db(), - page, - auth.my_id(), - false, - ) - .await -} diff --git a/upub/routes/src/activitypub/application.rs b/upub/routes/src/activitypub/application.rs index 115c193..b314d75 100644 --- a/upub/routes/src/activitypub/application.rs +++ b/upub/routes/src/activitypub/application.rs @@ -25,10 +25,6 @@ pub async fn view( .set_actor_type(Some(apb::ActorType::Application)) .set_name(Some(&ctx.cfg().instance.name)) .set_summary(Some(&ctx.cfg().instance.description)) - .set_streams(apb::Node::links(vec![ - upub::url!(ctx, "/feed"), - upub::url!(ctx, "/local"), - ])) .set_inbox(apb::Node::link(upub::url!(ctx, "/inbox"))) .set_outbox(apb::Node::link(upub::url!(ctx, "/outbox"))) .set_published(Some(ctx.actor().published)) diff --git a/upub/routes/src/activitypub/feed.rs b/upub/routes/src/activitypub/feed.rs deleted file mode 100644 index afa92b0..0000000 --- a/upub/routes/src/activitypub/feed.rs +++ /dev/null @@ -1,29 +0,0 @@ -use axum::extract::{Query, State}; -use upub::Context; - -use crate::{AuthIdentity, builders::JsonLD}; - -use super::Pagination; - - -pub async fn get( - State(ctx): State, -) -> crate::ApiResult> { - crate::builders::collection(&upub::url!(ctx, "/feed"), None) -} - -pub async fn page( - State(ctx): State, - AuthIdentity(auth): AuthIdentity, - Query(page): Query, -) -> crate::ApiResult> { - crate::builders::paginate_objects( - upub::url!(ctx, "/feed/page"), - auth.filter_objects(), - ctx.db(), - page, - auth.my_id(), - false, - ) - .await -} diff --git a/upub/routes/src/activitypub/inbox.rs b/upub/routes/src/activitypub/inbox.rs index 4d64594..fc79380 100644 --- a/upub/routes/src/activitypub/inbox.rs +++ b/upub/routes/src/activitypub/inbox.rs @@ -19,7 +19,7 @@ pub async fn page( AuthIdentity(auth): AuthIdentity, Query(page): Query, ) -> crate::ApiResult> { - crate::builders::paginate_activities( + crate::builders::paginate_feed( upub::url!(ctx, "/inbox/page"), auth.filter_activities(), ctx.db(), diff --git a/upub/routes/src/activitypub/mod.rs b/upub/routes/src/activitypub/mod.rs index f04d3a2..c1a49e4 100644 --- a/upub/routes/src/activitypub/mod.rs +++ b/upub/routes/src/activitypub/mod.rs @@ -1,7 +1,6 @@ pub mod actor; pub mod inbox; pub mod outbox; -pub mod feed; pub mod object; pub mod activity; pub mod application; @@ -32,8 +31,6 @@ impl ActivityPubRouter for Router { .route("/outbox", post(ap::outbox::post)) .route("/outbox", get(ap::outbox::get)) .route("/outbox/page", get(ap::outbox::page)) - .route("/feed", get(ap::feed::get)) - .route("/feed/page", get(ap::feed::page)) // AUTH routes .route("/auth", put(ap::auth::register)) .route("/auth", post(ap::auth::login)) @@ -52,10 +49,6 @@ impl ActivityPubRouter for Router { .route("/actors/:id/outbox", post(ap::actor::outbox::post)) .route("/actors/:id/outbox", get(ap::actor::outbox::get)) .route("/actors/:id/outbox/page", get(ap::actor::outbox::page)) - .route("/actors/:id/streams", get(ap::actor::streams::get)) - .route("/actors/:id/streams/page", get(ap::actor::streams::page)) - .route("/actors/:id/feed", get(ap::actor::feed::get)) - .route("/actors/:id/feed/page", get(ap::actor::feed::page)) .route("/actors/:id/followers", get(ap::actor::following::get::)) .route("/actors/:id/followers/page", get(ap::actor::following::page::)) .route("/actors/:id/following", get(ap::actor::following::get::)) diff --git a/upub/routes/src/activitypub/object/context.rs b/upub/routes/src/activitypub/object/context.rs index 62d654c..9d8a6b3 100644 --- a/upub/routes/src/activitypub/object/context.rs +++ b/upub/routes/src/activitypub/object/context.rs @@ -11,7 +11,7 @@ pub async fn get( ) -> crate::ApiResult> { let context = ctx.oid(&id); - let count = upub::Query::objects(auth.my_id()) + let count = upub::Query::feed(auth.my_id()) .filter(auth.filter_objects()) .filter(model::object::Column::Context.eq(&context)) .count(ctx.db()) @@ -28,7 +28,7 @@ pub async fn page( ) -> crate::ApiResult> { let context = ctx.oid(&id); - crate::builders::paginate_objects( + crate::builders::paginate_feed( upub::url!(ctx, "/objects/{id}/context/page"), Condition::all() .add(auth.filter_objects()) diff --git a/upub/routes/src/activitypub/object/mod.rs b/upub/routes/src/activitypub/object/mod.rs index 1770ff9..f47b4b2 100644 --- a/upub/routes/src/activitypub/object/mod.rs +++ b/upub/routes/src/activitypub/object/mod.rs @@ -4,7 +4,7 @@ pub mod context; use apb::{BaseMut, CollectionMut, ObjectMut, LD}; use axum::extract::{Path, Query, State}; use sea_orm::{ColumnTrait, QueryFilter, QuerySelect, SelectColumns, TransactionTrait}; -use upub::{model, selector::{BatchFillable, RichObject}, traits::Fetcher, Context}; +use upub::{model, selector::{BatchFillable, RichActivity}, traits::Fetcher, Context}; use crate::{builders::JsonLD, AuthIdentity}; @@ -27,10 +27,10 @@ pub async fn view( } } - let item = upub::Query::objects(auth.my_id()) + let item = upub::Query::feed(auth.my_id()) .filter(model::object::Column::Id.eq(&oid)) .filter(auth.filter_objects()) - .into_model::() + .into_model::() .one(ctx.db()) .await? .ok_or_else(crate::ApiError::not_found)? @@ -45,7 +45,7 @@ pub async fn view( let mut replies = apb::Node::Empty; if ctx.cfg().security.show_reply_ids { - let replies_ids = upub::Query::objects(auth.my_id()) + let replies_ids = upub::Query::feed(auth.my_id()) .filter(model::object::Column::InReplyTo.eq(oid)) .filter(auth.filter_objects()) .select_only() @@ -59,7 +59,7 @@ pub async fn view( .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(Some(item.object.replies as u64)) + .set_total_items(item.object.as_ref().map(|x| x.replies as u64)) .set_items(apb::Node::links(replies_ids)) ); } diff --git a/upub/routes/src/activitypub/object/replies.rs b/upub/routes/src/activitypub/object/replies.rs index d306c4b..12ae3ea 100644 --- a/upub/routes/src/activitypub/object/replies.rs +++ b/upub/routes/src/activitypub/object/replies.rs @@ -15,7 +15,7 @@ pub async fn get( // ctx.fetch_thread(&oid).await?; // } - let replies_ids = upub::Query::objects(auth.my_id()) + let replies_ids = upub::Query::feed(auth.my_id()) .filter(model::object::Column::InReplyTo.eq(ctx.oid(&id))) .filter(auth.filter_objects()) .select_only() @@ -44,7 +44,7 @@ pub async fn page( let page_id = upub::url!(ctx, "/objects/{id}/replies/page"); let oid = ctx.oid(&id); - crate::builders::paginate_objects( + crate::builders::paginate_feed( page_id, Condition::all() .add(auth.filter_objects()) diff --git a/upub/routes/src/activitypub/outbox.rs b/upub/routes/src/activitypub/outbox.rs index 2df92c6..1c5c91f 100644 --- a/upub/routes/src/activitypub/outbox.rs +++ b/upub/routes/src/activitypub/outbox.rs @@ -13,7 +13,7 @@ pub async fn page( Query(page): Query, AuthIdentity(auth): AuthIdentity, ) -> crate::ApiResult> { - crate::builders::paginate_activities( + crate::builders::paginate_feed( upub::url!(ctx, "/outbox/page"), Condition::all() .add(auth.filter_activities()) diff --git a/upub/routes/src/builders.rs b/upub/routes/src/builders.rs index 47d73cc..d7b1425 100644 --- a/upub/routes/src/builders.rs +++ b/upub/routes/src/builders.rs @@ -1,11 +1,11 @@ use apb::{BaseMut, CollectionMut, CollectionPageMut, LD}; use sea_orm::{Condition, ConnectionTrait, QueryFilter, QuerySelect, RelationTrait}; use axum::response::{IntoResponse, Response}; -use upub::selector::{BatchFillable, RichActivity, RichObject}; +use upub::selector::{BatchFillable, RichActivity}; use crate::activitypub::Pagination; -pub async fn paginate_activities( +pub async fn paginate_feed( id: String, filter: Condition, db: &impl ConnectionTrait, @@ -16,7 +16,7 @@ pub async fn paginate_activities( let limit = page.batch.unwrap_or(20).min(50); let offset = page.offset.unwrap_or(0); - let mut select = upub::Query::activities(my_id); + let mut select = upub::Query::feed(my_id); if with_users { select = select @@ -46,52 +46,6 @@ pub async fn paginate_activities( collection_page(&id, offset, limit, items) } -// TODO can we merge these two??? there are basically only three differences - -pub async fn paginate_objects( - id: String, - filter: Condition, - db: &impl ConnectionTrait, - page: Pagination, - my_id: Option, - with_users: bool, // TODO ewww too many arguments for this weird function... -) -> crate::ApiResult> { - let limit = page.batch.unwrap_or(20).min(50); - let offset = page.offset.unwrap_or(0); - - let mut select = upub::Query::objects(my_id); // <--- difference one - - if with_users { - select = select - .join( - sea_orm::JoinType::InnerJoin, - upub::model::object::Relation::Actors.def() // <--- difference two - ); - } - - let items = select - .filter(filter) - // TODO also limit to only local activities - .limit(limit) - .offset(offset) - .into_model::() // <--- difference three - .all(db) - .await? - .with_batched::(db) - .await? - .with_batched::(db) - .await? - .with_batched::(db) - .await?; - - let items : Vec = items - .into_iter() - .map(|item| item.ap()) - .collect(); - - collection_page(&id, offset, limit, items) -} - pub fn collection_page(id: &str, offset: u64, limit: u64, items: Vec) -> crate::ApiResult> { let next = if items.len() < limit as usize { apb::Node::Empty