mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-25 01:10:32 +00:00
Merge pull request #1962 from vpzomtrrfrt/oneormany2
Allow single item for to, cc, and @context
This commit is contained in:
commit
8bf0f31b0f
19 changed files with 101 additions and 0 deletions
30
crates/apub/assets/lotide/activities/create_note_reply.json
Normal file
30
crates/apub/assets/lotide/activities/create_note_reply.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"actor": "https://c.tide.tk/users/1",
|
||||||
|
"object": {
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id": "https://c.tide.tk/comments/52",
|
||||||
|
"type": "Note",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"source": {
|
||||||
|
"content": "test comment",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"attributedTo": "https://c.tide.tk/users/1",
|
||||||
|
"content": "<p>test comment</p>\n",
|
||||||
|
"published": "2021-09-16T01:20:27.558063+00:00",
|
||||||
|
"inReplyTo": "https://c.tide.tk/posts/51",
|
||||||
|
"to": "https://c.tide.tk/users/1",
|
||||||
|
"cc": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://c.tide.tk/communities/1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"to": "https://c.tide.tk/users/1",
|
||||||
|
"cc": [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"https://c.tide.tk/communities/1"
|
||||||
|
],
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id": "https://c.tide.tk/comments/52/create",
|
||||||
|
"type": "Create"
|
||||||
|
}
|
20
crates/apub/assets/lotide/activities/create_page.json
Normal file
20
crates/apub/assets/lotide/activities/create_page.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"actor": "https://b.tide.tk/apub/users/1",
|
||||||
|
"object": {
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id": "https://b.tide.tk/apub/posts/60",
|
||||||
|
"type": "Page",
|
||||||
|
"name": "test post from b",
|
||||||
|
"summary": "test post from b",
|
||||||
|
"to": "https://c.tide.tk/communities/1",
|
||||||
|
"cc": "https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"published": "2020-12-19T19:20:26.941381+00:00",
|
||||||
|
"attributedTo": "https://b.tide.tk/apub/users/1",
|
||||||
|
"url": "https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html"
|
||||||
|
},
|
||||||
|
"to": "https://c.tide.tk/communities/1",
|
||||||
|
"cc": "https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id": "https://b.tide.tk/apub/posts/60/create",
|
||||||
|
"type": "Create"
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -26,5 +26,8 @@ mod tests {
|
||||||
file_to_json_object::<CreateOrUpdateComment>("assets/pleroma/activities/create_note.json");
|
file_to_json_object::<CreateOrUpdateComment>("assets/pleroma/activities/create_note.json");
|
||||||
file_to_json_object::<CreateOrUpdateComment>("assets/smithereen/activities/create_note.json");
|
file_to_json_object::<CreateOrUpdateComment>("assets/smithereen/activities/create_note.json");
|
||||||
file_to_json_object::<CreateOrUpdateComment>("assets/mastodon/activities/create_note.json");
|
file_to_json_object::<CreateOrUpdateComment>("assets/mastodon/activities/create_note.json");
|
||||||
|
|
||||||
|
file_to_json_object::<CreateOrUpdatePost>("assets/lotide/activities/create_page.json");
|
||||||
|
file_to_json_object::<CreateOrUpdateComment>("assets/lotide/activities/create_note_reply.json");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
Loading…
Reference in a new issue