Skip to main content

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