//! Wrapper for federated structs which handles `@context` field. //! //! This wrapper can be used when sending Activitypub data, to automatically add `@context`. It //! avoids having to repeat the `@context` property on every struct, and getting multiple contexts //! in nested structs. //! //! ``` //! # use activitypub_federation::protocol::context::WithContext; //! #[derive(serde::Serialize)] //! struct Note { //! content: String //! } //! let note = Note { //! content: "Hello world".to_string() //! }; //! let note_with_context = WithContext::new_default(note); //! let serialized = serde_json::to_string(¬e_with_context)?; //! assert_eq!(serialized, r#"{"@context":["https://www.w3.org/ns/activitystreams"],"content":"Hello world"}"#); //! Ok::<(), serde_json::error::Error>(()) //! ``` use crate::{ config::RequestData, protocol::helpers::deserialize_one_or_many, traits::ActivityHandler, }; use serde::{Deserialize, Serialize}; use serde_json::Value; use url::Url; /// Default context used in Activitypub const DEFAULT_CONTEXT: &str = "https://www.w3.org/ns/activitystreams"; /// Wrapper for federated structs which handles `@context` field. #[derive(Serialize, Deserialize, Debug)] pub struct WithContext { #[serde(rename = "@context")] #[serde(deserialize_with = "deserialize_one_or_many")] context: Vec, #[serde(flatten)] inner: T, } impl WithContext { /// Create a new wrapper with the default Activitypub context. pub fn new_default(inner: T) -> WithContext { let context = vec![Value::String(DEFAULT_CONTEXT.to_string())]; WithContext::new(inner, context) } /// Create new wrapper with custom context. Use this in case you are implementing extensions. pub fn new(inner: T, context: Vec) -> WithContext { WithContext { context, inner } } /// Returns the inner `T` object which this `WithContext` object is wrapping pub fn inner(&self) -> &T { &self.inner } } #[async_trait::async_trait] impl ActivityHandler for WithContext where T: ActivityHandler + Send, { type DataType = ::DataType; type Error = ::Error; fn id(&self) -> &Url { self.inner.id() } fn actor(&self) -> &Url { self.inner.actor() } async fn receive(self, data: &RequestData) -> Result<(), Self::Error> { self.inner.receive(data).await } }