From 72c2cd5f81f27ce3457989e076b5ba6ac90b4a5e Mon Sep 17 00:00:00 2001 From: alemi Date: Sat, 23 Mar 2024 06:32:15 +0100 Subject: [PATCH] chore: cleaned up all model modules --- src/activitypub/activity.rs | 20 ++++- src/activitypub/object.rs | 19 ++++- src/activitypub/user/mod.rs | 1 + src/activitypub/user/outbox.rs | 7 +- src/model/activity.rs | 110 ++++-------------------- src/model/object.rs | 118 ++++++-------------------- src/model/user.rs | 147 ++++++--------------------------- 7 files changed, 103 insertions(+), 319 deletions(-) diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index 256b5a9b..5d4d1349 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -1,9 +1,22 @@ use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; -use crate::{activitystream::{object::activity::ActivityMut, Base, Node}, model::{activity, object}, server::Context}; +use crate::{activitystream::{object::{activity::ActivityMut, ObjectMut}, BaseMut, Node}, model::{self, activity, object}, server::Context}; use super::{jsonld::LD, JsonLD}; +pub fn ap_activity(activity: model::activity::Model) -> serde_json::Value { + serde_json::Value::new_object() + .set_id(Some(&activity.id)) + .set_activity_type(Some(activity.activity_type)) + .set_actor(Node::link(activity.actor)) + .set_object(Node::maybe_link(activity.object)) + .set_target(Node::maybe_link(activity.target)) + .set_published(Some(activity.published)) + .set_to(Node::links(activity.to.0.clone())) + .set_bto(Node::empty()) + .set_cc(Node::links(activity.cc.0.clone())) + .set_bcc(Node::empty()) +} pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { match activity::Entity::find_by_id(ctx.aid(id)) @@ -12,9 +25,8 @@ pub async fn view(State(ctx) : State, Path(id): Path) -> Result .await { Ok(Some((activity, object))) => Ok(JsonLD( - activity - .underlying_json_object() - .set_object(Node::maybe_object(object)) + ap_activity(activity) + .set_object(Node::maybe_object(object.map(super::object::ap_object))) .ld_context() )), Ok(None) => Err(StatusCode::NOT_FOUND), diff --git a/src/activitypub/object.rs b/src/activitypub/object.rs index d0c86c8f..af771acd 100644 --- a/src/activitypub/object.rs +++ b/src/activitypub/object.rs @@ -1,14 +1,29 @@ use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; -use crate::{activitystream::Base, model::object, server::Context}; +use crate::{activitystream::{object::ObjectMut, BaseMut, Node}, model::{self, object}, server::Context}; use super::{jsonld::LD, JsonLD}; +pub fn ap_object(object: model::object::Model) -> serde_json::Value { + serde_json::Value::new_object() + .set_id(Some(&object.id)) + .set_object_type(Some(object.object_type)) + .set_attributed_to(Node::maybe_link(object.attributed_to)) + .set_name(object.name.as_deref()) + .set_summary(object.summary.as_deref()) + .set_content(object.content.as_deref()) + .set_context(Node::maybe_link(object.context.clone())) + .set_published(Some(object.published)) + .set_to(Node::links(object.to.0.clone())) + .set_bto(Node::empty()) + .set_cc(Node::links(object.cc.0.clone())) + .set_bcc(Node::empty()) +} pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { match object::Entity::find_by_id(ctx.oid(id)).one(ctx.db()).await { - Ok(Some(object)) => Ok(JsonLD(object.underlying_json_object().ld_context())), + Ok(Some(object)) => Ok(JsonLD(ap_object(object).ld_context())), Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for object: {e}"); diff --git a/src/activitypub/user/mod.rs b/src/activitypub/user/mod.rs index 4df330a2..e165285d 100644 --- a/src/activitypub/user/mod.rs +++ b/src/activitypub/user/mod.rs @@ -63,6 +63,7 @@ pub async fn view(State(ctx) : State, Path(id): Path) -> Result // .set_public_key(user.public_key) // TODO .set_discoverable(Some(true)) .set_endpoints(None) + .ld_context() )) }, // remote user diff --git a/src/activitypub/user/outbox.rs b/src/activitypub/user/outbox.rs index fbbbabbe..4ee35978 100644 --- a/src/activitypub/user/outbox.rs +++ b/src/activitypub/user/outbox.rs @@ -1,7 +1,7 @@ use axum::{extract::{Path, Query, State}, http::StatusCode}; use sea_orm::{EntityTrait, Order, QueryOrder, QuerySelect}; -use crate::{activitypub::{jsonld::LD, JsonLD, Pagination}, activitystream::{object::{activity::ActivityMut, collection::{page::CollectionPageMut, CollectionMut, CollectionType}}, Base, BaseMut, Node}, model::{activity, object}, server::Context, url}; +use crate::{activitypub::{jsonld::LD, JsonLD, Pagination}, activitystream::{object::{activity::ActivityMut, collection::{page::CollectionPageMut, CollectionMut, CollectionType}}, BaseMut, Node}, model::{activity, object}, server::Context, url}; pub async fn outbox( State(ctx): State, @@ -23,7 +23,10 @@ pub async fn outbox( let next = ctx.id(items.last().map(|(a, _o)| a.id.as_str()).unwrap_or("").to_string()); let items = items .into_iter() - .map(|(a, o)| a.underlying_json_object().set_object(Node::maybe_object(o))) + .map(|(a, o)| + super::super::activity::ap_activity(a) + .set_object(Node::maybe_object(o.map(super::super::object::ap_object))) + ) .collect(); Ok(JsonLD( serde_json::Value::new_object() diff --git a/src/model/activity.rs b/src/model/activity.rs index b4824bb2..3a5477cb 100644 --- a/src/model/activity.rs +++ b/src/model/activity.rs @@ -1,6 +1,6 @@ use sea_orm::entity::prelude::*; -use crate::{activitypub::jsonld::LD, activitystream::{link::Link, object::{activity::{Activity, ActivityMut, ActivityType}, actor::Actor, Object, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node}}; +use crate::activitystream::object::activity::{Activity, ActivityType}; use super::Audience; @@ -25,6 +25,23 @@ pub struct Model { // TODO: origin, result, instrument } +impl Model { + pub fn new(activity: &impl Activity) -> Result { + Ok(Model { + id: activity.id().ok_or(super::FieldError("id"))?.to_string(), + activity_type: activity.activity_type().ok_or(super::FieldError("type"))?, + actor: activity.actor().id().ok_or(super::FieldError("actor"))?.to_string(), + object: activity.object().id().map(|x| x.to_string()), + target: activity.target().id().map(|x| x.to_string()), + published: activity.published().unwrap_or(chrono::Utc::now()), + to: activity.to().into(), + bto: activity.bto().into(), + cc: activity.cc().into(), + bcc: activity.bcc().into(), + }) + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( @@ -55,94 +72,3 @@ impl Related for Entity { } impl ActiveModelBehavior for ActiveModel {} - -impl Base for Model { - fn id(&self) -> Option<&str> { - Some(&self.id) - } - - fn base_type(&self) -> Option { - Some(BaseType::Object(ObjectType::Activity(self.activity_type))) - } - - fn underlying_json_object(self) -> serde_json::Value { - serde_json::Value::new_object() - .set_id(Some(&self.id)) - .set_activity_type(Some(self.activity_type)) - .set_actor(Node::link(self.actor)) - .set_object(Node::maybe_link(self.object)) - .set_target(Node::maybe_link(self.target)) - .set_published(Some(self.published)) - .set_to(Node::links(self.to.0.clone())) - .set_bto(Node::empty()) - .set_cc(Node::links(self.cc.0.clone())) - .set_bcc(Node::empty()) - } -} - -impl Object for Model { - fn object_type(&self) -> Option { - Some(ObjectType::Activity(self.activity_type)) - } - - fn published(&self) -> Option> { - Some(self.published) - } - - fn to(&self) -> Node { - Node::links(self.to.0.clone()) - } - - fn bto(&self) -> Node { - Node::links(self.bto.0.clone()) - } - - fn cc(&self) -> Node { - Node::links(self.cc.0.clone()) - } - - fn bcc(&self) -> Node { - Node::links(self.bcc.0.clone()) - } -} - -impl Activity for Model { - fn activity_type(&self) -> Option { - Some(self.activity_type) - } - - fn actor(&self) -> Node { - Node::::Link(Box::new(self.actor.clone())) - } - - fn object(&self) -> Node { - match &self.object { - None => Node::Empty::, - Some(x) => Node::Link(Box::new(x.clone())), - } - } - - fn target(&self) -> Node { - match &self.target { - None => Node::Empty::, - Some(x) => Node::Link(Box::new(x.clone())), - } - } -} - -impl Model { - pub fn new(activity: &impl Activity) -> Result { - Ok(Model { - id: activity.id().ok_or(super::FieldError("id"))?.to_string(), - activity_type: activity.activity_type().ok_or(super::FieldError("type"))?, - actor: activity.actor().id().ok_or(super::FieldError("actor"))?.to_string(), - object: activity.object().id().map(|x| x.to_string()), - target: activity.target().id().map(|x| x.to_string()), - published: activity.published().unwrap_or(chrono::Utc::now()), - to: activity.to().into(), - bto: activity.bto().into(), - cc: activity.cc().into(), - bcc: activity.bcc().into(), - }) - } -} diff --git a/src/model/object.rs b/src/model/object.rs index 96fcd6bf..6c84e128 100644 --- a/src/model/object.rs +++ b/src/model/object.rs @@ -1,6 +1,6 @@ use sea_orm::entity::prelude::*; -use crate::{activitypub::jsonld::LD, activitystream::{object::{ObjectMut, ObjectType}, BaseMut, BaseType, Link, Node}}; +use crate::activitystream::object::ObjectType; use super::Audience; @@ -26,6 +26,28 @@ pub struct Model { pub published: ChronoDateTimeUtc, } +impl Model { + pub fn new(object: &impl crate::activitystream::object::Object) -> Result { + Ok(Model { + id: object.id().ok_or(super::FieldError("id"))?.to_string(), + object_type: object.object_type().ok_or(super::FieldError("type"))?, + attributed_to: object.attributed_to().id().map(|x| x.to_string()), + name: object.name().map(|x| x.to_string()), + summary: object.summary().map(|x| x.to_string()), + content: object.content().map(|x| x.to_string()), + context: object.context().id().map(|x| x.to_string()), + published: object.published().ok_or(super::FieldError("published"))?, + comments: 0, + likes: 0, + shares: 0, + to: object.to().into(), + bto: object.bto().into(), + cc: object.cc().into(), + bcc: object.bcc().into(), + }) + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::activity::Entity")] @@ -52,97 +74,3 @@ impl Related for Entity { } 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(self.object_type)) - } - - fn underlying_json_object(self) -> serde_json::Value { - serde_json::Value::new_object() - .set_id(Some(&self.id)) - .set_object_type(Some(self.object_type)) - .set_attributed_to(Node::maybe_link(self.attributed_to)) - .set_name(self.name.as_deref()) - .set_summary(self.summary.as_deref()) - .set_content(self.content.as_deref()) - .set_context(Node::maybe_link(self.context.clone())) - .set_published(Some(self.published)) - .set_to(Node::links(self.to.0.clone())) - .set_bto(Node::empty()) - .set_cc(Node::links(self.cc.0.clone())) - .set_bcc(Node::empty()) - } -} - -impl crate::activitystream::object::Object for Model { - fn object_type(&self) -> Option { - Some(self.object_type) - } - - fn attributed_to(&self) -> Node { - Node::::from(self.attributed_to.as_deref()) - } - - fn name(&self) -> Option<&str> { - self.name.as_deref() - } - - fn summary(&self) -> Option<&str> { - self.summary.as_deref() - } - - fn content(&self) -> Option<&str> { - self.content.as_deref() - } - - fn context(&self) -> Node { - Node::maybe_link(self.context.clone()) - } - - fn to(&self) -> Node { - Node::links(self.to.0.clone()) - } - - fn bto(&self) -> Node { - Node::links(self.bto.0.clone()) - } - - fn cc(&self) -> Node { - Node::links(self.cc.0.clone()) - } - - fn bcc(&self) -> Node { - Node::links(self.bcc.0.clone()) - } - - fn published (&self) -> Option> { - Some(self.published) - } -} - -impl Model { - pub fn new(object: &impl crate::activitystream::object::Object) -> Result { - Ok(Model { - id: object.id().ok_or(super::FieldError("id"))?.to_string(), - object_type: object.object_type().ok_or(super::FieldError("type"))?, - attributed_to: object.attributed_to().id().map(|x| x.to_string()), - name: object.name().map(|x| x.to_string()), - summary: object.summary().map(|x| x.to_string()), - content: object.content().map(|x| x.to_string()), - context: object.context().id().map(|x| x.to_string()), - published: object.published().ok_or(super::FieldError("published"))?, - comments: 0, - likes: 0, - shares: 0, - to: object.to().into(), - bto: object.bto().into(), - cc: object.cc().into(), - bcc: object.bcc().into(), - }) - } -} diff --git a/src/model/user.rs b/src/model/user.rs index ef1da4db..2495ce4d 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -35,6 +35,29 @@ pub struct Model { // pub streams: Option, } +impl Model { + pub fn new(object: &impl Actor) -> Result { + let ap_id = object.id().ok_or(super::FieldError("id"))?.to_string(); + let (domain, preferred_username) = activitypub::split_id(&ap_id); + Ok(Model { + id: ap_id, preferred_username, domain, + actor_type: object.actor_type().ok_or(super::FieldError("type"))?, + name: object.name().map(|x| x.to_string()), + summary: object.summary().map(|x| x.to_string()), + icon: object.icon().id().map(|x| x.to_string()), + image: object.image().id().map(|x| x.to_string()), + inbox: object.inbox().id().map(|x| x.to_string()), + outbox: object.inbox().id().map(|x| x.to_string()), + shared_inbox: None, // TODO!!! parse endpoints + followers: object.followers().id().map(|x| x.to_string()), + following: object.following().id().map(|x| x.to_string()), + created: object.published().unwrap_or(chrono::Utc::now()), + updated: chrono::Utc::now(), + 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 + }) + } +} #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { @@ -76,127 +99,3 @@ impl Related for Entity { } 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 Model { - pub fn new(object: &impl Actor) -> Result { - let ap_id = object.id().ok_or(super::FieldError("id"))?.to_string(); - let (domain, preferred_username) = activitypub::split_id(&ap_id); - Ok(Model { - id: ap_id, preferred_username, domain, - actor_type: object.actor_type().ok_or(super::FieldError("type"))?, - name: object.name().map(|x| x.to_string()), - summary: object.summary().map(|x| x.to_string()), - icon: object.icon().id().map(|x| x.to_string()), - image: object.image().id().map(|x| x.to_string()), - inbox: object.inbox().id().map(|x| x.to_string()), - outbox: object.inbox().id().map(|x| x.to_string()), - shared_inbox: None, // TODO!!! parse endpoints - followers: object.followers().id().map(|x| x.to_string()), - following: object.following().id().map(|x| x.to_string()), - created: object.published().unwrap_or(chrono::Utc::now()), - updated: chrono::Utc::now(), - 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 - }) - } -}