Allow single item for to, cc, and @context

release/v0.14
Colin Reeder 2021-11-26 21:55:33 -07:00 committed by Dessalines
parent be951a76c8
commit cfda9b73dd
16 changed files with 48 additions and 0 deletions

View File

@ -8,6 +8,7 @@ static CONTEXT: Lazy<Vec<serde_json::Value>> = Lazy::new(|| {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub(crate) struct WithContext<T> { pub(crate) struct WithContext<T> {
#[serde(rename = "@context")] #[serde(rename = "@context")]
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
context: Vec<serde_json::Value>, context: Vec<serde_json::Value>,
#[serde(flatten)] #[serde(flatten)]
inner: T, inner: T,

View File

@ -3,6 +3,7 @@ use anyhow::{anyhow, Context};
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool}; use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use serde::{Deserialize, Deserializer};
use std::net::IpAddr; use std::net::IpAddr;
use url::{ParseError, Url}; use url::{ParseError, Url};
@ -85,6 +86,25 @@ pub(crate) fn check_is_apub_id_valid(
Ok(()) Ok(())
} }
pub(crate) fn deserialize_one_or_many<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}
let result: OneOrMany<T> = Deserialize::deserialize(deserializer)?;
Ok(match result {
OneOrMany::Many(list) => list,
OneOrMany::One(value) => vec![value],
})
}
pub enum EndpointType { pub enum EndpointType {
Community, Community,
Person, Person,

View File

@ -8,9 +8,11 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct AddMod { pub struct AddMod {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: ObjectId<ApubPerson>, pub(crate) object: ObjectId<ApubPerson>,
pub(crate) target: Url, pub(crate) target: Url,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: AddType, pub(crate) kind: AddType,

View File

@ -12,8 +12,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct AnnounceActivity { pub struct AnnounceActivity {
pub(crate) actor: ObjectId<ApubCommunity>, pub(crate) actor: ObjectId<ApubCommunity>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: AnnouncableActivities, pub(crate) object: AnnouncableActivities,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: AnnounceType, pub(crate) kind: AnnounceType,

View File

@ -11,8 +11,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct BlockUserFromCommunity { pub struct BlockUserFromCommunity {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: ObjectId<ApubPerson>, pub(crate) object: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
pub(crate) target: ObjectId<ApubCommunity>, pub(crate) target: ObjectId<ApubCommunity>,
#[serde(rename = "type")] #[serde(rename = "type")]

View File

@ -8,8 +8,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct RemoveMod { pub struct RemoveMod {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: ObjectId<ApubPerson>, pub(crate) object: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: RemoveType, pub(crate) kind: RemoveType,

View File

@ -11,8 +11,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UndoBlockUserFromCommunity { pub struct UndoBlockUserFromCommunity {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: BlockUserFromCommunity, pub(crate) object: BlockUserFromCommunity,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: UndoType, pub(crate) kind: UndoType,

View File

@ -13,9 +13,11 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateCommunity { pub struct UpdateCommunity {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
// TODO: would be nice to use a separate struct here, which only contains the fields updated here // TODO: would be nice to use a separate struct here, which only contains the fields updated here
pub(crate) object: Box<Group>, pub(crate) object: Box<Group>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: UpdateType, pub(crate) kind: UpdateType,

View File

@ -11,8 +11,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateOrUpdateComment { pub struct CreateOrUpdateComment {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: Note, pub(crate) object: Note,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(default)] #[serde(default)]
pub(crate) tag: Vec<Mention>, pub(crate) tag: Vec<Mention>,

View File

@ -10,8 +10,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateOrUpdatePost { pub struct CreateOrUpdatePost {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: Page, pub(crate) object: Page,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: CreateOrUpdateType, pub(crate) kind: CreateOrUpdateType,

View File

@ -13,6 +13,7 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Delete { pub struct Delete {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: Tombstone, pub(crate) object: Tombstone,
#[serde(rename = "type")] #[serde(rename = "type")]

View File

@ -11,8 +11,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UndoDelete { pub struct UndoDelete {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: Delete, pub(crate) object: Delete,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: UndoType, pub(crate) kind: UndoType,

View File

@ -11,8 +11,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UndoVote { pub struct UndoVote {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: Vote, pub(crate) object: Vote,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: UndoType, pub(crate) kind: UndoType,

View File

@ -15,8 +15,10 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Vote { pub struct Vote {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
pub(crate) object: ObjectId<PostOrComment>, pub(crate) object: ObjectId<PostOrComment>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: VoteType, pub(crate) kind: VoteType,

View File

@ -23,8 +23,10 @@ pub struct Note {
pub(crate) r#type: NoteType, pub(crate) r#type: NoteType,
pub(crate) id: ObjectId<ApubComment>, pub(crate) id: ObjectId<ApubComment>,
pub(crate) attributed_to: ObjectId<ApubPerson>, pub(crate) attributed_to: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
#[serde(default)] #[serde(default)]
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
pub(crate) content: String, pub(crate) content: String,
pub(crate) media_type: Option<MediaTypeHtml>, pub(crate) media_type: Option<MediaTypeHtml>,

View File

@ -24,8 +24,10 @@ pub struct Page {
pub(crate) r#type: PageType, pub(crate) r#type: PageType,
pub(crate) id: ObjectId<ApubPost>, pub(crate) id: ObjectId<ApubPost>,
pub(crate) attributed_to: ObjectId<ApubPerson>, pub(crate) attributed_to: ObjectId<ApubPerson>,
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
#[serde(default)] #[serde(default)]
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
pub(crate) name: String, pub(crate) name: String,
pub(crate) content: Option<String>, pub(crate) content: Option<String>,