use crate::activitypub::constants::{ AS_CONTEXT, MASTODON_CONTEXT, SCHEMA_ORG_CONTEXT, W3ID_SECURITY_CONTEXT, }; use chrono::{DateTime, Utc}; use serde::{de::Error as DeserializerError, Deserialize, Deserializer, Serialize}; use serde_json::{json, Value}; use super::receiver::parse_property_value; use super::vocabulary::HASHTAG; #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Attachment { #[serde(rename = "type")] pub attachment_type: String, pub name: Option, pub media_type: Option, pub url: Option, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct Link { pub href: String, } fn default_tag_type() -> String { HASHTAG.to_string() } #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Tag { pub name: Option, #[serde(rename = "type", default = "default_tag_type")] pub tag_type: String, pub href: Option, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct SimpleTag { #[serde(rename = "type")] pub tag_type: String, pub href: String, pub name: String, } /// https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-e232.md #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct LinkTag { #[serde(rename = "type")] pub tag_type: String, pub href: String, pub media_type: String, pub name: Option, } #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct EmojiTagImage { #[serde(rename = "type")] pub object_type: String, pub url: String, pub media_type: Option, } #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct EmojiTag { #[serde(rename = "type")] pub tag_type: String, pub icon: EmojiTagImage, pub id: String, pub name: String, pub updated: DateTime, } pub fn deserialize_value_array<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let maybe_value: Option = Option::deserialize(deserializer)?; let values = if let Some(value) = maybe_value { parse_property_value(&value).map_err(DeserializerError::custom)? } else { vec![] }; Ok(values) } #[derive(Deserialize)] #[cfg_attr(test, derive(Default))] #[serde(rename_all = "camelCase")] pub struct Object { // https://www.w3.org/TR/activitypub/#obj-id // "id" and "type" are required properties pub id: String, #[serde(rename = "type")] pub object_type: String, pub name: Option, pub attachment: Option, pub cc: Option, pub media_type: Option, pub published: Option>, pub attributed_to: Option, pub in_reply_to: Option, pub content: Option, pub quote_url: Option, pub sensitive: Option, #[serde(default, deserialize_with = "deserialize_value_array")] pub tag: Vec, pub to: Option, pub updated: Option>, pub url: Option, } pub type Context = Value; pub fn build_default_context() -> Context { json!([ AS_CONTEXT, W3ID_SECURITY_CONTEXT, { "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "toot": MASTODON_CONTEXT, "featured": { "@id": "toot:featured", "@type": "@id" }, "featuredTags": { "@id": "toot:featuredTags", "@type": "@id" }, "alsoKnownAs": { "@id": "as:alsoKnownAs", "@type": "@id" }, "movedTo": { "@id": "as:movedTo", "@type": "@id" }, "schema": SCHEMA_ORG_CONTEXT, "PropertyValue": "schema:PropertyValue", "value": "schema:value", "IdentityProof": "toot:IdentityProof", "discoverable": "toot:discoverable", "Device": "toot:Device", "Ed25519Signature": "toot:Ed25519Signature", "Ed25519Key": "toot:Ed25519Key", "Curve25519Key": "toot:Curve25519Key", "EncryptedMessage": "toot:EncryptedMessage", "publicKeyBase64": "toot:publicKeyBase64", "deviceId": "toot:deviceId", "claim": { "@type": "@id", "@id": "toot:claim" }, "fingerprintKey": { "@type": "@id", "@id": "toot:fingerprintKey" }, "identityKey": { "@type": "@id", "@id": "toot:identityKey" }, "devices": { "@type": "@id", "@id": "toot:devices" }, "messageFranking": "toot:messageFranking", "messageType": "toot:messageType", "cipherText": "toot:cipherText", "suspended": "toot:suspended", "focalPoint": { "@container": "@list", "@id": "toot:focalPoint" } } ]) }