ruma_client_api/push/set_pusher/
set_pusher_serde.rs

1use js_option::JsOption;
2use ruma_common::serde::from_raw_json_value;
3use serde::{de, ser::SerializeStruct, Deserialize, Serialize};
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 serde_json::{from_value as from_json_value, json, to_value as to_json_value};
72
73    use super::PusherAction;
74    use crate::push::{
75        set_pusher::v3::PusherPostData, EmailPusherData, Pusher, PusherIds, PusherKind,
76    };
77
78    #[test]
79    fn serialize_post() {
80        let action = PusherAction::Post(PusherPostData {
81            pusher: Pusher {
82                ids: PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned()),
83                kind: PusherKind::Email(EmailPusherData::new()),
84                app_display_name: "My Matrix App".to_owned(),
85                device_display_name: "My Phone".to_owned(),
86                profile_tag: None,
87                lang: "en".to_owned(),
88            },
89            append: false,
90        });
91
92        assert_eq!(
93            to_json_value(action).unwrap(),
94            json!({
95                "pushkey": "abcdef",
96                "app_id": "my.matrix.app",
97                "kind": "email",
98                "app_display_name": "My Matrix App",
99                "device_display_name": "My Phone",
100                "lang": "en",
101                "data": {}
102            })
103        );
104    }
105
106    #[test]
107    fn serialize_delete() {
108        let action =
109            PusherAction::Delete(PusherIds::new("abcdef".to_owned(), "my.matrix.app".to_owned()));
110
111        assert_eq!(
112            to_json_value(action).unwrap(),
113            json!({
114                "pushkey": "abcdef",
115                "app_id": "my.matrix.app",
116                "kind": null,
117            })
118        );
119    }
120
121    #[test]
122    fn deserialize_post() {
123        let json = json!({
124            "pushkey": "abcdef",
125            "app_id": "my.matrix.app",
126            "kind": "email",
127            "app_display_name": "My Matrix App",
128            "device_display_name": "My Phone",
129            "lang": "en",
130            "data": {}
131        });
132
133        assert_matches!(from_json_value(json).unwrap(), PusherAction::Post(post_data));
134        assert!(!post_data.append);
135
136        let pusher = post_data.pusher;
137        assert_eq!(pusher.ids.pushkey, "abcdef");
138        assert_eq!(pusher.ids.app_id, "my.matrix.app");
139        assert_matches!(pusher.kind, PusherKind::Email(_));
140        assert_eq!(pusher.app_display_name, "My Matrix App");
141        assert_eq!(pusher.device_display_name, "My Phone");
142        assert_eq!(pusher.profile_tag, None);
143        assert_eq!(pusher.lang, "en");
144    }
145
146    #[test]
147    fn deserialize_delete() {
148        let json = json!({
149            "pushkey": "abcdef",
150            "app_id": "my.matrix.app",
151            "kind": null,
152        });
153
154        assert_matches!(from_json_value(json).unwrap(), PusherAction::Delete(ids));
155        assert_eq!(ids.pushkey, "abcdef");
156        assert_eq!(ids.app_id, "my.matrix.app");
157    }
158}