chore: finally rid us of builders::paginate_feed
for good
This commit is contained in:
parent
437908f7d5
commit
129213204a
18 changed files with 194 additions and 204 deletions
|
@ -3,6 +3,27 @@ use std::collections::{hash_map::Entry, HashMap};
|
|||
use sea_orm::{ConnectionTrait, DbErr, EntityTrait, FromQueryResult, ModelTrait, QueryFilter};
|
||||
use super::{RichActivity, RichObject};
|
||||
|
||||
#[allow(async_fn_in_trait)]
|
||||
pub trait RichFillable: Sized {
|
||||
async fn load_batched_models(self, tx: &impl ConnectionTrait) -> Result<Self, DbErr>;
|
||||
}
|
||||
|
||||
impl<T> RichFillable for T
|
||||
where
|
||||
T: BatchFillable
|
||||
{
|
||||
async fn load_batched_models(self, tx: &impl ConnectionTrait) -> Result<Self, DbErr> {
|
||||
self
|
||||
.with_batched::<crate::model::attachment::Entity>(tx)
|
||||
.await?
|
||||
.with_batched::<crate::model::mention::Entity>(tx)
|
||||
.await?
|
||||
.with_batched::<crate::model::hashtag::Entity>(tx)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(async_fn_in_trait)]
|
||||
pub trait BatchFillable: Sized {
|
||||
async fn with_batched<E>(self, tx: &impl ConnectionTrait) -> Result<Self, DbErr>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
mod batch;
|
||||
pub use batch::BatchFillable;
|
||||
pub use batch::{BatchFillable, RichFillable};
|
||||
|
||||
mod query;
|
||||
pub use query::Query;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::model;
|
|||
pub struct Query;
|
||||
|
||||
impl Query {
|
||||
pub fn feed(my_id: Option<i64>) -> Select<model::addressing::Entity> {
|
||||
pub fn feed(my_id: Option<i64>, with_replies: bool) -> Select<model::addressing::Entity> {
|
||||
let mut select = model::addressing::Entity::find()
|
||||
.distinct_on([
|
||||
(model::addressing::Entity, model::addressing::Column::Published).into_column_ref(),
|
||||
|
@ -45,10 +45,14 @@ impl Query {
|
|||
.select_column_as(model::like::Column::Actor, format!("{}{}", model::like::Entity.table_name(), model::like::Column::Actor.to_string()));
|
||||
}
|
||||
|
||||
if !with_replies {
|
||||
select = select.filter(model::object::Column::InReplyTo.is_null());
|
||||
}
|
||||
|
||||
select
|
||||
}
|
||||
|
||||
pub fn objects(my_id: Option<i64>) -> Select<model::addressing::Entity> {
|
||||
pub fn objects(my_id: Option<i64>, with_replies: bool) -> Select<model::addressing::Entity> {
|
||||
let mut select = model::addressing::Entity::find()
|
||||
.distinct()
|
||||
.join(sea_orm::JoinType::InnerJoin, model::addressing::Relation::Objects.def())
|
||||
|
@ -68,6 +72,10 @@ impl Query {
|
|||
.select_column_as(model::like::Column::Actor, format!("{}{}", model::like::Entity.table_name(), model::like::Column::Actor.to_string()));
|
||||
}
|
||||
|
||||
if !with_replies {
|
||||
select = select.filter(model::object::Column::InReplyTo.is_null());
|
||||
}
|
||||
|
||||
select
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, QueryFilter, TransactionTrait};
|
||||
use upub::{model, selector::{BatchFillable, RichActivity}, traits::Fetcher, Context};
|
||||
use sea_orm::{ColumnTrait, Condition, QueryFilter, TransactionTrait};
|
||||
use upub::{model, selector::{RichActivity, RichFillable}, traits::Fetcher, Context};
|
||||
use apb::LD;
|
||||
|
||||
use crate::{builders::JsonLD, AuthIdentity};
|
||||
|
@ -23,20 +23,19 @@ pub async fn view(
|
|||
}
|
||||
}
|
||||
|
||||
let row = upub::Query::feed(auth.my_id())
|
||||
.filter(auth.filter_activities())
|
||||
.filter(model::activity::Column::Id.eq(&aid))
|
||||
let filter = Condition::all()
|
||||
.add(auth.filter_activities())
|
||||
.add(model::activity::Column::Id.eq(&aid));
|
||||
|
||||
let activity = upub::Query::feed(auth.my_id(), true)
|
||||
.filter(filter)
|
||||
.into_model::<RichActivity>()
|
||||
.one(ctx.db())
|
||||
.await?
|
||||
.ok_or_else(crate::ApiError::not_found)?
|
||||
.with_batched::<upub::model::attachment::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::mention::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::hashtag::Entity>(ctx.db())
|
||||
.load_batched_models(ctx.db())
|
||||
.await?;
|
||||
|
||||
Ok(JsonLD(ctx.ap(row).ld_context()))
|
||||
Ok(JsonLD(ctx.ap(activity).ld_context()))
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ pub async fn page<const OUTGOING: bool>(
|
|||
use upub::model::relation::Column::{Follower, Following, FollowerInstance, FollowingInstance};
|
||||
let follow___ = if OUTGOING { "following" } else { "followers" };
|
||||
|
||||
let (limit, offset) = page.pagination();
|
||||
let (limit, _offset) = page.pagination();
|
||||
|
||||
let (user, config) = model::actor::Entity::find_by_ap_id(&ctx.uid(&id))
|
||||
.find_also_related(model::config::Entity)
|
||||
|
@ -117,7 +117,7 @@ pub async fn page<const OUTGOING: bool>(
|
|||
|
||||
crate::builders::collection_page(
|
||||
&upub::url!(ctx, "/actors/{id}/{follow___}/page"),
|
||||
offset, limit,
|
||||
page,
|
||||
apb::Node::links(following),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use axum::{http::StatusCode, extract::{Path, Query, State}, Json};
|
||||
use sea_orm::{ColumnTrait, Condition};
|
||||
use sea_orm::{ColumnTrait, Condition, QueryFilter, QuerySelect};
|
||||
|
||||
use upub::Context;
|
||||
use upub::{selector::{RichActivity, RichFillable}, Context};
|
||||
|
||||
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity, Identity};
|
||||
|
||||
|
@ -35,18 +35,26 @@ pub async fn page(
|
|||
return Err(crate::ApiError::forbidden());
|
||||
}
|
||||
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/actors/{id}/inbox/page"),
|
||||
Condition::any()
|
||||
let filter = Condition::any()
|
||||
.add(upub::model::addressing::Column::Actor.eq(*internal))
|
||||
.add(upub::model::activity::Column::Actor.eq(uid))
|
||||
.add(upub::model::object::Column::AttributedTo.eq(uid)),
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.add(upub::model::object::Column::AttributedTo.eq(uid));
|
||||
|
||||
let (limit, offset) = page.pagination();
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichActivity>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/inbox/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
||||
pub async fn post(
|
||||
|
|
|
@ -31,15 +31,13 @@ pub async fn page(
|
|||
|
||||
let (limit, offset) = page.pagination();
|
||||
|
||||
let mut select = upub::Query::objects(auth.my_id())
|
||||
let items : Vec<serde_json::Value> = upub::Query::objects(auth.my_id(), true)
|
||||
.join(sea_orm::JoinType::InnerJoin, upub::model::object::Relation::Likes.def())
|
||||
.filter(auth.filter_objects())
|
||||
.filter(upub::model::like::Column::Actor.eq(user.internal))
|
||||
.order_by_desc(upub::model::like::Column::Published)
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
let items : Vec<serde_json::Value> = select
|
||||
.offset(offset)
|
||||
.into_model::<RichObject>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
|
@ -53,13 +51,5 @@ pub async fn page(
|
|||
.map(|x| ctx.ap(x))
|
||||
.collect();
|
||||
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/actors/{id}/outbox/page"),
|
||||
auth.filter_objects(),
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/outbox/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
|
|
@ -51,6 +51,6 @@ pub async fn page(
|
|||
.map(|x| ctx.ap(x))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/notifications/page"), offset, limit, apb::Node::array(activities))
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/notifications/page"), page, apb::Node::array(activities))
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use axum::{extract::{Path, Query, State}, http::StatusCode, Json};
|
||||
use sea_orm::{ActiveValue::{NotSet, Set}, ColumnTrait, Condition, EntityTrait};
|
||||
use sea_orm::{ActiveValue::{NotSet, Set}, ColumnTrait, Condition, EntityTrait, QueryFilter, QuerySelect};
|
||||
|
||||
use upub::{model, Context};
|
||||
use upub::{model, selector::{RichActivity, RichFillable}, Context};
|
||||
|
||||
use crate::{activitypub::{CreationResult, Pagination}, builders::JsonLD, AuthIdentity, Identity};
|
||||
|
||||
|
@ -28,15 +28,23 @@ pub async fn page(
|
|||
.add(model::object::Column::Audience.eq(&uid))
|
||||
);
|
||||
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/actors/{id}/outbox/page"),
|
||||
filter,
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
let (limit, offset) = page.pagination();
|
||||
// by default we want replies because servers don't know about our api and need to see everything
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
// TODO also limit to only local activities
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichActivity>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/outbox/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
||||
pub async fn post(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use apb::{LD, ActorMut, BaseMut, ObjectMut, PublicKeyMut};
|
||||
use axum::{extract::{Path, Query, State}, http::HeaderMap, response::{IntoResponse, Redirect, Response}};
|
||||
use reqwest::Method;
|
||||
use sea_orm::{Condition, ColumnTrait};
|
||||
use upub::{traits::{Cloaker, Fetcher}, Context};
|
||||
use sea_orm::{ColumnTrait, Condition, QueryFilter, QuerySelect};
|
||||
use upub::{selector::{RichFillable, RichObject}, traits::{Cloaker, Fetcher}, Context};
|
||||
|
||||
use crate::{builders::JsonLD, ApiError, AuthIdentity};
|
||||
|
||||
|
@ -57,21 +57,28 @@ pub async fn search(
|
|||
|
||||
// TODO lmao rethink this all
|
||||
// still haven't redone this gg me
|
||||
// have redone it but didnt rethink it properly so we're stuck with this bahahaha
|
||||
let page = Pagination {
|
||||
offset: page.offset,
|
||||
batch: page.batch,
|
||||
replies: Some(true),
|
||||
};
|
||||
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/search"),
|
||||
filter,
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
let (limit, offset) = page.pagination();
|
||||
let items = upub::Query::feed(auth.my_id(), true)
|
||||
.filter(filter)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichObject>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/search"), page, apb::Node::array(items))
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use apb::{Activity, ActivityType, Base};
|
||||
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
||||
use sea_orm::{sea_query::IntoCondition, ActiveValue::{NotSet, Set}, ColumnTrait, EntityTrait};
|
||||
use upub::{model::job::JobType, Context};
|
||||
use sea_orm::{sea_query::IntoCondition, ActiveValue::{NotSet, Set}, ColumnTrait, EntityTrait, QueryFilter, QuerySelect};
|
||||
use upub::{model::job::JobType, selector::{RichActivity, RichFillable}, Context};
|
||||
|
||||
use crate::{AuthIdentity, Identity, builders::JsonLD};
|
||||
|
||||
|
@ -19,24 +19,23 @@ pub async fn page(
|
|||
AuthIdentity(auth): AuthIdentity,
|
||||
Query(page): Query<Pagination>,
|
||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/inbox/page"),
|
||||
upub::model::addressing::Column::Actor.is_null().into_condition(),
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
let filter = upub::model::addressing::Column::Actor.is_null().into_condition();
|
||||
let (limit, offset) = page.pagination();
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichActivity>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/inbox/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
||||
macro_rules! pretty_json {
|
||||
($json:ident) => {
|
||||
serde_json::to_string_pretty(&$json).expect("failed serializing to string serde_json::Value")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn post(
|
||||
State(ctx): State<Context>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
|
@ -52,7 +51,10 @@ pub async fn post(
|
|||
// would be cool if mastodon played nicer with the network...
|
||||
return Ok(StatusCode::OK);
|
||||
}
|
||||
tracing::warn!("refusing unauthorized activity: {}", pretty_json!(activity));
|
||||
tracing::warn!(
|
||||
"refusing unauthorized activity: {}",
|
||||
serde_json::to_string_pretty(&activity).expect("failed serializing to string serde_json::Value?")
|
||||
);
|
||||
if matches!(auth, Identity::Anonymous) {
|
||||
return Err(crate::ApiError::unauthorized());
|
||||
} else {
|
||||
|
|
|
@ -88,7 +88,7 @@ pub struct TryFetch {
|
|||
pub fetch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, serde::Deserialize)]
|
||||
// TODO i don't really like how pleroma/mastodon do it actually, maybe change this?
|
||||
pub struct Pagination {
|
||||
pub offset: Option<u64>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect};
|
||||
use upub::{model, selector::{BatchFillable, RichObject}, Context};
|
||||
use sea_orm::{ColumnTrait, Condition, PaginatorTrait, QueryFilter, QuerySelect};
|
||||
use upub::{model, selector::{RichFillable, RichObject}, Context};
|
||||
|
||||
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity};
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub async fn get(
|
|||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
let context = ctx.oid(&id);
|
||||
|
||||
let count = upub::Query::objects(auth.my_id())
|
||||
let count = upub::Query::objects(auth.my_id(), true)
|
||||
.filter(auth.filter_objects())
|
||||
.filter(model::object::Column::Context.eq(&context))
|
||||
.count(ctx.db())
|
||||
|
@ -23,33 +23,30 @@ pub async fn get(
|
|||
pub async fn page(
|
||||
State(ctx): State<Context>,
|
||||
Path(id): Path<String>,
|
||||
Query(page): Query<Pagination>,
|
||||
Query(mut page): Query<Pagination>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
let context = ctx.oid(&id);
|
||||
|
||||
let filter = Condition::all()
|
||||
.add(auth.filter_objects())
|
||||
.add(model::object::Column::Context.eq(context));
|
||||
|
||||
page.replies = Some(true); // TODO ugly that we have to force set it this way...
|
||||
let (limit, offset) = page.pagination();
|
||||
|
||||
let items = upub::Query::objects(auth.my_id())
|
||||
.filter(auth.filter_objects())
|
||||
.filter(model::object::Column::Context.eq(context))
|
||||
// note that this should be ASC so we get replies somewhat ordered
|
||||
.order_by_asc(model::object::Column::Published)
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichObject>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::attachment::Entity>(ctx.db())
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::mention::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::hashtag::Entity>(ctx.db())
|
||||
.await?;
|
||||
|
||||
let items : Vec<serde_json::Value> = items
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/objects/{id}/context/page"), offset, limit, apb::Node::array(items))
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/objects/{id}/context/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ pub mod context;
|
|||
|
||||
use apb::LD;
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, QueryFilter, TransactionTrait};
|
||||
use upub::{model, selector::{BatchFillable, RichObject}, traits::Fetcher, Context};
|
||||
use sea_orm::{ColumnTrait, Condition, QueryFilter, TransactionTrait};
|
||||
use upub::{model, selector::{RichFillable, RichObject}, traits::Fetcher, Context};
|
||||
|
||||
use crate::{builders::JsonLD, AuthIdentity};
|
||||
|
||||
|
@ -27,19 +27,18 @@ pub async fn view(
|
|||
}
|
||||
}
|
||||
|
||||
let item = upub::Query::objects(auth.my_id())
|
||||
.filter(auth.filter_objects())
|
||||
.filter(model::object::Column::Id.eq(&oid))
|
||||
let filter = Condition::all()
|
||||
.add(auth.filter_objects())
|
||||
.add(model::object::Column::Id.eq(&oid));
|
||||
|
||||
let object = upub::Query::feed(auth.my_id(), true)
|
||||
.filter(filter)
|
||||
.into_model::<RichObject>()
|
||||
.one(ctx.db())
|
||||
.await?
|
||||
.ok_or_else(crate::ApiError::not_found)?
|
||||
.with_batched::<upub::model::attachment::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::mention::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::hashtag::Entity>(ctx.db())
|
||||
.load_batched_models(ctx.db())
|
||||
.await?;
|
||||
|
||||
Ok(JsonLD(ctx.ap(item).ld_context()))
|
||||
Ok(JsonLD(ctx.ap(object).ld_context()))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use apb::{BaseMut, CollectionMut, LD};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect};
|
||||
use upub::{model, selector::RichObject, traits::Fetcher, Context};
|
||||
use sea_orm::{ColumnTrait, Condition, PaginatorTrait, QueryFilter, QuerySelect};
|
||||
use upub::{model, selector::{RichFillable, RichObject}, traits::Fetcher, Context};
|
||||
|
||||
use crate::{activitypub::{Pagination, TryFetch}, builders::JsonLD, AuthIdentity};
|
||||
|
||||
|
@ -21,7 +21,7 @@ pub async fn get(
|
|||
ctx.fetch_thread(&oid, ctx.db()).await?;
|
||||
}
|
||||
|
||||
let total_replies = upub::Query::objects(None)
|
||||
let total_replies = upub::Query::objects(None, true)
|
||||
.filter(auth.filter_objects())
|
||||
.filter(model::object::Column::InReplyTo.eq(&oid))
|
||||
.count(ctx.db())
|
||||
|
@ -43,30 +43,29 @@ pub async fn page(
|
|||
Query(mut page): Query<Pagination>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
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);
|
||||
|
||||
let res = upub::Query::objects(auth.my_id())
|
||||
let filter = Condition::all()
|
||||
.add(auth.filter_objects())
|
||||
.add(model::object::Column::InReplyTo.eq(oid));
|
||||
|
||||
let (limit, offset) = page.pagination();
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
// TODO also limit to only local activities
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.filter(auth.filter_objects())
|
||||
.filter(model::object::Column::InReplyTo.eq(oid))
|
||||
.order_by_desc(model::object::Column::Published)
|
||||
.into_model::<RichObject>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| ctx.ap(x))
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(
|
||||
&page_id,
|
||||
offset,
|
||||
limit,
|
||||
apb::Node::array(res)
|
||||
)
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/objects/{id}/replies/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
||||
use sea_orm::{ColumnTrait, Condition};
|
||||
use upub::Context;
|
||||
use sea_orm::{ColumnTrait, Condition, QueryFilter, QuerySelect};
|
||||
use upub::{selector::{RichActivity, RichFillable}, Context};
|
||||
|
||||
use crate::{activitypub::{CreationResult, Pagination}, AuthIdentity, builders::JsonLD};
|
||||
|
||||
|
@ -13,17 +13,25 @@ pub async fn page(
|
|||
Query(page): Query<Pagination>,
|
||||
AuthIdentity(auth): AuthIdentity,
|
||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
crate::builders::paginate_feed(
|
||||
upub::url!(ctx, "/outbox/page"),
|
||||
Condition::all()
|
||||
let filter = Condition::all()
|
||||
.add(upub::model::addressing::Column::Actor.is_null())
|
||||
.add(upub::model::actor::Column::Domain.eq(ctx.domain().to_string())),
|
||||
&ctx,
|
||||
page,
|
||||
auth.my_id(),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.add(upub::model::actor::Column::Domain.eq(ctx.domain().to_string()));
|
||||
|
||||
let (limit, offset) = page.pagination();
|
||||
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||
.filter(filter)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichActivity>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
crate::builders::collection_page(&upub::url!(ctx, "/outbox/page"), page, apb::Node::array(items))
|
||||
}
|
||||
|
||||
pub async fn post(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{QueryFilter, QuerySelect, ColumnTrait};
|
||||
|
||||
use upub::{selector::{BatchFillable, RichActivity}, Context};
|
||||
use upub::{selector::{RichFillable, RichActivity}, Context};
|
||||
|
||||
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity};
|
||||
|
||||
|
@ -31,11 +31,7 @@ pub async fn page(
|
|||
.into_model::<RichActivity>()
|
||||
.all(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::attachment::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::mention::Entity>(ctx.db())
|
||||
.await?
|
||||
.with_batched::<upub::model::hashtag::Entity>(ctx.db())
|
||||
.load_batched_models(ctx.db())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|x| ctx.ap(x))
|
||||
|
@ -43,8 +39,7 @@ pub async fn page(
|
|||
|
||||
crate::builders::collection_page(
|
||||
&upub::url!(ctx, "/tags/{id}/page"),
|
||||
offset,
|
||||
limit,
|
||||
page,
|
||||
apb::Node::array(objects),
|
||||
)
|
||||
|
||||
|
|
|
@ -1,61 +1,10 @@
|
|||
use apb::{BaseMut, CollectionMut, CollectionPageMut, LD};
|
||||
use sea_orm::{Condition, QueryFilter, QuerySelect, RelationTrait, ColumnTrait};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use upub::selector::{BatchFillable, RichActivity};
|
||||
|
||||
use crate::activitypub::Pagination;
|
||||
|
||||
#[deprecated = "use upub::Query directly"]
|
||||
pub async fn paginate_feed(
|
||||
id: String,
|
||||
filter: Condition,
|
||||
ctx: &upub::Context,
|
||||
page: Pagination,
|
||||
my_id: Option<i64>,
|
||||
with_users: bool, // TODO ewww too many arguments for this weird function...
|
||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
pub fn collection_page(id: &str, page: Pagination, items: apb::Node<serde_json::Value>) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
let (limit, offset) = page.pagination();
|
||||
|
||||
let mut conditions = Condition::all()
|
||||
.add(filter);
|
||||
|
||||
// by default we want replies because servers don't know about our api and want everything
|
||||
if !page.replies.unwrap_or(true) {
|
||||
conditions = conditions.add(upub::model::object::Column::InReplyTo.is_null());
|
||||
}
|
||||
|
||||
let mut select = upub::Query::feed(my_id);
|
||||
|
||||
if with_users {
|
||||
select = select
|
||||
.join(sea_orm::JoinType::InnerJoin, upub::model::activity::Relation::Actors.def());
|
||||
}
|
||||
|
||||
let db = ctx.db();
|
||||
let items = select
|
||||
.filter(conditions)
|
||||
// TODO also limit to only local activities
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.into_model::<RichActivity>()
|
||||
.all(db)
|
||||
.await?
|
||||
.with_batched::<upub::model::attachment::Entity>(db)
|
||||
.await?
|
||||
.with_batched::<upub::model::mention::Entity>(db)
|
||||
.await?
|
||||
.with_batched::<upub::model::hashtag::Entity>(db)
|
||||
.await?;
|
||||
|
||||
let items : Vec<serde_json::Value> = items
|
||||
.into_iter()
|
||||
.map(|item| ctx.ap(item))
|
||||
.collect();
|
||||
|
||||
collection_page(&id, offset, limit, apb::Node::array(items))
|
||||
}
|
||||
|
||||
pub fn collection_page(id: &str, offset: u64, limit: u64, items: apb::Node<serde_json::Value>) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||
let next = if items.len() < limit as usize {
|
||||
apb::Node::Empty
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue