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 sea_orm::{ConnectionTrait, DbErr, EntityTrait, FromQueryResult, ModelTrait, QueryFilter};
|
||||||
use super::{RichActivity, RichObject};
|
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)]
|
#[allow(async_fn_in_trait)]
|
||||||
pub trait BatchFillable: Sized {
|
pub trait BatchFillable: Sized {
|
||||||
async fn with_batched<E>(self, tx: &impl ConnectionTrait) -> Result<Self, DbErr>
|
async fn with_batched<E>(self, tx: &impl ConnectionTrait) -> Result<Self, DbErr>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod batch;
|
mod batch;
|
||||||
pub use batch::BatchFillable;
|
pub use batch::{BatchFillable, RichFillable};
|
||||||
|
|
||||||
mod query;
|
mod query;
|
||||||
pub use query::Query;
|
pub use query::Query;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::model;
|
||||||
pub struct Query;
|
pub struct Query;
|
||||||
|
|
||||||
impl 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()
|
let mut select = model::addressing::Entity::find()
|
||||||
.distinct_on([
|
.distinct_on([
|
||||||
(model::addressing::Entity, model::addressing::Column::Published).into_column_ref(),
|
(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()));
|
.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
|
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()
|
let mut select = model::addressing::Entity::find()
|
||||||
.distinct()
|
.distinct()
|
||||||
.join(sea_orm::JoinType::InnerJoin, model::addressing::Relation::Objects.def())
|
.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()));
|
.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
|
select
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use sea_orm::{ColumnTrait, QueryFilter, TransactionTrait};
|
use sea_orm::{ColumnTrait, Condition, QueryFilter, TransactionTrait};
|
||||||
use upub::{model, selector::{BatchFillable, RichActivity}, traits::Fetcher, Context};
|
use upub::{model, selector::{RichActivity, RichFillable}, traits::Fetcher, Context};
|
||||||
use apb::LD;
|
use apb::LD;
|
||||||
|
|
||||||
use crate::{builders::JsonLD, AuthIdentity};
|
use crate::{builders::JsonLD, AuthIdentity};
|
||||||
|
@ -23,20 +23,19 @@ pub async fn view(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = upub::Query::feed(auth.my_id())
|
let filter = Condition::all()
|
||||||
.filter(auth.filter_activities())
|
.add(auth.filter_activities())
|
||||||
.filter(model::activity::Column::Id.eq(&aid))
|
.add(model::activity::Column::Id.eq(&aid));
|
||||||
|
|
||||||
|
let activity = upub::Query::feed(auth.my_id(), true)
|
||||||
|
.filter(filter)
|
||||||
.into_model::<RichActivity>()
|
.into_model::<RichActivity>()
|
||||||
.one(ctx.db())
|
.one(ctx.db())
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(crate::ApiError::not_found)?
|
.ok_or_else(crate::ApiError::not_found)?
|
||||||
.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?;
|
.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};
|
use upub::model::relation::Column::{Follower, Following, FollowerInstance, FollowingInstance};
|
||||||
let follow___ = if OUTGOING { "following" } else { "followers" };
|
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))
|
let (user, config) = model::actor::Entity::find_by_ap_id(&ctx.uid(&id))
|
||||||
.find_also_related(model::config::Entity)
|
.find_also_related(model::config::Entity)
|
||||||
|
@ -117,7 +117,7 @@ pub async fn page<const OUTGOING: bool>(
|
||||||
|
|
||||||
crate::builders::collection_page(
|
crate::builders::collection_page(
|
||||||
&upub::url!(ctx, "/actors/{id}/{follow___}/page"),
|
&upub::url!(ctx, "/actors/{id}/{follow___}/page"),
|
||||||
offset, limit,
|
page,
|
||||||
apb::Node::links(following),
|
apb::Node::links(following),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::{http::StatusCode, extract::{Path, Query, State}, Json};
|
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};
|
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity, Identity};
|
||||||
|
|
||||||
|
@ -35,18 +35,26 @@ pub async fn page(
|
||||||
return Err(crate::ApiError::forbidden());
|
return Err(crate::ApiError::forbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::builders::paginate_feed(
|
let filter = Condition::any()
|
||||||
upub::url!(ctx, "/actors/{id}/inbox/page"),
|
|
||||||
Condition::any()
|
|
||||||
.add(upub::model::addressing::Column::Actor.eq(*internal))
|
.add(upub::model::addressing::Column::Actor.eq(*internal))
|
||||||
.add(upub::model::activity::Column::Actor.eq(uid))
|
.add(upub::model::activity::Column::Actor.eq(uid))
|
||||||
.add(upub::model::object::Column::AttributedTo.eq(uid)),
|
.add(upub::model::object::Column::AttributedTo.eq(uid));
|
||||||
&ctx,
|
|
||||||
page,
|
let (limit, offset) = page.pagination();
|
||||||
auth.my_id(),
|
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||||
false,
|
.filter(filter)
|
||||||
)
|
.limit(limit)
|
||||||
.await
|
.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(
|
pub async fn post(
|
||||||
|
|
|
@ -31,15 +31,13 @@ pub async fn page(
|
||||||
|
|
||||||
let (limit, offset) = page.pagination();
|
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())
|
.join(sea_orm::JoinType::InnerJoin, upub::model::object::Relation::Likes.def())
|
||||||
.filter(auth.filter_objects())
|
.filter(auth.filter_objects())
|
||||||
.filter(upub::model::like::Column::Actor.eq(user.internal))
|
.filter(upub::model::like::Column::Actor.eq(user.internal))
|
||||||
.order_by_desc(upub::model::like::Column::Published)
|
.order_by_desc(upub::model::like::Column::Published)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.offset(offset);
|
.offset(offset)
|
||||||
|
|
||||||
let items : Vec<serde_json::Value> = select
|
|
||||||
.into_model::<RichObject>()
|
.into_model::<RichObject>()
|
||||||
.all(ctx.db())
|
.all(ctx.db())
|
||||||
.await?
|
.await?
|
||||||
|
@ -53,13 +51,5 @@ pub async fn page(
|
||||||
.map(|x| ctx.ap(x))
|
.map(|x| ctx.ap(x))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
crate::builders::paginate_feed(
|
crate::builders::collection_page(&upub::url!(ctx, "/actors/{id}/outbox/page"), page, apb::Node::array(items))
|
||||||
upub::url!(ctx, "/actors/{id}/outbox/page"),
|
|
||||||
auth.filter_objects(),
|
|
||||||
&ctx,
|
|
||||||
page,
|
|
||||||
auth.my_id(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,6 @@ pub async fn page(
|
||||||
.map(|x| ctx.ap(x))
|
.map(|x| ctx.ap(x))
|
||||||
.collect();
|
.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 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};
|
use crate::{activitypub::{CreationResult, Pagination}, builders::JsonLD, AuthIdentity, Identity};
|
||||||
|
|
||||||
|
@ -28,15 +28,23 @@ pub async fn page(
|
||||||
.add(model::object::Column::Audience.eq(&uid))
|
.add(model::object::Column::Audience.eq(&uid))
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::builders::paginate_feed(
|
let (limit, offset) = page.pagination();
|
||||||
upub::url!(ctx, "/actors/{id}/outbox/page"),
|
// by default we want replies because servers don't know about our api and need to see everything
|
||||||
filter,
|
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||||
&ctx,
|
.filter(filter)
|
||||||
page,
|
// TODO also limit to only local activities
|
||||||
auth.my_id(),
|
.limit(limit)
|
||||||
false,
|
.offset(offset)
|
||||||
)
|
.into_model::<RichActivity>()
|
||||||
.await
|
.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(
|
pub async fn post(
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use apb::{LD, ActorMut, BaseMut, ObjectMut, PublicKeyMut};
|
use apb::{LD, ActorMut, BaseMut, ObjectMut, PublicKeyMut};
|
||||||
use axum::{extract::{Path, Query, State}, http::HeaderMap, response::{IntoResponse, Redirect, Response}};
|
use axum::{extract::{Path, Query, State}, http::HeaderMap, response::{IntoResponse, Redirect, Response}};
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use sea_orm::{Condition, ColumnTrait};
|
use sea_orm::{ColumnTrait, Condition, QueryFilter, QuerySelect};
|
||||||
use upub::{traits::{Cloaker, Fetcher}, Context};
|
use upub::{selector::{RichFillable, RichObject}, traits::{Cloaker, Fetcher}, Context};
|
||||||
|
|
||||||
use crate::{builders::JsonLD, ApiError, AuthIdentity};
|
use crate::{builders::JsonLD, ApiError, AuthIdentity};
|
||||||
|
|
||||||
|
@ -57,21 +57,28 @@ pub async fn search(
|
||||||
|
|
||||||
// TODO lmao rethink this all
|
// TODO lmao rethink this all
|
||||||
// still haven't redone this gg me
|
// 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 {
|
let page = Pagination {
|
||||||
offset: page.offset,
|
offset: page.offset,
|
||||||
batch: page.batch,
|
batch: page.batch,
|
||||||
replies: Some(true),
|
replies: Some(true),
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::builders::paginate_feed(
|
let (limit, offset) = page.pagination();
|
||||||
upub::url!(ctx, "/search"),
|
let items = upub::Query::feed(auth.my_id(), true)
|
||||||
filter,
|
.filter(filter)
|
||||||
&ctx,
|
.limit(limit)
|
||||||
page,
|
.offset(offset)
|
||||||
auth.my_id(),
|
.into_model::<RichObject>()
|
||||||
false,
|
.all(ctx.db())
|
||||||
)
|
.await?
|
||||||
.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)]
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use apb::{Activity, ActivityType, Base};
|
use apb::{Activity, ActivityType, Base};
|
||||||
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
||||||
use sea_orm::{sea_query::IntoCondition, ActiveValue::{NotSet, Set}, ColumnTrait, EntityTrait};
|
use sea_orm::{sea_query::IntoCondition, ActiveValue::{NotSet, Set}, ColumnTrait, EntityTrait, QueryFilter, QuerySelect};
|
||||||
use upub::{model::job::JobType, Context};
|
use upub::{model::job::JobType, selector::{RichActivity, RichFillable}, Context};
|
||||||
|
|
||||||
use crate::{AuthIdentity, Identity, builders::JsonLD};
|
use crate::{AuthIdentity, Identity, builders::JsonLD};
|
||||||
|
|
||||||
|
@ -19,24 +19,23 @@ pub async fn page(
|
||||||
AuthIdentity(auth): AuthIdentity,
|
AuthIdentity(auth): AuthIdentity,
|
||||||
Query(page): Query<Pagination>,
|
Query(page): Query<Pagination>,
|
||||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
crate::builders::paginate_feed(
|
let filter = upub::model::addressing::Column::Actor.is_null().into_condition();
|
||||||
upub::url!(ctx, "/inbox/page"),
|
let (limit, offset) = page.pagination();
|
||||||
upub::model::addressing::Column::Actor.is_null().into_condition(),
|
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||||
&ctx,
|
.filter(filter)
|
||||||
page,
|
.limit(limit)
|
||||||
auth.my_id(),
|
.offset(offset)
|
||||||
false,
|
.into_model::<RichActivity>()
|
||||||
)
|
.all(ctx.db())
|
||||||
.await
|
.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(
|
pub async fn post(
|
||||||
State(ctx): State<Context>,
|
State(ctx): State<Context>,
|
||||||
AuthIdentity(auth): AuthIdentity,
|
AuthIdentity(auth): AuthIdentity,
|
||||||
|
@ -52,7 +51,10 @@ pub async fn post(
|
||||||
// would be cool if mastodon played nicer with the network...
|
// would be cool if mastodon played nicer with the network...
|
||||||
return Ok(StatusCode::OK);
|
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) {
|
if matches!(auth, Identity::Anonymous) {
|
||||||
return Err(crate::ApiError::unauthorized());
|
return Err(crate::ApiError::unauthorized());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub struct TryFetch {
|
||||||
pub fetch: bool,
|
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?
|
// TODO i don't really like how pleroma/mastodon do it actually, maybe change this?
|
||||||
pub struct Pagination {
|
pub struct Pagination {
|
||||||
pub offset: Option<u64>,
|
pub offset: Option<u64>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use sea_orm::{ColumnTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect};
|
use sea_orm::{ColumnTrait, Condition, PaginatorTrait, QueryFilter, QuerySelect};
|
||||||
use upub::{model, selector::{BatchFillable, RichObject}, Context};
|
use upub::{model, selector::{RichFillable, RichObject}, Context};
|
||||||
|
|
||||||
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity};
|
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ pub async fn get(
|
||||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
let context = ctx.oid(&id);
|
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(auth.filter_objects())
|
||||||
.filter(model::object::Column::Context.eq(&context))
|
.filter(model::object::Column::Context.eq(&context))
|
||||||
.count(ctx.db())
|
.count(ctx.db())
|
||||||
|
@ -23,33 +23,30 @@ pub async fn get(
|
||||||
pub async fn page(
|
pub async fn page(
|
||||||
State(ctx): State<Context>,
|
State(ctx): State<Context>,
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
Query(page): Query<Pagination>,
|
Query(mut page): Query<Pagination>,
|
||||||
AuthIdentity(auth): AuthIdentity,
|
AuthIdentity(auth): AuthIdentity,
|
||||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
let context = ctx.oid(&id);
|
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 (limit, offset) = page.pagination();
|
||||||
|
|
||||||
let items = upub::Query::objects(auth.my_id())
|
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||||
.filter(auth.filter_objects())
|
.filter(filter)
|
||||||
.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)
|
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.into_model::<RichObject>()
|
.into_model::<RichObject>()
|
||||||
.all(ctx.db())
|
.all(ctx.db())
|
||||||
.await?
|
.await?
|
||||||
.with_batched::<upub::model::attachment::Entity>(ctx.db())
|
.load_batched_models(ctx.db())
|
||||||
.await?
|
.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()
|
.into_iter()
|
||||||
.map(|item| ctx.ap(item))
|
.map(|item| ctx.ap(item))
|
||||||
.collect();
|
.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 apb::LD;
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use sea_orm::{ColumnTrait, QueryFilter, TransactionTrait};
|
use sea_orm::{ColumnTrait, Condition, QueryFilter, TransactionTrait};
|
||||||
use upub::{model, selector::{BatchFillable, RichObject}, traits::Fetcher, Context};
|
use upub::{model, selector::{RichFillable, RichObject}, traits::Fetcher, Context};
|
||||||
|
|
||||||
use crate::{builders::JsonLD, AuthIdentity};
|
use crate::{builders::JsonLD, AuthIdentity};
|
||||||
|
|
||||||
|
@ -27,19 +27,18 @@ pub async fn view(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let item = upub::Query::objects(auth.my_id())
|
let filter = Condition::all()
|
||||||
.filter(auth.filter_objects())
|
.add(auth.filter_objects())
|
||||||
.filter(model::object::Column::Id.eq(&oid))
|
.add(model::object::Column::Id.eq(&oid));
|
||||||
|
|
||||||
|
let object = upub::Query::feed(auth.my_id(), true)
|
||||||
|
.filter(filter)
|
||||||
.into_model::<RichObject>()
|
.into_model::<RichObject>()
|
||||||
.one(ctx.db())
|
.one(ctx.db())
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(crate::ApiError::not_found)?
|
.ok_or_else(crate::ApiError::not_found)?
|
||||||
.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?;
|
.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 apb::{BaseMut, CollectionMut, LD};
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use sea_orm::{ColumnTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect};
|
use sea_orm::{ColumnTrait, Condition, PaginatorTrait, QueryFilter, QuerySelect};
|
||||||
use upub::{model, selector::RichObject, traits::Fetcher, Context};
|
use upub::{model, selector::{RichFillable, RichObject}, traits::Fetcher, Context};
|
||||||
|
|
||||||
use crate::{activitypub::{Pagination, TryFetch}, builders::JsonLD, AuthIdentity};
|
use crate::{activitypub::{Pagination, TryFetch}, builders::JsonLD, AuthIdentity};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ pub async fn get(
|
||||||
ctx.fetch_thread(&oid, ctx.db()).await?;
|
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(auth.filter_objects())
|
||||||
.filter(model::object::Column::InReplyTo.eq(&oid))
|
.filter(model::object::Column::InReplyTo.eq(&oid))
|
||||||
.count(ctx.db())
|
.count(ctx.db())
|
||||||
|
@ -43,30 +43,29 @@ pub async fn page(
|
||||||
Query(mut page): Query<Pagination>,
|
Query(mut page): Query<Pagination>,
|
||||||
AuthIdentity(auth): AuthIdentity,
|
AuthIdentity(auth): AuthIdentity,
|
||||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
let page_id = upub::url!(ctx, "/objects/{id}/replies/page");
|
|
||||||
let oid = ctx.oid(&id);
|
let oid = ctx.oid(&id);
|
||||||
let (limit, offset) = page.pagination();
|
|
||||||
|
|
||||||
// TODO kinda weird ignoring this but its weirder to exclude replies from replies view...
|
// TODO kinda weird ignoring this but its weirder to exclude replies from replies view...
|
||||||
page.replies = Some(true);
|
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)
|
.limit(limit)
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.filter(auth.filter_objects())
|
|
||||||
.filter(model::object::Column::InReplyTo.eq(oid))
|
|
||||||
.order_by_desc(model::object::Column::Published)
|
|
||||||
.into_model::<RichObject>()
|
.into_model::<RichObject>()
|
||||||
.all(ctx.db())
|
.all(ctx.db())
|
||||||
.await?
|
.await?
|
||||||
|
.load_batched_models(ctx.db())
|
||||||
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| ctx.ap(x))
|
.map(|item| ctx.ap(item))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
crate::builders::collection_page(
|
crate::builders::collection_page(&upub::url!(ctx, "/objects/{id}/replies/page"), page, apb::Node::array(items))
|
||||||
&page_id,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
apb::Node::array(res)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
use axum::{extract::{Query, State}, http::StatusCode, 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::{CreationResult, Pagination}, AuthIdentity, builders::JsonLD};
|
use crate::{activitypub::{CreationResult, Pagination}, AuthIdentity, builders::JsonLD};
|
||||||
|
|
||||||
|
@ -13,17 +13,25 @@ pub async fn page(
|
||||||
Query(page): Query<Pagination>,
|
Query(page): Query<Pagination>,
|
||||||
AuthIdentity(auth): AuthIdentity,
|
AuthIdentity(auth): AuthIdentity,
|
||||||
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
crate::builders::paginate_feed(
|
let filter = Condition::all()
|
||||||
upub::url!(ctx, "/outbox/page"),
|
|
||||||
Condition::all()
|
|
||||||
.add(upub::model::addressing::Column::Actor.is_null())
|
.add(upub::model::addressing::Column::Actor.is_null())
|
||||||
.add(upub::model::actor::Column::Domain.eq(ctx.domain().to_string())),
|
.add(upub::model::actor::Column::Domain.eq(ctx.domain().to_string()));
|
||||||
&ctx,
|
|
||||||
page,
|
let (limit, offset) = page.pagination();
|
||||||
auth.my_id(),
|
let items = upub::Query::feed(auth.my_id(), page.replies.unwrap_or(true))
|
||||||
true,
|
.filter(filter)
|
||||||
)
|
.limit(limit)
|
||||||
.await
|
.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(
|
pub async fn post(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use sea_orm::{QueryFilter, QuerySelect, ColumnTrait};
|
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};
|
use crate::{activitypub::Pagination, builders::JsonLD, AuthIdentity};
|
||||||
|
|
||||||
|
@ -31,11 +31,7 @@ pub async fn page(
|
||||||
.into_model::<RichActivity>()
|
.into_model::<RichActivity>()
|
||||||
.all(ctx.db())
|
.all(ctx.db())
|
||||||
.await?
|
.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?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| ctx.ap(x))
|
.map(|x| ctx.ap(x))
|
||||||
|
@ -43,8 +39,7 @@ pub async fn page(
|
||||||
|
|
||||||
crate::builders::collection_page(
|
crate::builders::collection_page(
|
||||||
&upub::url!(ctx, "/tags/{id}/page"),
|
&upub::url!(ctx, "/tags/{id}/page"),
|
||||||
offset,
|
page,
|
||||||
limit,
|
|
||||||
apb::Node::array(objects),
|
apb::Node::array(objects),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,61 +1,10 @@
|
||||||
use apb::{BaseMut, CollectionMut, CollectionPageMut, LD};
|
use apb::{BaseMut, CollectionMut, CollectionPageMut, LD};
|
||||||
use sea_orm::{Condition, QueryFilter, QuerySelect, RelationTrait, ColumnTrait};
|
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use upub::selector::{BatchFillable, RichActivity};
|
|
||||||
|
|
||||||
use crate::activitypub::Pagination;
|
use crate::activitypub::Pagination;
|
||||||
|
|
||||||
#[deprecated = "use upub::Query directly"]
|
pub fn collection_page(id: &str, page: Pagination, items: apb::Node<serde_json::Value>) -> crate::ApiResult<JsonLD<serde_json::Value>> {
|
||||||
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>> {
|
|
||||||
let (limit, offset) = page.pagination();
|
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 {
|
let next = if items.len() < limit as usize {
|
||||||
apb::Node::Empty
|
apb::Node::Empty
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue