ruma_client_api/push/set_pusher/
set_pusher_serde.rs

1use js_option::JsOption;
2use ruma_common::serde::from_raw_json_value;
3use serde::{Deserialize, Serialize, de, ser::SerializeStruct};
4use serde_json::value::RawValue as RawJsonValue;
5
6use super::v3::{PusherAction, PusherPostData};
7
8#[derive(Debug, Deserialize)]
9struct PusherPostDataDeHelper {
10    #[serde(default)]
11    append: bool,
12}
13
14impl<'de> Deserialize<'de> for PusherPostData {
15    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
16    where
17        D: de::Deserializer<'de>,
18    {
19        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
20
21        let PusherPostDataDeHelper { append } = from_raw_json_value(&json)?;
22        let pusher = from_raw_json_value(&json)?;
23
24        Ok(Self { pusher, append })
25    }
26}
27
28impl Serialize for PusherAction {
29    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30    where
31        S: serde::Serializer,
32    {
33        match self {
34            PusherAction::Post(pusher) => pusher.serialize(serializer),
35            PusherAction::Delete(ids) => {
36                let mut st = serializer.serialize_struct("PusherAction", 3)?;
37                st.serialize_field("pushkey", &ids.pushkey)?;
38                st.serialize_field("app_id", &ids.app_id)?;
39                st.serialize_field("kind", &None::<&str>)?;
40                st.end()
41            }
42        }
43    }
44}
45
46#[derive(Debug, Deserialize)]
47struct PusherActionDeHelper {
48    kind: JsOption<String>,
49}
50
51impl<'de> Deserialize<'de> for PusherAction {
52    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53    where
54        D: de::Deserializer<'de>,
55    {
56        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
57        let PusherActionDeHelper { kind } = from_raw_json_value(&json)?;
58
59        match kind {
60            JsOption::Some(_) => Ok(Self::Post(from_raw_json_value(&json)?)),
61            JsOption::Null => Ok(Self::Delete(from_raw_json_value(&json)?)),
62            // This is unreachable because we don't use `#[serde(default)]` on the field.
63            JsOption::Undefined => Err(de::Error::missing_field("kind")),
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use assert_matches2::assert_matches;
71    use ruma_common::canonical_json::assert_to_canonical_json_eq;
72    use serde_json::{from_value as from_json_value, json};
73
74    use super::PusherAction;
75    use crate::push::{
76        EmailPusherData, Pusher, PusherIds, PusherKind, set_pusher::v3::PusherPostData,
77    };
78
79    #[test]
80    fn serialize_post() {
81        let action = PusherAction::Post(PusherPostData {
82            pusher: Pusher {
83                ids: PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned()),
84                kind: PusherKind::Email(EmailPusherData::new()),
85                app_display_name: "My Matrix App".to_owned(),
86                device_display_name: "My Phone".to_owned(),
87                profile_tag: None,
88                lang: "en".to_owned(),
89            },
90            append: false,
91        });
92
93        assert_to_canonical_json_eq!(
94            action,
95            json!({
96                "pushkey": "abcdef",
97                "app_id": "my.matrix.app",
98                "kind": "email",
99                "app_display_name": "My Matrix App",
100                "device_display_name": "My Phone",
101                "lang": "en",
102                "data": {}
103            })
104        );
105    }
106
107    #[test]
108    fn serialize_delete() {
109        let action =
110            PusherAction::Delete(PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned()));
111
112        assert_to_canonical_json_eq!(
113            action,
114            json!({
115                "pushkey": "abcdef",
116                "app_id": "my.matrix.app",
117                "kind": null,
118            })
119        );
120    }
121
122    #[test]
123    fn deserialize_post() {
124        let json = json!({
125            "pushkey": "abcdef",
126            "app_id": "my.matrix.app",
127            "kind": "email",
128            "app_display_name": "My Matrix App",
129            "device_display_name": "My Phone",
130            "lang": "en",
131            "data": {}
132        });
133
134        assert_matches!(from_json_value(json).unwrap(), PusherAction::Post(post_data));
135        assert!(!post_data.append);
136
137        let pusher = post_data.pusher;
138        assert_eq!(pusher.ids.pushkey, "abcdef");
139        assert_eq!(pusher.ids.app_id, "my.matrix.app");
140        assert_matches!(pusher.kind, PusherKind::Email(_));
141        assert_eq!(pusher.app_display_name, "My Matrix App");
142        assert_eq!(pusher.device_display_name, "My Phone");
143        assert_eq!(pusher.profile_tag, None);
144        assert_eq!(pusher.lang, "en");
145    }
146
147    #[test]
148    fn deserialize_delete() {
149        let json = json!({
150            "pushkey": "abcdef",
151            "app_id": "my.matrix.app",
152            "kind": null,
153        });
154
155        assert_matches!(from_json_value(json).unwrap(), PusherAction::Delete(ids));
156        assert_eq!(ids.pushkey, "abcdef");
157        assert_eq!(ids.app_id, "my.matrix.app");
158    }
159}