fix: use new apb fields

This commit is contained in:
əlemi 2024-05-02 00:47:11 +02:00
parent a499c93e99
commit bcd8f27933
Signed by: alemi
GPG key ID: A4895B84D311642C
5 changed files with 69 additions and 141 deletions

View file

@ -34,7 +34,7 @@ sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "runtime-toki
reqwest = { version = "0.12", features = ["json"] }
axum = "0.7"
tower-http = { version = "0.5", features = ["cors", "trace"] }
apb = { path = "apb", features = ["unstructured", "orm"] }
apb = { path = "apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters"] }
# nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!!
nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" }
# migrations

View file

@ -1,4 +1,4 @@
use apb::{ActivityMut, CollectionMut, ObjectMut};
use apb::{ActivityMut, ObjectMut};
use sea_orm::{entity::prelude::*, sea_query::IntoCondition, Condition, FromQueryResult, Iterable, Order, QueryOrder, QuerySelect, SelectColumns};
use crate::routes::activitypub::jsonld::LD;
@ -98,36 +98,18 @@ impl Event {
match self {
Event::Activity(x) => x.ap(),
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
})),
activity.ap().set_object(apb::Node::object(
object.ap()
.set_attachment(attachment)
.set_liked_by_me(if liked.is_some() { Some(true) } else { None })
)),
Event::StrayObject { object, liked } => serde_json::Value::new_object()
.set_activity_type(Some(apb::ActivityType::Activity))
.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
})),
.set_object(apb::Node::object(
object.ap()
.set_attachment(attachment)
.set_liked_by_me(if liked.is_some() { Some(true) } else { None })
)),
Event::Tombstone => serde_json::Value::new_object()
.set_activity_type(Some(apb::ActivityType::Activity))
.set_object(apb::Node::object(

View file

@ -1,4 +1,4 @@
use apb::{BaseMut, Object, Collection, CollectionMut, ObjectMut};
use apb::{BaseMut, Collection, CollectionMut, ObjectMut};
use sea_orm::entity::prelude::*;
use crate::routes::activitypub::jsonld::LD;
@ -41,21 +41,12 @@ impl Model {
context: object.context().id(),
in_reply_to: object.in_reply_to().id(),
published: object.published().ok_or(super::FieldError("published"))?,
comments: object.replies()
.get()
comments: object.replies().get()
.map_or(0, |x| x.total_items().unwrap_or(0)) as i64,
likes: object.likes().get()
.map_or(0, |x| x.total_items().unwrap_or(0)) as i64,
shares: object.shares().get()
.map_or(0, |x| x.total_items().unwrap_or(0)) as i64,
likes: object.audience()
.get()
.map_or(0, |x|
x.as_collection()
.map_or(0, |x| x.total_items().unwrap_or(0))
) as i64,
shares: object.generator()
.get()
.map_or(0, |x|
x.as_collection()
.map_or(0, |x| x.total_items().unwrap_or(0))
) as i64,
to: object.to().into(),
bto: object.bto().into(),
cc: object.cc().into(),
@ -81,12 +72,12 @@ impl Model {
.set_cc(apb::Node::links(self.cc.0.clone()))
.set_bcc(apb::Node::Empty)
.set_sensitive(Some(self.sensitive))
.set_generator(apb::Node::object(
.set_shares(apb::Node::object(
serde_json::Value::new_object()
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
.set_total_items(Some(self.shares as u64))
))
.set_audience(apb::Node::object(
.set_likes(apb::Node::object(
serde_json::Value::new_object()
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
.set_total_items(Some(self.likes as u64))

View file

@ -1,6 +1,6 @@
use sea_orm::entity::prelude::*;
use apb::{Actor, ActorMut, ActorType, BaseMut, Collection, CollectionMut, DocumentMut, Object, ObjectMut, PublicKey, PublicKeyMut};
use apb::{Actor, ActorMut, ActorType, BaseMut, DocumentMut, Object, ObjectMut, PublicKey, PublicKeyMut};
use crate::routes::activitypub::jsonld::LD;
@ -59,9 +59,9 @@ impl Model {
following: object.following().id(),
created: object.published().unwrap_or(chrono::Utc::now()),
updated: chrono::Utc::now(),
following_count: object.generator().get().map_or(0, |f| f.as_collection().map_or(0, |f| f.total_items().unwrap_or(0))) as i64,
followers_count: object.audience().get().map_or(0, |f| f.as_collection().map_or(0, |f| f.total_items().unwrap_or(0))) as i64,
statuses_count: object.replies().get().map_or(0, |o| o.total_items().unwrap_or(0)) as i64,
following_count: object.following_count().unwrap_or(0) as i64,
followers_count: object.followers_count().unwrap_or(0) as i64,
statuses_count: object.statuses_count().unwrap_or(0) as i64,
public_key: object.public_key().get().ok_or(super::FieldError("publicKey"))?.public_key_pem().to_string(),
private_key: None, // there's no way to transport privkey over AP json, must come from DB
})
@ -85,24 +85,9 @@ impl Model {
)))
.set_published(Some(self.created))
.set_preferred_username(Some(&self.preferred_username))
.set_replies(apb::Node::object(
serde_json::Value::new_object()
.set_id(self.outbox.as_deref())
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
.set_total_items(Some(self.statuses_count as u64))
))
.set_audience(apb::Node::object(
serde_json::Value::new_object()
.set_id(self.followers.as_deref())
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
.set_total_items(Some(self.followers_count as u64))
))
.set_generator(apb::Node::object(
serde_json::Value::new_object()
.set_id(self.following.as_deref())
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
.set_total_items(Some(self.following_count as u64))
))
.set_statuses_count(Some(self.statuses_count as u64))
.set_followers_count(Some(self.followers_count as u64))
.set_following_count(Some(self.following_count as u64))
.set_inbox(apb::Node::maybe_link(self.inbox))
.set_outbox(apb::Node::maybe_link(self.outbox))
.set_following(apb::Node::maybe_link(self.following))

View file

@ -7,7 +7,7 @@ pub mod following;
use axum::extract::{Path, Query, State};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QuerySelect, SelectColumns};
use apb::{ActorMut, CollectionMut, Node, Object, 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};
@ -27,6 +27,37 @@ pub async fn view(
if auth.is_local() && query.fetch && !ctx.is_local(&uid) {
ctx.fetch_user(&uid).await?;
}
let (followed_by_me, following_me) = match auth.my_id() {
None => (None, None),
Some(my_id) => {
// TODO these two queries are fast because of indexes but still are 2 subqueries for each
// user GET, not even parallelized... should really add these as joins on the main query, so
// that it's one roundtrip only
let followed_by_me = model::relation::Entity::find()
.filter(model::relation::Column::Follower.eq(my_id))
.filter(model::relation::Column::Following.eq(&uid))
.select_only()
.select_column(model::relation::Column::Follower)
.into_tuple::<String>()
.one(ctx.db())
.await?
.map(|_| true);
let following_me = model::relation::Entity::find()
.filter(model::relation::Column::Following.eq(my_id))
.filter(model::relation::Column::Follower.eq(&uid))
.select_only()
.select_column(model::relation::Column::Follower)
.into_tuple::<String>()
.one(ctx.db())
.await?
.map(|_| true);
(followed_by_me, following_me)
},
};
match user::Entity::find_by_id(&uid)
.find_also_related(model::config::Entity)
.one(ctx.db()).await?
@ -37,39 +68,9 @@ pub async fn view(
.set_inbox(Node::link(url!(ctx, "/users/{id}/inbox")))
.set_outbox(Node::link(url!(ctx, "/users/{id}/outbox")))
.set_following(Node::link(url!(ctx, "/users/{id}/following")))
.set_followers(Node::link(url!(ctx, "/users/{id}/followers")));
// TODO maybe this thing could be made as a single join, to avoid triple db roundtrip for
// each fetch made by local users? it's indexed and fast but still...
if let Some(my_id) = auth.my_id() {
if !auth.is(&uid) {
let followed_by_me = model::relation::Entity::find()
.filter(model::relation::Column::Follower.eq(my_id))
.filter(model::relation::Column::Following.eq(&uid))
.select_only()
.select_column(model::relation::Column::Follower)
.into_tuple::<String>()
.all(ctx.db())
.await?;
user
.audience()
.update(|x| x.set_ordered_items(apb::Node::links(followed_by_me)));
let following_me = model::relation::Entity::find()
.filter(model::relation::Column::Following.eq(my_id))
.filter(model::relation::Column::Follower.eq(&uid))
.select_only()
.select_column(model::relation::Column::Following)
.into_tuple::<String>()
.all(ctx.db())
.await?;
user
.generator()
.update(|x| x.set_ordered_items(apb::Node::links(following_me)));
}
}
.set_followers(Node::link(url!(ctx, "/users/{id}/followers")))
.set_following_me(following_me)
.set_followed_by_me(followed_by_me);
if !auth.is(&uid) && !cfg.show_followers_count {
user = user.set_audience(apb::Node::Empty);
@ -81,44 +82,13 @@ pub async fn view(
Ok(JsonLD(user.ld_context()))
},
// remote user TODDO doesn't work?
Some((user_model, None)) => {
let user = user_model.ap();
// TODO maybe this thing could be made as a single join, to avoid triple db roundtrip for
// each fetch made by local users? it's indexed and fast but still...
if let Some(my_id) = auth.my_id() {
if !auth.is(&uid) {
let followed_by_me = model::relation::Entity::find()
.filter(model::relation::Column::Follower.eq(my_id))
.filter(model::relation::Column::Following.eq(&uid))
.select_only()
.select_column(model::relation::Column::Follower)
.into_tuple::<String>()
.all(ctx.db())
.await?;
user
.audience()
.update(|x| x.set_ordered_items(apb::Node::links(followed_by_me)));
let following_me = model::relation::Entity::find()
.filter(model::relation::Column::Following.eq(my_id))
.filter(model::relation::Column::Follower.eq(&uid))
.select_only()
.select_column(model::relation::Column::Following)
.into_tuple::<String>()
.all(ctx.db())
.await?;
user
.generator()
.update(|x| x.set_ordered_items(apb::Node::links(following_me)));
}
}
Ok(JsonLD(user.ld_context()))
},
// remote user
Some((user_model, None)) => Ok(JsonLD(
user_model.ap()
.set_following_me(following_me)
.set_followed_by_me(followed_by_me)
.ld_context()
)),
None => Err(UpubError::not_found()),
}
}