11//! Serde deserialization functions which help to receive differently shaped data
22
3- use serde:: { Deserialize , Deserializer } ;
3+ use activitystreams_kinds:: public;
4+ use itertools:: Itertools ;
5+ use serde:: { de:: Error , Deserialize , Deserializer } ;
6+ use serde_json:: Value ;
7+ use url:: Url ;
48
5- /// Deserialize JSON single value or array into Vec.
9+ /// Deserialize JSON single value or array into ` Vec<Url>` .
610///
711/// Useful if your application can handle multiple values for a field, but another federated
812/// platform only sends a single one.
913///
14+ /// Also accepts common `Public` aliases for recipient fields. Some implementations send `Public`
15+ /// or `as:Public` instead of the canonical `https://www.w3.org/ns/activitystreams#Public` URL
16+ /// in fields such as `to` and `cc`.
17+ ///
1018/// ```
19+ /// # use activitypub_federation::kinds::public;
1120/// # use activitypub_federation::protocol::helpers::deserialize_one_or_many;
1221/// # use url::Url;
1322/// #[derive(serde::Deserialize)]
@@ -25,24 +34,39 @@ use serde::{Deserialize, Deserializer};
2534/// "https://lemmy.ml/u/bob"
2635/// ]}"#)?;
2736/// assert_eq!(multiple.to.len(), 2);
28- /// Ok::<(), anyhow::Error>(())
29- pub fn deserialize_one_or_many < ' de , T , D > ( deserializer : D ) -> Result < Vec < T > , D :: Error >
37+ ///
38+ /// let note: Note = serde_json::from_str(r#"{"to": ["Public", "as:Public"]}"#)?;
39+ /// assert_eq!(note.to, vec![public()]);
40+ /// # Ok::<(), anyhow::Error>(())
41+ /// ```
42+ pub fn deserialize_one_or_many < ' de , D > ( deserializer : D ) -> Result < Vec < Url > , D :: Error >
3043where
31- T : Deserialize < ' de > ,
3244 D : Deserializer < ' de > ,
3345{
3446 #[ derive( Deserialize ) ]
3547 #[ serde( untagged) ]
36- enum OneOrMany < T > {
37- One ( T ) ,
38- Many ( Vec < T > ) ,
48+ enum OneOrMany {
49+ Many ( Vec < Value > ) ,
50+ One ( Value ) ,
3951 }
4052
41- let result: OneOrMany < T > = Deserialize :: deserialize ( deserializer) ?;
42- Ok ( match result {
43- OneOrMany :: Many ( list) => list,
53+ let result: OneOrMany = Deserialize :: deserialize ( deserializer) ?;
54+ let values = match result {
4455 OneOrMany :: One ( value) => vec ! [ value] ,
45- } )
56+ OneOrMany :: Many ( values) => values,
57+ } ;
58+
59+ values
60+ . into_iter ( )
61+ . map ( |value| match value {
62+ Value :: String ( value) if matches ! ( value. as_str( ) , "Public" | "as:Public" ) => {
63+ Ok ( public ( ) )
64+ }
65+ Value :: String ( value) => Url :: parse ( & value) . map_err ( D :: Error :: custom) ,
66+ value => Url :: deserialize ( value) . map_err ( D :: Error :: custom) ,
67+ } )
68+ . collect :: < Result < Vec < _ > , _ > > ( )
69+ . map ( |values| values. into_iter ( ) . unique ( ) . collect ( ) )
4670}
4771
4872/// Deserialize JSON single value or single element array into single value.
@@ -140,6 +164,11 @@ where
140164
141165#[ cfg( test) ]
142166mod tests {
167+ use super :: deserialize_one_or_many;
168+ use activitystreams_kinds:: public;
169+ use anyhow:: Result ;
170+ use serde:: Deserialize ;
171+
143172 #[ test]
144173 fn deserialize_one_multiple_values ( ) {
145174 use crate :: protocol:: helpers:: deserialize_one;
@@ -155,4 +184,70 @@ mod tests {
155184 ) ;
156185 assert ! ( note. is_err( ) ) ;
157186 }
187+
188+ #[ test]
189+ fn deserialize_one_or_many_single_public_aliases ( ) -> Result < ( ) > {
190+ use url:: Url ;
191+
192+ #[ derive( Deserialize ) ]
193+ struct Note {
194+ #[ serde( deserialize_with = "deserialize_one_or_many" ) ]
195+ to : Vec < Url > ,
196+ }
197+
198+ for alias in [ "Public" , "as:Public" ] {
199+ let note = serde_json:: from_str :: < Note > ( & format ! ( r#"{{"to": "{alias}"}}"# ) ) ?;
200+ assert_eq ! ( note. to, vec![ public( ) ] ) ;
201+ }
202+
203+ Ok ( ( ) )
204+ }
205+
206+ #[ test]
207+ fn deserialize_one_or_many_array ( ) -> Result < ( ) > {
208+ use url:: Url ;
209+
210+ #[ derive( Deserialize ) ]
211+ struct Note {
212+ #[ serde( deserialize_with = "deserialize_one_or_many" ) ]
213+ to : Vec < Url > ,
214+ }
215+
216+ let note = serde_json:: from_str :: < Note > (
217+ r#"{
218+ "to": [
219+ "https://example.com/c/main",
220+ "Public",
221+ "as:Public",
222+ "https://www.w3.org/ns/activitystreams#Public"
223+ ]
224+ }"# ,
225+ ) ?;
226+
227+ assert_eq ! (
228+ note. to,
229+ vec![ Url :: parse( "https://example.com/c/main" ) ?, public( ) , ]
230+ ) ;
231+
232+ Ok ( ( ) )
233+ }
234+
235+ #[ test]
236+ fn deserialize_one_or_many_leaves_other_strings_unchanged ( ) -> Result < ( ) > {
237+ use url:: Url ;
238+
239+ #[ derive( Deserialize ) ]
240+ struct Note {
241+ #[ serde( deserialize_with = "deserialize_one_or_many" ) ]
242+ to : Vec < Url > ,
243+ content : String ,
244+ }
245+
246+ let note = serde_json:: from_str :: < Note > ( r#"{"to": "Public", "content": "Public"}"# ) ?;
247+
248+ assert_eq ! ( note. to, vec![ public( ) ] ) ;
249+ assert_eq ! ( note. content, "Public" ) ;
250+
251+ Ok ( ( ) )
252+ }
158253}
0 commit comments