diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index b0b06a14..256b5a9b 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -1,8 +1,8 @@ use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; -use crate::{activitystream::{prelude::*, Node}, model::{activity, object}, server::Context}; +use crate::{activitystream::{object::activity::ActivityMut, Base, Node}, model::{activity, object}, server::Context}; -use super::JsonLD; +use super::{jsonld::LD, JsonLD}; pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { @@ -11,7 +11,12 @@ pub async fn view(State(ctx) : State, Path(id): Path) -> Result .one(ctx.db()) .await { - Ok(Some((activity, object))) => Ok(JsonLD(activity.underlying_json_object().set_object(Node::maybe_object(object)))), + Ok(Some((activity, object))) => Ok(JsonLD( + activity + .underlying_json_object() + .set_object(Node::maybe_object(object)) + .ld_context() + )), Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for activity: {e}"); diff --git a/src/activitypub/jsonld.rs b/src/activitypub/jsonld.rs index 46a6faa5..664f37fa 100644 --- a/src/activitypub/jsonld.rs +++ b/src/activitypub/jsonld.rs @@ -1,26 +1,34 @@ -// got this from https://github.com/kitsune-soc/kitsune/blob/b023a12b687dd9a274233a5a9950f2de5e192344/kitsune/src/http/responder.rs -// i was trying to do it with middlewares but this is way cleaner +use axum::response::{IntoResponse, Response}; -use axum::{ - response::{IntoResponse, Response}, - Json, -}; -use serde::Serialize; - -pub struct JsonLD(pub T); - -impl IntoResponse for JsonLD -where - T: Serialize, -{ - fn into_response(self) -> Response { - ( - [( - "Content-Type", - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", - )], - Json(self.0), - ) - .into_response() +pub trait LD { + fn ld_context(self) -> Self; + fn new_object() -> serde_json::Value { + serde_json::Value::Object(serde_json::Map::default()) + } +} + +impl LD for serde_json::Value { + fn ld_context(mut self) -> Self { + if let Some(obj) = self.as_object_mut() { + obj.insert( + "@context".to_string(), + serde_json::Value::Array(vec![ + serde_json::Value::String("https://www.w3.org/ns/activitystreams".into()) + ]), + ); + } else { + tracing::warn!("cannot add @context to json value different than object"); + } + self + } +} + +// got this from https://github.com/kitsune-soc/kitsune/blob/b023a12b687dd9a274233a5a9950f2de5e192344/kitsune/src/http/responder.rs +// i was trying to do it with middlewares but this is way cleaner +pub struct JsonLD(pub T); +impl IntoResponse for JsonLD { + fn into_response(self) -> Response { + // headers body + ([("Content-Type", "application/ld+json")], axum::Json(self.0)).into_response() } } diff --git a/src/activitypub/mod.rs b/src/activitypub/mod.rs index 6fbd0b5c..3c2ea7f7 100644 --- a/src/activitypub/mod.rs +++ b/src/activitypub/mod.rs @@ -7,7 +7,9 @@ pub use jsonld::JsonLD; use axum::{extract::State, http::StatusCode, Json}; use sea_orm::{EntityTrait, IntoActiveModel}; -use crate::{activitystream::{self, object::{activity::{Activity, ActivityType}, actor::{ActorMut, ActorType}, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node}, model, server::Context, url}; +use crate::{activitystream::{object::{activity::{Activity, ActivityType}, actor::{ActorMut, ActorType}, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node}, model, server::Context, url}; + +use self::jsonld::LD; pub const PUBLIC_TARGET : &str = "https://www.w3.org/ns/activitystreams#Public"; @@ -38,7 +40,7 @@ pub struct Page { pub async fn view(State(ctx): State) -> Result, StatusCode> { Ok(Json( - activitystream::object() + serde_json::Value::new_object() .set_actor_type(Some(ActorType::Application)) .set_id(Some(&url!(ctx, ""))) .set_name(Some("μpub")) diff --git a/src/activitypub/user.rs b/src/activitypub/user.rs index 63d0d6bb..b0df2d4a 100644 --- a/src/activitypub/user.rs +++ b/src/activitypub/user.rs @@ -1,12 +1,11 @@ use std::sync::Arc; -use crate::activitystream::prelude::*; use axum::{extract::{Path, Query, State}, http::StatusCode, Json}; use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, IntoActiveModel, Order, QueryFilter, QueryOrder, QuerySelect}; -use crate::{activitystream::{self, object::{activity::ActivityType, collection::CollectionType, ObjectType}, BaseType, Node}, model::{self, activity, object, user}, server::Context, url}; +use crate::{activitystream::{object::{activity::{Activity, ActivityMut, ActivityType}, collection::{page::CollectionPageMut, CollectionMut, CollectionType}, ObjectType}, Base, BaseMut, BaseType, Node}, model::{self, activity, object, user}, server::Context, url}; -use super::JsonLD; +use super::{jsonld::LD, JsonLD}; pub async fn list(State(_db) : State>) -> Result, StatusCode> { todo!() @@ -14,7 +13,7 @@ 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())), + Ok(Some(user)) => Ok(JsonLD(user.underlying_json_object().ld_context())), Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for user: {e}"); @@ -59,7 +58,7 @@ pub async fn outbox( .map(|(a, o)| a.underlying_json_object().set_object(Node::maybe_object(o))) .collect(); Ok(JsonLD( - activitystream::object() + serde_json::Value::new_object() // TODO set id, calculate uri from given args .set_collection_type(Some(CollectionType::OrderedCollectionPage)) .set_part_of(Node::link(url!(ctx, "/users/{id}/outbox"))) @@ -71,7 +70,7 @@ pub async fn outbox( } else { Ok(JsonLD( - crate::activitystream::object() + serde_json::Value::new_object() .set_id(Some(&url!(ctx, "/users/{id}/outbox"))) .set_collection_type(Some(CollectionType::OrderedCollection)) .set_first(Node::link(url!(ctx, "/users/{id}/outbox?page=true"))) diff --git a/src/activitystream/mod.rs b/src/activitystream/mod.rs index bea9bb57..6acebd53 100644 --- a/src/activitystream/mod.rs +++ b/src/activitystream/mod.rs @@ -32,17 +32,6 @@ pub trait Base { fn underlying_json_object(self) -> serde_json::Value; } -pub fn raw_object() -> serde_json::Value { serde_json::Value::Object(serde_json::Map::default()) } -pub fn object() -> serde_json::Value { - let mut map = serde_json::Map::default(); - map.insert( - "@context".to_string(), - serde_json::Value::Array(vec![ - serde_json::Value::String("https://www.w3.org/ns/activitystreams".into()) - ]), - ); - serde_json::Value::Object(map) -} pub trait BaseMut { fn set_id(self, val: Option<&str>) -> Self; diff --git a/src/activitystream/object/actor.rs b/src/activitystream/object/actor.rs index 293ee04e..1fc9c545 100644 --- a/src/activitystream/object/actor.rs +++ b/src/activitystream/object/actor.rs @@ -8,8 +8,7 @@ strenum! { Application, Group, Organization, - Person, - Object; + Person; }; } diff --git a/src/model/activity.rs b/src/model/activity.rs index 0e649501..5a288ba1 100644 --- a/src/model/activity.rs +++ b/src/model/activity.rs @@ -1,6 +1,6 @@ use sea_orm::{entity::prelude::*, FromJsonQueryResult}; -use crate::activitystream::{self, link::Link, object::{activity::{Activity, ActivityMut, ActivityType}, actor::Actor, Object, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node}; +use crate::{activitypub::jsonld::LD, activitystream::{link::Link, object::{activity::{Activity, ActivityMut, ActivityType}, actor::Actor, Object, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node}}; #[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, FromJsonQueryResult)] pub struct Audience(pub Vec); @@ -80,7 +80,7 @@ impl Base for Model { } fn underlying_json_object(self) -> serde_json::Value { - activitystream::object() + serde_json::Value::new_object() .set_id(Some(&self.id)) .set_activity_type(Some(self.activity_type)) .set_actor(Node::link(self.actor)) diff --git a/src/model/object.rs b/src/model/object.rs index 91ca3ae1..61892a3c 100644 --- a/src/model/object.rs +++ b/src/model/object.rs @@ -1,7 +1,6 @@ use sea_orm::entity::prelude::*; -use crate::activitystream::prelude::*; -use crate::activitystream::{object::ObjectType, BaseType, Node}; +use crate::{activitypub::jsonld::LD, activitystream::{object::{ObjectMut, ObjectType}, BaseMut, BaseType, Node}}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "objects")] @@ -54,7 +53,7 @@ impl crate::activitystream::Base for Model { } fn underlying_json_object(self) -> serde_json::Value { - crate::activitystream::object() + 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)) diff --git a/src/model/user.rs b/src/model/user.rs index cdf0099e..ddbe001a 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -1,7 +1,11 @@ use sea_orm::entity::prelude::*; -use crate::activitystream::object::document::DocumentType; -use crate::activitystream::prelude::*; +use crate::activitypub::jsonld::LD; +use crate::activitystream::key::{PublicKey as _, PublicKeyMut as _}; +use crate::activitystream::object::actor::ActorMut as _; +use crate::activitystream::object::document::{DocumentMut as _, DocumentType}; +use crate::activitystream::object::ObjectMut as _; +use crate::activitystream::{BaseMut as _, Object as _}; use crate::{activitypub, activitystream::{object::actor::ActorType, BaseType, Node, ObjectType}}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] @@ -71,7 +75,7 @@ impl crate::activitystream::Base for Model { } fn underlying_json_object(self) -> serde_json::Value { - crate::activitystream::object() + serde_json::Value::new_object() .set_id(Some(&self.id)) .set_actor_type(Some(self.actor_type)) .set_name(self.name.as_deref()) @@ -87,7 +91,6 @@ impl crate::activitystream::Base for Model { .set_public_key(self.public_key()) .set_discoverable(Some(true)) .set_endpoints(None) // TODO dirty fix to put an empty object - .underlying_json_object() } } @@ -103,7 +106,7 @@ impl crate::activitystream::object::Object for Model { fn icon(&self) -> Node { match &self.icon { Some(x) => Node::object( - crate::activitystream::raw_object() + serde_json::Value::new_object() .set_document_type(Some(DocumentType::Image)) .set_url(Node::link(x.clone())) ), @@ -114,7 +117,7 @@ impl crate::activitystream::object::Object for Model { fn image(&self) -> Node { match &self.image { Some(x) => Node::object( - crate::activitystream::raw_object() + serde_json::Value::new_object() .set_document_type(Some(DocumentType::Image)) .set_url(Node::link(x.clone())) ), @@ -154,7 +157,7 @@ impl crate::activitystream::object::actor::Actor for Model { fn public_key(&self) -> Node { Node::object( - crate::activitystream::raw_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))