1use xso::{AsXml, FromXml};
9
10use crate::data_forms::DataForm;
11use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
12use crate::ns;
13use crate::pubsub::{AffiliationAttribute, NodeName, Subscription};
14use jid::Jid;
15
16#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
18#[xml(namespace = ns::PUBSUB_OWNER, name = "affiliation")]
19pub struct Affiliation {
20 #[xml(attribute)]
22 jid: Jid,
23
24 #[xml(attribute)]
26 affiliation: AffiliationAttribute,
27}
28
29#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
31#[xml(namespace = ns::PUBSUB_OWNER, name = "subscription")]
32pub struct SubscriptionElem {
33 #[xml(attribute)]
35 pub jid: Jid,
36
37 #[xml(attribute)]
39 pub subscription: Subscription,
40
41 #[xml(attribute(default))]
43 pub subid: Option<String>,
44}
45
46#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
48#[xml(namespace = ns::PUBSUB_OWNER, name = "pubsub")]
49pub struct Owner {
50 #[xml(child)]
52 pub payload: Payload,
53}
54
55impl IqGetPayload for Owner {}
57impl IqSetPayload for Owner {}
58impl IqResultPayload for Owner {}
59
60#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
64#[xml(namespace = ns::PUBSUB_OWNER, exhaustive)]
65pub enum Payload {
66 #[xml(name = "affiliations")]
68 Affiliations {
69 #[xml(attribute)]
71 node: NodeName,
72
73 #[xml(child(n = ..))]
75 affiliations: Vec<Affiliation>,
76 },
77
78 #[xml(name = "configure")]
80 Configure {
81 #[xml(attribute(default))]
83 node: Option<NodeName>,
84
85 #[xml(child(default))]
87 form: Option<DataForm>,
88 },
89
90 #[xml(name = "default")]
92 Default {
93 #[xml(child(default))]
95 form: Option<DataForm>,
96 },
97
98 #[xml(name = "delete")]
100 Delete {
101 #[xml(attribute)]
103 node: NodeName,
104
105 #[xml(extract(default, name = "redirect", fields(attribute(name = "uri", type_ = String))))]
107 redirect_uri: Option<String>,
108 },
109
110 #[xml(name = "purge")]
112 Purge {
113 #[xml(attribute)]
115 node: NodeName,
116 },
117
118 #[xml(name = "subscriptions")]
120 Subscriptions {
121 #[xml(attribute)]
123 node: NodeName,
124
125 #[xml(child(n = ..))]
127 subscriptions: Vec<SubscriptionElem>,
128 },
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::data_forms::{DataFormType, Field, FieldType};
135 use core::str::FromStr;
136 use jid::BareJid;
137 use minidom::Element;
138
139 #[test]
140 fn affiliations() {
141 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><affiliations node='foo'><affiliation jid='hamlet@denmark.lit' affiliation='owner'/><affiliation jid='polonius@denmark.lit' affiliation='outcast'/></affiliations></pubsub>"
142 .parse()
143 .unwrap();
144 let elem1 = elem.clone();
145
146 let payload = Payload::Affiliations {
147 node: NodeName(String::from("foo")),
148 affiliations: vec![
149 Affiliation {
150 jid: Jid::from(BareJid::from_str("hamlet@denmark.lit").unwrap()),
151 affiliation: AffiliationAttribute::Owner,
152 },
153 Affiliation {
154 jid: Jid::from(BareJid::from_str("polonius@denmark.lit").unwrap()),
155 affiliation: AffiliationAttribute::Outcast,
156 },
157 ],
158 };
159 let pubsub = Owner { payload };
160
161 let elem2 = Element::from(pubsub);
162 assert_eq!(elem1, elem2);
163 }
164
165 #[test]
166 fn configure() {
167 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><configure node='foo'><x xmlns='jabber:x:data' type='submit'><field var='FORM_TYPE' type='hidden'><value>http://jabber.org/protocol/pubsub#node_config</value></field><field var='pubsub#access_model' type='list-single'><value>whitelist</value></field></x></configure></pubsub>"
168 .parse()
169 .unwrap();
170 let elem1 = elem.clone();
171
172 let payload = Payload::Configure {
173 node: Some(NodeName(String::from("foo"))),
174 form: Some(DataForm::new(
175 DataFormType::Submit,
176 ns::PUBSUB_CONFIGURE,
177 vec![Field::new("pubsub#access_model", FieldType::ListSingle)
178 .with_value("whitelist")],
179 )),
180 };
181 let pubsub = Owner { payload };
182
183 let elem2 = Element::from(pubsub);
184 assert_eq!(elem1, elem2);
185 }
186
187 #[test]
188 fn test_serialize_configure() {
189 let reference: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><configure node='foo'><x xmlns='jabber:x:data' type='submit'/></configure></pubsub>"
190 .parse()
191 .unwrap();
192
193 let elem: Element = "<x xmlns='jabber:x:data' type='submit'/>".parse().unwrap();
194
195 let form = DataForm::try_from(elem).unwrap();
196
197 let payload = Payload::Configure {
198 node: Some(NodeName(String::from("foo"))),
199 form: Some(form),
200 };
201 let configure = Owner { payload };
202 let serialized: Element = configure.into();
203 assert_eq!(serialized, reference);
204 }
205
206 #[test]
207 fn default() {
208 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><default><x xmlns='jabber:x:data' type='submit'><field var='FORM_TYPE' type='hidden'><value>http://jabber.org/protocol/pubsub#node_config</value></field><field var='pubsub#access_model' type='list-single'><value>whitelist</value></field></x></default></pubsub>"
209 .parse()
210 .unwrap();
211 let elem1 = elem.clone();
212
213 let payload = Payload::Default {
214 form: Some(DataForm::new(
215 DataFormType::Submit,
216 ns::PUBSUB_CONFIGURE,
217 vec![Field::new("pubsub#access_model", FieldType::ListSingle)
218 .with_value("whitelist")],
219 )),
220 };
221 let pubsub = Owner { payload };
222
223 let elem2 = Element::from(pubsub);
224 assert_eq!(elem1, elem2);
225 }
226
227 #[test]
228 fn delete() {
229 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><delete node='foo'><redirect uri='xmpp:hamlet@denmark.lit?;node=blog'/></delete></pubsub>"
230 .parse()
231 .unwrap();
232 let elem1 = elem.clone();
233
234 let payload = Payload::Delete {
235 node: NodeName(String::from("foo")),
236 redirect_uri: Some(String::from("xmpp:hamlet@denmark.lit?;node=blog")),
237 };
238 let pubsub = Owner { payload };
239
240 let elem2 = Element::from(pubsub);
241 assert_eq!(elem1, elem2);
242 }
243
244 #[test]
245 fn purge() {
246 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><purge node='foo'></purge></pubsub>"
247 .parse()
248 .unwrap();
249 let elem1 = elem.clone();
250
251 let payload = Payload::Purge {
252 node: NodeName(String::from("foo")),
253 };
254 let pubsub = Owner { payload };
255
256 let elem2 = Element::from(pubsub);
257 assert_eq!(elem1, elem2);
258 }
259
260 #[test]
261 fn subscriptions() {
262 let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><subscriptions node='foo'><subscription jid='hamlet@denmark.lit' subscription='subscribed'/><subscription jid='polonius@denmark.lit' subscription='unconfigured'/><subscription jid='bernardo@denmark.lit' subscription='subscribed' subid='123-abc'/><subscription jid='bernardo@denmark.lit' subscription='subscribed' subid='004-yyy'/></subscriptions></pubsub>"
263 .parse()
264 .unwrap();
265 let elem1 = elem.clone();
266
267 let payload = Payload::Subscriptions {
268 node: NodeName(String::from("foo")),
269 subscriptions: vec![
270 SubscriptionElem {
271 jid: Jid::from(BareJid::from_str("hamlet@denmark.lit").unwrap()),
272 subscription: Subscription::Subscribed,
273 subid: None,
274 },
275 SubscriptionElem {
276 jid: Jid::from(BareJid::from_str("polonius@denmark.lit").unwrap()),
277 subscription: Subscription::Unconfigured,
278 subid: None,
279 },
280 SubscriptionElem {
281 jid: Jid::from(BareJid::from_str("bernardo@denmark.lit").unwrap()),
282 subscription: Subscription::Subscribed,
283 subid: Some(String::from("123-abc")),
284 },
285 SubscriptionElem {
286 jid: Jid::from(BareJid::from_str("bernardo@denmark.lit").unwrap()),
287 subscription: Subscription::Subscribed,
288 subid: Some(String::from("004-yyy")),
289 },
290 ],
291 };
292 let pubsub = Owner { payload };
293
294 let elem2 = Element::from(pubsub);
295 assert_eq!(elem1, elem2);
296 }
297}