From c361528b2f0c6e9f2bb8c069832ac156128ff715 Mon Sep 17 00:00:00 2001 From: alemi Date: Sat, 23 Mar 2024 06:10:53 +0100 Subject: [PATCH] feat: moved object creation out of entity --- src/activitypub/user/mod.rs | 52 ++++++++- src/model/user.rs | 210 +++++++++++++++++++----------------- 2 files changed, 160 insertions(+), 102 deletions(-) diff --git a/src/activitypub/user/mod.rs b/src/activitypub/user/mod.rs index 318d9e69..4df330a2 100644 --- a/src/activitypub/user/mod.rs +++ b/src/activitypub/user/mod.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::{DatabaseConnection, EntityTrait}; -use crate::{activitystream::Base, model::user, server::Context}; +use crate::{activitystream::{object::{actor::ActorMut, collection::{CollectionMut, CollectionType}, document::{DocumentMut, DocumentType}, ObjectMut}, BaseMut, Node}, model::{self, user}, server::Context, url}; use super::{jsonld::LD, JsonLD}; @@ -21,8 +21,54 @@ pub async fn list(State(_db) : State>) -> Result, Path(id): Path) -> Result, StatusCode> { - match user::Entity::find_by_id(ctx.uid(id)).one(ctx.db()).await { - Ok(Some(user)) => Ok(JsonLD(user.underlying_json_object().ld_context())), + match user::Entity::find_by_id(ctx.uid(id.clone())) + .find_also_related(model::config::Entity) + .one(ctx.db()).await + { + // local user + Ok(Some((user, Some(cfg)))) => { + Ok(JsonLD(serde_json::Value::new_object() + .set_id(Some(&user.id)) + .set_actor_type(Some(user.actor_type)) + .set_name(user.name.as_deref()) + .set_summary(user.summary.as_deref()) + .set_icon(Node::maybe_object(user.icon.map(|i| + serde_json::Value::new_object() + .set_document_type(Some(DocumentType::Image)) + .set_url(Node::link(i.clone())) + ))) + .set_image(Node::maybe_object(user.image.map(|i| + serde_json::Value::new_object() + .set_document_type(Some(DocumentType::Image)) + .set_url(Node::link(i.clone())) + ))) + .set_published(Some(user.created)) + .set_preferred_username(Some(&user.preferred_username)) + .set_inbox(Node::link(url!(ctx, "/users/{id}/inbox"))) + .set_outbox(Node::link(url!(ctx, "/users/{id}/outbox"))) + .set_following(Node::object( + serde_json::Value::new_object() + .set_id(Some(&url!(ctx, "/users/{id}/following"))) + .set_collection_type(Some(CollectionType::OrderedCollection)) + .set_total_items(if cfg.show_following_count { Some(0 /* user.following_count TODO */) } else { None }) + .set_first(Node::link(url!(ctx, "/users/{id}/following?page=true"))) + )) + .set_followers(Node::object( + serde_json::Value::new_object() + .set_id(Some(&url!(ctx, "/users/{id}/followers"))) + .set_collection_type(Some(CollectionType::OrderedCollection)) + .set_total_items(if cfg.show_followers_count { Some(0 /* user.followers_count TODO */) } else { None }) + .set_first(Node::link(url!(ctx, "/users/{id}/followers?page=true"))) + )) + // .set_public_key(user.public_key) // TODO + .set_discoverable(Some(true)) + .set_endpoints(None) + )) + }, + // remote user + Ok(Some((_user, None))) => { + Err(StatusCode::NOT_IMPLEMENTED) + }, Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for user: {e}"); diff --git a/src/model/user.rs b/src/model/user.rs index facf70f4..47b2787d 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -69,107 +69,119 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::Config.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Credential.def() + } +} + impl ActiveModelBehavior for ActiveModel {} -impl crate::activitystream::Base for Model { - fn id(&self) -> Option<&str> { - Some(&self.id) - } - - fn base_type(&self) -> Option { - Some(BaseType::Object(ObjectType::Actor(self.actor_type))) - } - - fn underlying_json_object(self) -> serde_json::Value { - serde_json::Value::new_object() - .set_id(Some(&self.id)) - .set_actor_type(Some(self.actor_type)) - .set_name(self.name.as_deref()) - .set_summary(self.summary.as_deref()) - .set_icon(self.icon()) - .set_image(self.image()) - .set_published(Some(self.created)) - .set_preferred_username(Some(&self.preferred_username)) - .set_inbox(self.inbox()) - .set_outbox(self.outbox()) - .set_following(self.following()) - .set_followers(self.followers()) - .set_public_key(self.public_key()) - .set_discoverable(Some(true)) - .set_endpoints(None) // TODO dirty fix to put an empty object - } -} - -impl crate::activitystream::object::Object for Model { - fn name(&self) -> Option<&str> { - self.name.as_deref() - } - - fn summary(&self) -> Option<&str> { - self.summary.as_deref() - } - - fn icon(&self) -> Node { - match &self.icon { - Some(x) => Node::object( - serde_json::Value::new_object() - .set_document_type(Some(DocumentType::Image)) - .set_url(Node::link(x.clone())) - ), - None => Node::Empty, - } - } - - fn image(&self) -> Node { - match &self.image { - Some(x) => Node::object( - serde_json::Value::new_object() - .set_document_type(Some(DocumentType::Image)) - .set_url(Node::link(x.clone())) - ), - None => Node::Empty, - } - } - - fn published(&self) -> Option> { - Some(self.created) - } -} - -impl crate::activitystream::object::actor::Actor for Model { - fn actor_type(&self) -> Option { - Some(self.actor_type) - } - - fn preferred_username(&self) -> Option<&str> { - Some(&self.preferred_username) - } - - fn inbox(&self) -> Node { - Node::link(self.inbox.clone().unwrap_or(format!("https://{}/users/{}/inbox", self.domain, self.preferred_username))) - } - - fn outbox(&self) -> Node { - Node::link(self.outbox.clone().unwrap_or(format!("https://{}/users/{}/outbox", self.domain, self.preferred_username))) - } - - fn following(&self) -> Node { - Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/following", self.domain, self.preferred_username))) - } - - fn followers(&self) -> Node { - Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/followers", self.domain, self.preferred_username))) - } - - fn public_key(&self) -> Node { - Node::object( - serde_json::Value::new_object() - .set_id(Some(&format!("{}#main-key", self.id))) // TODO is this some standard?? - .set_public_key_pem(&self.public_key) - .set_owner(Some(&self.id)) - ) - } -} +// impl crate::activitystream::Base for Model { +// fn id(&self) -> Option<&str> { +// Some(&self.id) +// } +// +// fn base_type(&self) -> Option { +// Some(BaseType::Object(ObjectType::Actor(self.actor_type))) +// } +// +// fn underlying_json_object(self) -> serde_json::Value { +// serde_json::Value::new_object() +// .set_id(Some(&self.id)) +// .set_actor_type(Some(self.actor_type)) +// .set_name(self.name.as_deref()) +// .set_summary(self.summary.as_deref()) +// .set_icon(self.icon()) +// .set_image(self.image()) +// .set_published(Some(self.created)) +// .set_preferred_username(Some(&self.preferred_username)) +// .set_inbox(self.inbox()) +// .set_outbox(self.outbox()) +// .set_following(self.following()) +// .set_followers(self.followers()) +// .set_public_key(self.public_key()) +// .set_discoverable(Some(true)) +// .set_endpoints(None) // TODO dirty fix to put an empty object +// } +// } +// +// impl crate::activitystream::object::Object for Model { +// fn name(&self) -> Option<&str> { +// self.name.as_deref() +// } +// +// fn summary(&self) -> Option<&str> { +// self.summary.as_deref() +// } +// +// fn icon(&self) -> Node { +// match &self.icon { +// Some(x) => Node::object( +// serde_json::Value::new_object() +// .set_document_type(Some(DocumentType::Image)) +// .set_url(Node::link(x.clone())) +// ), +// None => Node::Empty, +// } +// } +// +// fn image(&self) -> Node { +// match &self.image { +// Some(x) => Node::object( +// serde_json::Value::new_object() +// .set_document_type(Some(DocumentType::Image)) +// .set_url(Node::link(x.clone())) +// ), +// None => Node::Empty, +// } +// } +// +// fn published(&self) -> Option> { +// Some(self.created) +// } +// } +// +// impl crate::activitystream::object::actor::Actor for Model { +// fn actor_type(&self) -> Option { +// Some(self.actor_type) +// } +// +// fn preferred_username(&self) -> Option<&str> { +// Some(&self.preferred_username) +// } +// +// fn inbox(&self) -> Node { +// Node::link(self.inbox.clone().unwrap_or(format!("https://{}/users/{}/inbox", self.domain, self.preferred_username))) +// } +// +// fn outbox(&self) -> Node { +// Node::link(self.outbox.clone().unwrap_or(format!("https://{}/users/{}/outbox", self.domain, self.preferred_username))) +// } +// +// fn following(&self) -> Node { +// Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/following", self.domain, self.preferred_username))) +// } +// +// fn followers(&self) -> Node { +// Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/followers", self.domain, self.preferred_username))) +// } +// +// fn public_key(&self) -> Node { +// Node::object( +// serde_json::Value::new_object() +// .set_id(Some(&format!("{}#main-key", self.id))) // TODO is this some standard?? +// .set_public_key_pem(&self.public_key) +// .set_owner(Some(&self.id)) +// ) +// } +// } impl Model { pub fn new(object: &impl Actor) -> Result {