diff --git a/src/activitypub/activity.rs b/src/activitypub/activity.rs index 069eec2b..b0b06a14 100644 --- a/src/activitypub/activity.rs +++ b/src/activitypub/activity.rs @@ -1,15 +1,17 @@ -use axum::{extract::{Path, State}, http::StatusCode, Json}; +use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; use crate::{activitystream::{prelude::*, Node}, model::{activity, object}, server::Context}; +use super::JsonLD; -pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { + +pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { match activity::Entity::find_by_id(ctx.aid(id)) .find_also_related(object::Entity) .one(ctx.db()) .await { - Ok(Some((activity, object))) => Ok(Json(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)))), 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 new file mode 100644 index 00000000..46a6faa5 --- /dev/null +++ b/src/activitypub/jsonld.rs @@ -0,0 +1,26 @@ +// 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}, + 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() + } +} diff --git a/src/activitypub/mod.rs b/src/activitypub/mod.rs index 331d4e21..6fbd0b5c 100644 --- a/src/activitypub/mod.rs +++ b/src/activitypub/mod.rs @@ -1,6 +1,8 @@ pub mod user; pub mod object; pub mod activity; +pub mod jsonld; +pub use jsonld::JsonLD; use axum::{extract::State, http::StatusCode, Json}; use sea_orm::{EntityTrait, IntoActiveModel}; @@ -46,7 +48,7 @@ pub async fn view(State(ctx): State) -> Result, )) } -pub async fn inbox(State(ctx) : State, Json(object): Json) -> Result, StatusCode> { +pub async fn inbox(State(ctx) : State, Json(object): Json) -> Result, StatusCode> { match object.base_type() { None => { Err(StatusCode::BAD_REQUEST) }, Some(BaseType::Link(_x)) => Err(StatusCode::UNPROCESSABLE_ENTITY), // we could but not yet @@ -70,7 +72,7 @@ pub async fn inbox(State(ctx) : State, Json(object): Json { Err(StatusCode::NOT_IMPLEMENTED) }, Some(_x) => { Err(StatusCode::UNPROCESSABLE_ENTITY) } diff --git a/src/activitypub/object.rs b/src/activitypub/object.rs index 11f8f21c..16460485 100644 --- a/src/activitypub/object.rs +++ b/src/activitypub/object.rs @@ -1,12 +1,14 @@ -use axum::{extract::{Path, State}, http::StatusCode, Json}; +use axum::{extract::{Path, State}, http::StatusCode}; use sea_orm::EntityTrait; use crate::{activitystream::Base, model::object, server::Context}; +use super::JsonLD; -pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { + +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(Json(object.underlying_json_object())), + Ok(Some(object)) => Ok(JsonLD(object.underlying_json_object())), Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for object: {e}"); diff --git a/src/activitypub/user.rs b/src/activitypub/user.rs index a80403a2..63d0d6bb 100644 --- a/src/activitypub/user.rs +++ b/src/activitypub/user.rs @@ -6,13 +6,15 @@ use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, IntoActiv use crate::{activitystream::{self, object::{activity::ActivityType, collection::CollectionType, ObjectType}, BaseType, Node}, model::{self, activity, object, user}, server::Context, url}; -pub async fn list(State(_db) : State>) -> Result, StatusCode> { +use super::JsonLD; + +pub async fn list(State(_db) : State>) -> Result, StatusCode> { todo!() } -pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { +pub async fn view(State(ctx) : State, Path(id): Path) -> Result, StatusCode> { match user::Entity::find_by_id(ctx.uid(id)).one(ctx.db()).await { - Ok(Some(user)) => Ok(Json(user.underlying_json_object())), + Ok(Some(user)) => Ok(JsonLD(user.underlying_json_object())), Ok(None) => Err(StatusCode::NOT_FOUND), Err(e) => { tracing::error!("error querying for user: {e}"); @@ -25,7 +27,7 @@ pub async fn outbox( State(ctx): State, Path(id): Path, Query(page): Query, -) -> Result, StatusCode> { +) -> Result, StatusCode> { if let Some(true) = page.page { // find requested recent post, to filter based on its date (use now() as fallback) @@ -56,7 +58,7 @@ pub async fn outbox( .into_iter() .map(|(a, o)| a.underlying_json_object().set_object(Node::maybe_object(o))) .collect(); - Ok(Json( + Ok(JsonLD( activitystream::object() // TODO set id, calculate uri from given args .set_collection_type(Some(CollectionType::OrderedCollectionPage)) @@ -68,7 +70,7 @@ pub async fn outbox( } } else { - Ok(Json( + Ok(JsonLD( crate::activitystream::object() .set_id(Some(&url!(ctx, "/users/{id}/outbox"))) .set_collection_type(Some(CollectionType::OrderedCollection)) @@ -81,7 +83,7 @@ pub async fn inbox( State(ctx): State, Path(_id): Path, Json(object): Json -) -> Result, StatusCode> { +) -> Result, StatusCode> { match object.base_type() { None => { Err(StatusCode::BAD_REQUEST) }, Some(BaseType::Link(_x)) => Err(StatusCode::UNPROCESSABLE_ENTITY), // we could but not yet @@ -105,7 +107,7 @@ pub async fn inbox( activity::Entity::insert(activity_entity.into_active_model()) .exec(ctx.db()) .await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - Ok(Json(serde_json::Value::Null)) // TODO hmmmmmmmmmmm not the best value to return.... + Ok(JsonLD(serde_json::Value::Null)) // TODO hmmmmmmmmmmm not the best value to return.... }, Some(BaseType::Object(ObjectType::Activity(_x))) => { Err(StatusCode::NOT_IMPLEMENTED) }, Some(_x) => { Err(StatusCode::UNPROCESSABLE_ENTITY) }