From fe30ad59d7a6036878083fd5ca5b6ca7ef319f5b Mon Sep 17 00:00:00 2001 From: alemi Date: Wed, 27 Mar 2024 04:23:42 +0100 Subject: [PATCH] feat: normalized pagination --- src/activitypub/user/following.rs | 89 ++++++++++++++++--------------- src/activitypub/user/mod.rs | 3 +- src/router.rs | 11 ++-- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/activitypub/user/following.rs b/src/activitypub/user/following.rs index 52360fe..d7a224d 100644 --- a/src/activitypub/user/following.rs +++ b/src/activitypub/user/following.rs @@ -3,7 +3,30 @@ use sea_orm::{ColumnTrait, Condition, EntityTrait, PaginatorTrait, QueryFilter, use crate::{activitypub::{jsonld::LD, JsonLD, Pagination}, activitystream::{object::collection::{page::CollectionPageMut, CollectionMut, CollectionType}, BaseMut, Node}, model, server::Context, url}; -pub async fn follow___( +use model::relation::Column::{Following, Follower}; + +pub async fn get( + State(ctx): State, + Path(id): Path, +) -> Result, StatusCode> { + let follow___ = if OUTGOING { "following" } else { "followers" }; + let count = model::relation::Entity::find() + .filter(Condition::all().add(if OUTGOING { Follower } else { Following }.eq(id.clone()))) + .count(ctx.db()).await.unwrap_or_else(|e| { + tracing::error!("failed counting {follow___} for {id}: {e}"); + 0 + }); + Ok(JsonLD( + serde_json::Value::new_object() + .set_id(Some(&format!("{}/users/{id}/{follow___}", ctx.base()))) + .set_collection_type(Some(CollectionType::OrderedCollection)) + .set_total_items(Some(count)) + .set_first(Node::link(format!("{}/users/{id}/{follow___}/page", ctx.base()))) + .ld_context() + )) +} + +pub async fn page( State(ctx): State, Path(id): Path, Query(page): Query, @@ -11,48 +34,26 @@ pub async fn follow___( let follow___ = if OUTGOING { "following" } else { "followers" }; let limit = page.batch.unwrap_or(20).min(50); let offset = page.offset.unwrap_or(0); - if let Some(true) = page.page { - - use model::relation::Column::{Following, Follower}; - match model::relation::Entity::find() - .filter(Condition::all().add(if OUTGOING { Follower } else { Following }.eq(id.clone()))) - .select_column(if OUTGOING { Following } else { Follower }) - .limit(limit) - .offset(page.offset.unwrap_or(0)) - .all(ctx.db()).await - { - Err(e) => { - tracing::error!("error queriying {follow___} for {id}: {e}"); - Err(StatusCode::INTERNAL_SERVER_ERROR) - }, - Ok(following) => { - Ok(JsonLD( - serde_json::Value::new_object() - .set_collection_type(Some(CollectionType::OrderedCollectionPage)) - .set_part_of(Node::link(url!(ctx, "/users/{id}/{follow___}"))) - .set_next(Node::link(url!(ctx, "/users/{id}/{follow___}?page=true&offset={}", offset+limit))) - .set_ordered_items(Node::array(following.into_iter().map(|x| x.following).collect())) - .ld_context() - )) - }, - } - - } else { - - let count = model::relation::Entity::find() - .filter(Condition::all().add(model::relation::Column::Follower.eq(id.clone()))) - .count(ctx.db()).await.unwrap_or_else(|e| { - tracing::error!("failed counting {follow___} for {id}: {e}"); - 0 - }); - Ok(JsonLD( - serde_json::Value::new_object() - .set_id(Some(&format!("{}/users/{id}/{follow___}", ctx.base()))) - .set_collection_type(Some(CollectionType::OrderedCollection)) - .set_total_items(Some(count)) - .set_first(Node::link(format!("{}/users/{id}/{follow___}?page=true", ctx.base()))) - .ld_context() - )) - + match model::relation::Entity::find() + .filter(Condition::all().add(if OUTGOING { Follower } else { Following }.eq(id.clone()))) + .select_column(if OUTGOING { Following } else { Follower }) + .limit(limit) + .offset(page.offset.unwrap_or(0)) + .all(ctx.db()).await + { + Err(e) => { + tracing::error!("error queriying {follow___} for {id}: {e}"); + Err(StatusCode::INTERNAL_SERVER_ERROR) + }, + Ok(following) => { + Ok(JsonLD( + serde_json::Value::new_object() + .set_collection_type(Some(CollectionType::OrderedCollectionPage)) + .set_part_of(Node::link(url!(ctx, "/users/{id}/{follow___}"))) + .set_next(Node::link(url!(ctx, "/users/{id}/{follow___}/page?offset={}", offset+limit))) + .set_ordered_items(Node::array(following.into_iter().map(|x| x.following).collect())) + .ld_context() + )) + }, } } diff --git a/src/activitypub/user/mod.rs b/src/activitypub/user/mod.rs index ea3b3e5..5a5bad4 100644 --- a/src/activitypub/user/mod.rs +++ b/src/activitypub/user/mod.rs @@ -2,8 +2,7 @@ pub mod inbox; pub mod outbox; -mod following; -pub use following::follow___; +pub mod following; use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; diff --git a/src/router.rs b/src/router.rs index 8f8c353..24141c5 100644 --- a/src/router.rs +++ b/src/router.rs @@ -21,13 +21,16 @@ pub async fn serve(db: DatabaseConnection, domain: String) { .route("/nodeinfo/:version", get(ap::well_known::nodeinfo)) // actor routes .route("/users/:id", get(ap::user::view)) - .route("/users/:id/inbox", get(ap::user::inbox::get)) .route("/users/:id/inbox", post(ap::user::inbox::post)) - .route("/users/:id/outbox", get(ap::user::outbox::get)) + .route("/users/:id/inbox", get(ap::user::inbox::get)) + .route("/users/:id/inbox/page", get(ap::user::inbox::page)) .route("/users/:id/outbox", post(ap::user::outbox::post)) + .route("/users/:id/outbox", get(ap::user::outbox::get)) .route("/users/:id/outbox/page", get(ap::user::outbox::page)) - .route("/users/:id/followers", get(ap::user::follow___::)) - .route("/users/:id/following", get(ap::user::follow___::)) + .route("/users/:id/followers", get(ap::user::following::get::)) + .route("/users/:id/followers/page", get(ap::user::following::page::)) + .route("/users/:id/following", get(ap::user::following::get::)) + .route("/users/:id/following/page", get(ap::user::following::page::)) // specific object routes .route("/activities/:id", get(ap::activity::view)) .route("/objects/:id", get(ap::object::view))