forked from alemi/upub
feat: query and show objects liked by you
it shows it in quite a jank way: inside the "audience" collections you find your id as only item. it's weird af but technically valid ap i think? will probably be replaced with a local api extension as soon as i read about those
This commit is contained in:
parent
63ba54dad9
commit
45d16fa0a3
14 changed files with 78 additions and 26 deletions
|
@ -1,4 +1,4 @@
|
|||
use apb::{ActivityMut, ObjectMut};
|
||||
use apb::{ActivityMut, CollectionMut, ObjectMut};
|
||||
use sea_orm::{entity::prelude::*, Condition, FromQueryResult, Iterable, Order, QueryOrder, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::routes::activitypub::jsonld::LD;
|
||||
|
@ -65,11 +65,15 @@ impl ActiveModelBehavior for ActiveModel {}
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
Tombstone,
|
||||
StrayObject(crate::model::object::Model),
|
||||
Activity(crate::model::activity::Model),
|
||||
StrayObject {
|
||||
object: crate::model::object::Model,
|
||||
liked: Option<String>,
|
||||
},
|
||||
DeepActivity {
|
||||
activity: crate::model::activity::Model,
|
||||
object: crate::model::object::Model,
|
||||
liked: Option<String>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,9 +82,9 @@ impl Event {
|
|||
pub fn id(&self) -> &str {
|
||||
match self {
|
||||
Event::Tombstone => "",
|
||||
Event::StrayObject(x) => x.id.as_str(),
|
||||
Event::Activity(x) => x.id.as_str(),
|
||||
Event::DeepActivity { activity: _, object } => object.id.as_str(),
|
||||
Event::StrayObject { object, liked: _ } => object.id.as_str(),
|
||||
Event::DeepActivity { activity: _, liked: _, object } => object.id.as_str(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,11 +97,37 @@ impl Event {
|
|||
};
|
||||
match self {
|
||||
Event::Activity(x) => x.ap(),
|
||||
Event::DeepActivity { activity, object } =>
|
||||
activity.ap().set_object(apb::Node::object(object.ap().set_attachment(attachment))),
|
||||
Event::StrayObject(x) => serde_json::Value::new_object()
|
||||
Event::DeepActivity { activity, object, liked } =>
|
||||
activity.ap().set_object(apb::Node::object({
|
||||
let likes = object.likes;
|
||||
let mut obj = object.ap()
|
||||
.set_attachment(attachment);
|
||||
if let Some(liked) = liked {
|
||||
obj = obj.set_audience(apb::Node::object( // TODO setting this again ewww...
|
||||
serde_json::Value::new_object()
|
||||
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
|
||||
.set_total_items(Some(likes as u64))
|
||||
.set_ordered_items(apb::Node::links(vec![liked]))
|
||||
));
|
||||
}
|
||||
obj
|
||||
})),
|
||||
Event::StrayObject { object, liked } => serde_json::Value::new_object()
|
||||
.set_activity_type(Some(apb::ActivityType::Activity))
|
||||
.set_object(apb::Node::object(x.ap().set_attachment(attachment))),
|
||||
.set_object(apb::Node::object({
|
||||
let likes = object.likes;
|
||||
let mut obj = object.ap()
|
||||
.set_attachment(attachment);
|
||||
if let Some(liked) = liked {
|
||||
obj = obj.set_audience(apb::Node::object( // TODO setting this again ewww...
|
||||
serde_json::Value::new_object()
|
||||
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
|
||||
.set_total_items(Some(likes as u64))
|
||||
.set_ordered_items(apb::Node::links(vec![liked]))
|
||||
));
|
||||
}
|
||||
obj
|
||||
})),
|
||||
Event::Tombstone => serde_json::Value::new_object()
|
||||
.set_activity_type(Some(apb::ActivityType::Activity))
|
||||
.set_object(apb::Node::object(
|
||||
|
@ -112,10 +142,11 @@ impl FromQueryResult for Event {
|
|||
fn from_query_result(res: &sea_orm::QueryResult, _pre: &str) -> Result<Self, sea_orm::DbErr> {
|
||||
let activity = crate::model::activity::Model::from_query_result(res, crate::model::activity::Entity.table_name()).ok();
|
||||
let object = crate::model::object::Model::from_query_result(res, crate::model::object::Entity.table_name()).ok();
|
||||
let liked = res.try_get(crate::model::like::Entity.table_name(), &crate::model::like::Column::Actor.to_string()).ok();
|
||||
match (activity, object) {
|
||||
(Some(activity), Some(object)) => Ok(Self::DeepActivity { activity, object }),
|
||||
(Some(activity), Some(object)) => Ok(Self::DeepActivity { activity, object, liked }),
|
||||
(Some(activity), None) => Ok(Self::Activity(activity)),
|
||||
(None, Some(object)) => Ok(Self::StrayObject(object)),
|
||||
(None, Some(object)) => Ok(Self::StrayObject { object, liked }),
|
||||
(None, None) => Ok(Self::Tombstone),
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +154,7 @@ impl FromQueryResult for Event {
|
|||
|
||||
|
||||
impl Entity {
|
||||
pub fn find_addressed() -> Select<Entity> {
|
||||
pub fn find_addressed(uid: Option<&str>) -> Select<Entity> {
|
||||
let mut select = Entity::find()
|
||||
.distinct()
|
||||
.select_only()
|
||||
|
@ -137,6 +168,13 @@ impl Entity {
|
|||
)
|
||||
.order_by(Column::Published, Order::Desc);
|
||||
|
||||
if let Some(uid) = uid {
|
||||
select = select
|
||||
.filter(crate::model::like::Column::Actor.eq(uid))
|
||||
.join(sea_orm::JoinType::LeftJoin, crate::model::object::Relation::Like.def())
|
||||
.select_column_as(crate::model::like::Column::Actor, format!("{}{}", crate::model::like::Entity.table_name(), crate::model::like::Column::Actor.to_string()));
|
||||
}
|
||||
|
||||
for col in crate::model::object::Column::iter() {
|
||||
select = select.select_column_as(col, format!("{}{}", crate::model::object::Entity.table_name(), col.to_string()));
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@ impl BatchFillable for &[Event] {
|
|||
.filter_map(|x| match x {
|
||||
Event::Tombstone => None,
|
||||
Event::Activity(_) => None,
|
||||
Event::StrayObject(x) => Some(x.clone()),
|
||||
Event::DeepActivity { activity: _, object } => Some(object.clone()),
|
||||
Event::StrayObject { object, liked: _ } => Some(object.clone()),
|
||||
Event::DeepActivity { activity: _, liked: _, object } => Some(object.clone()),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ pub async fn view(
|
|||
}
|
||||
}
|
||||
|
||||
let row = model::addressing::Entity::find_addressed()
|
||||
let row = model::addressing::Entity::find_addressed(auth.my_id())
|
||||
.filter(model::activity::Column::Id.eq(&aid))
|
||||
.filter(auth.filter_condition())
|
||||
.into_model::<Event>()
|
||||
|
|
|
@ -11,7 +11,7 @@ pub async fn get(
|
|||
let local_context_id = url!(ctx, "/context/{id}");
|
||||
let context = ctx.uri("context", id);
|
||||
|
||||
let count = model::addressing::Entity::find_addressed()
|
||||
let count = model::addressing::Entity::find_addressed(auth.my_id())
|
||||
.filter(auth.filter_condition())
|
||||
.filter(model::object::Column::Context.eq(context))
|
||||
.count(ctx.db())
|
||||
|
@ -40,7 +40,8 @@ pub async fn page(
|
|||
.add(auth.filter_condition())
|
||||
.add(model::object::Column::Context.eq(context)),
|
||||
ctx.db(),
|
||||
page
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ pub async fn page(
|
|||
url!(ctx, "/inbox/page"),
|
||||
auth.filter_condition(),
|
||||
ctx.db(),
|
||||
page
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use apb::ObjectMut;
|
|||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, ModelTrait, QueryFilter};
|
||||
|
||||
use crate::{errors::UpubError, model::{self, addressing::Event}, server::{auth::AuthIdentity, fetcher::Fetcher, Context}};
|
||||
use crate::{errors::UpubError, model::{self, addressing::Event}, server::{auth::{AuthIdentity, Identity}, fetcher::Fetcher, Context}};
|
||||
|
||||
use super::{jsonld::LD, JsonLD, TryFetch};
|
||||
|
||||
|
@ -27,7 +27,7 @@ pub async fn view(
|
|||
}
|
||||
}
|
||||
|
||||
let item = model::addressing::Entity::find_addressed()
|
||||
let item = model::addressing::Entity::find_addressed(auth.my_id())
|
||||
.filter(model::object::Column::Id.eq(&oid))
|
||||
.filter(auth.filter_condition())
|
||||
.into_model::<Event>()
|
||||
|
@ -38,8 +38,8 @@ pub async fn view(
|
|||
let object = match item {
|
||||
Event::Tombstone => return Err(UpubError::not_found()),
|
||||
Event::Activity(_) => return Err(UpubError::not_found()),
|
||||
Event::StrayObject(x) => x,
|
||||
Event::DeepActivity { activity: _, object } => object,
|
||||
Event::StrayObject { object, liked: _ } => object,
|
||||
Event::DeepActivity { activity: _, liked: _, object } => object,
|
||||
};
|
||||
|
||||
let attachments = object.find_related(model::attachment::Entity)
|
||||
|
|
|
@ -11,7 +11,7 @@ pub async fn get(
|
|||
let replies_id = url!(ctx, "/objects/{id}/replies");
|
||||
let oid = ctx.uri("objects", id);
|
||||
|
||||
let count = model::addressing::Entity::find_addressed()
|
||||
let count = model::addressing::Entity::find_addressed(auth.my_id())
|
||||
.filter(auth.filter_condition())
|
||||
.filter(model::object::Column::InReplyTo.eq(oid))
|
||||
.count(ctx.db())
|
||||
|
@ -35,7 +35,8 @@ pub async fn page(
|
|||
.add(auth.filter_condition())
|
||||
.add(model::object::Column::InReplyTo.eq(oid)),
|
||||
ctx.db(),
|
||||
page
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ pub async fn page(
|
|||
auth.filter_condition(), // TODO filter local only stuff
|
||||
ctx.db(),
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ pub async fn page(
|
|||
.add(model::activity::Column::Actor.eq(uid)),
|
||||
ctx.db(),
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ pub mod following;
|
|||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::EntityTrait;
|
||||
|
||||
use apb::{ActorMut, BaseMut, CollectionMut, Node, ObjectMut};
|
||||
use apb::{ActorMut, Node, ObjectMut};
|
||||
use crate::{errors::UpubError, model::{self, user}, server::{auth::AuthIdentity, fetcher::Fetcher, Context}, url};
|
||||
|
||||
use super::{jsonld::LD, JsonLD, TryFetch};
|
||||
|
|
|
@ -33,6 +33,7 @@ pub async fn page(
|
|||
),
|
||||
ctx.db(),
|
||||
page,
|
||||
auth.my_id(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ pub async fn statuses(
|
|||
Query(_query): Query<StatusesQuery>,
|
||||
) -> Result<Json<Vec<Status>>, StatusCode> {
|
||||
let uid = ctx.uid(id);
|
||||
model::addressing::Entity::find_addressed()
|
||||
model::addressing::Entity::find_addressed(auth.my_id())
|
||||
.filter(model::activity::Column::Actor.eq(uid))
|
||||
.filter(auth.filter_condition());
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn my_id(&self) -> Option<&str> {
|
||||
match self {
|
||||
Identity::Local(x) => Some(x.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_anon(&self) -> bool {
|
||||
matches!(self, Self::Anonymous)
|
||||
}
|
||||
|
|
|
@ -8,11 +8,12 @@ pub async fn paginate(
|
|||
filter: Condition,
|
||||
db: &DatabaseConnection,
|
||||
page: Pagination,
|
||||
my_id: Option<&str>,
|
||||
) -> crate::Result<JsonLD<serde_json::Value>> {
|
||||
let limit = page.batch.unwrap_or(20).min(50);
|
||||
let offset = page.offset.unwrap_or(0);
|
||||
|
||||
let items = crate::model::addressing::Entity::find_addressed()
|
||||
let items = crate::model::addressing::Entity::find_addressed(my_id)
|
||||
.filter(filter)
|
||||
// TODO also limit to only local activities
|
||||
.limit(limit)
|
||||
|
|
Loading…
Reference in a new issue