xmpp-parsers: Use xso for pubsub owner
Also merge its direct children into its enum fields.
This commit is contained in:
parent
26dd6a2a29
commit
5cbe5936a6
3 changed files with 102 additions and 154 deletions
|
|
@ -62,6 +62,8 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
|
||||||
having been exchanged, and the stream_id is now a String instead of
|
having been exchanged, and the stream_id is now a String instead of
|
||||||
&str.
|
&str.
|
||||||
- Add a lang property in Presence, to avoid parser errors.
|
- Add a lang property in Presence, to avoid parser errors.
|
||||||
|
- pubsub::Owner is now a wrapper for the pubsub::owner::Paylolad enum,
|
||||||
|
and all its direct children have been merged into this enum (!532)
|
||||||
* New parsers/serialisers:
|
* New parsers/serialisers:
|
||||||
- Stream Features (RFC 6120) (!400)
|
- Stream Features (RFC 6120) (!400)
|
||||||
- Spam Reporting (XEP-0377) (!506)
|
- Spam Reporting (XEP-0377) (!506)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub mod owner;
|
||||||
pub mod pubsub;
|
pub mod pubsub;
|
||||||
|
|
||||||
pub use self::event::Event;
|
pub use self::event::Event;
|
||||||
pub use self::owner::PubSubOwner;
|
pub use self::owner::Owner;
|
||||||
pub use self::pubsub::PubSub;
|
pub use self::pubsub::PubSub;
|
||||||
|
|
||||||
use minidom::Element;
|
use minidom::Element;
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,6 @@ use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
|
||||||
use crate::ns;
|
use crate::ns;
|
||||||
use crate::pubsub::{AffiliationAttribute, NodeName, Subscription};
|
use crate::pubsub::{AffiliationAttribute, NodeName, Subscription};
|
||||||
use jid::Jid;
|
use jid::Jid;
|
||||||
use minidom::Element;
|
|
||||||
use xso::error::{Error, FromElementError};
|
|
||||||
|
|
||||||
/// A list of affiliations you have on a service, or on a node.
|
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "affiliations")]
|
|
||||||
pub struct Affiliations {
|
|
||||||
/// The node name this request pertains to.
|
|
||||||
#[xml(attribute)]
|
|
||||||
pub node: NodeName,
|
|
||||||
|
|
||||||
/// The actual list of affiliation elements.
|
|
||||||
#[xml(child(n = ..))]
|
|
||||||
pub affiliations: Vec<Affiliation>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An affiliation element.
|
/// An affiliation element.
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||||
|
|
@ -41,72 +26,6 @@ pub struct Affiliation {
|
||||||
affiliation: AffiliationAttribute,
|
affiliation: AffiliationAttribute,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request to configure a node.
|
|
||||||
#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "configure")]
|
|
||||||
pub struct Configure {
|
|
||||||
/// The node to be configured.
|
|
||||||
#[xml(attribute(default))]
|
|
||||||
pub node: Option<NodeName>,
|
|
||||||
|
|
||||||
/// The form to configure it.
|
|
||||||
#[xml(child(default))]
|
|
||||||
pub form: Option<DataForm>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request to retrieve default configuration.
|
|
||||||
#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "default")]
|
|
||||||
pub struct Default {
|
|
||||||
/// The form to configure it.
|
|
||||||
#[xml(child(default))]
|
|
||||||
pub form: Option<DataForm>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request to delete a node.
|
|
||||||
#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "delete")]
|
|
||||||
pub struct Delete {
|
|
||||||
/// The node to be deleted.
|
|
||||||
#[xml(attribute)]
|
|
||||||
pub node: NodeName,
|
|
||||||
|
|
||||||
/// Redirection to replace the deleted node.
|
|
||||||
#[xml(child(default))]
|
|
||||||
pub redirect: Option<Redirect>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A redirect element.
|
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "redirect")]
|
|
||||||
pub struct Redirect {
|
|
||||||
/// The node this node will be redirected to.
|
|
||||||
#[xml(attribute)]
|
|
||||||
pub uri: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request to clear a node.
|
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "purge")]
|
|
||||||
pub struct Purge {
|
|
||||||
/// The node to be cleared.
|
|
||||||
#[xml(attribute)]
|
|
||||||
pub node: NodeName,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A request for current subscriptions.
|
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "subscriptions")]
|
|
||||||
pub struct Subscriptions {
|
|
||||||
/// The node to query.
|
|
||||||
#[xml(attribute)]
|
|
||||||
pub node: NodeName,
|
|
||||||
|
|
||||||
/// The list of subscription elements returned.
|
|
||||||
#[xml(child(n = ..))]
|
|
||||||
pub subscriptions: Vec<SubscriptionElem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A subscription element, describing the state of a subscription.
|
/// A subscription element, describing the state of a subscription.
|
||||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "subscription")]
|
#[xml(namespace = ns::PUBSUB_OWNER, name = "subscription")]
|
||||||
|
|
@ -124,68 +43,89 @@ pub struct SubscriptionElem {
|
||||||
pub subid: Option<String>,
|
pub subid: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main payload used to communicate with a PubSubOwner service.
|
/// Represents an owner request to a PubSub service.
|
||||||
|
#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
|
||||||
|
#[xml(namespace = ns::PUBSUB_OWNER, name = "pubsub")]
|
||||||
|
pub struct Owner {
|
||||||
|
/// The inner child of this request.
|
||||||
|
#[xml(child)]
|
||||||
|
pub payload: Payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Differentiate each payload per type someday, to simplify our types.
|
||||||
|
impl IqGetPayload for Owner {}
|
||||||
|
impl IqSetPayload for Owner {}
|
||||||
|
impl IqResultPayload for Owner {}
|
||||||
|
|
||||||
|
/// Main payload used to communicate with a PubSub service.
|
||||||
///
|
///
|
||||||
/// `<pubsub xmlns="http://jabber.org/protocol/pubsub#owner"/>`
|
/// `<pubsub xmlns="http://jabber.org/protocol/pubsub#owner"/>`
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
|
||||||
pub enum PubSubOwner {
|
#[xml(namespace = ns::PUBSUB_OWNER, exhaustive)]
|
||||||
|
pub enum Payload {
|
||||||
/// Manage the affiliations of a node.
|
/// Manage the affiliations of a node.
|
||||||
Affiliations(Affiliations),
|
#[xml(name = "affiliations")]
|
||||||
/// Request to configure a node, with optional suggested name and suggested configuration.
|
Affiliations {
|
||||||
Configure(Configure),
|
/// The node name this request pertains to.
|
||||||
|
#[xml(attribute)]
|
||||||
|
node: NodeName,
|
||||||
|
|
||||||
|
/// The actual list of affiliation elements.
|
||||||
|
#[xml(child(n = ..))]
|
||||||
|
affiliations: Vec<Affiliation>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Request to configure a node.
|
||||||
|
#[xml(name = "configure")]
|
||||||
|
Configure {
|
||||||
|
/// The node to be configured.
|
||||||
|
#[xml(attribute(default))]
|
||||||
|
node: Option<NodeName>,
|
||||||
|
|
||||||
|
/// The form to configure it.
|
||||||
|
#[xml(child(default))]
|
||||||
|
form: Option<DataForm>,
|
||||||
|
},
|
||||||
|
|
||||||
/// Request the default node configuration.
|
/// Request the default node configuration.
|
||||||
Default(Default),
|
#[xml(name = "default")]
|
||||||
|
Default {
|
||||||
|
/// The form to configure it.
|
||||||
|
#[xml(child(default))]
|
||||||
|
form: Option<DataForm>,
|
||||||
|
},
|
||||||
|
|
||||||
/// Delete a node.
|
/// Delete a node.
|
||||||
Delete(Delete),
|
#[xml(name = "delete")]
|
||||||
|
Delete {
|
||||||
|
/// The node to be deleted.
|
||||||
|
#[xml(attribute)]
|
||||||
|
node: NodeName,
|
||||||
|
|
||||||
|
/// Redirection to replace the deleted node.
|
||||||
|
#[xml(extract(default, name = "redirect", fields(attribute(name = "uri", type_ = String))))]
|
||||||
|
redirect_uri: Option<String>,
|
||||||
|
},
|
||||||
|
|
||||||
/// Purge all items from node.
|
/// Purge all items from node.
|
||||||
Purge(Purge),
|
#[xml(name = "purge")]
|
||||||
/// Request subscriptions of a node.
|
Purge {
|
||||||
Subscriptions(Subscriptions),
|
/// The node to be cleared.
|
||||||
}
|
#[xml(attribute)]
|
||||||
|
node: NodeName,
|
||||||
|
},
|
||||||
|
|
||||||
impl IqGetPayload for PubSubOwner {}
|
/// Request the current subscriptions to a node.
|
||||||
impl IqSetPayload for PubSubOwner {}
|
#[xml(name = "subscriptions")]
|
||||||
impl IqResultPayload for PubSubOwner {}
|
Subscriptions {
|
||||||
|
/// The node to query.
|
||||||
|
#[xml(attribute)]
|
||||||
|
node: NodeName,
|
||||||
|
|
||||||
impl TryFrom<Element> for PubSubOwner {
|
/// The list of subscription elements returned.
|
||||||
type Error = FromElementError;
|
#[xml(child(n = ..))]
|
||||||
|
subscriptions: Vec<SubscriptionElem>,
|
||||||
fn try_from(elem: Element) -> Result<PubSubOwner, FromElementError> {
|
},
|
||||||
check_self!(elem, "pubsub", PUBSUB_OWNER);
|
|
||||||
check_no_attributes!(elem, "pubsub");
|
|
||||||
|
|
||||||
let mut payload = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("configure", ns::PUBSUB_OWNER) {
|
|
||||||
if payload.is_some() {
|
|
||||||
return Err(Error::Other(
|
|
||||||
"Payload is already defined in pubsub owner element.",
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
let configure = Configure::try_from(child.clone())?;
|
|
||||||
payload = Some(PubSubOwner::Configure(configure));
|
|
||||||
} else {
|
|
||||||
return Err(Error::Other("Unknown child in pubsub element.").into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
payload.ok_or(Error::Other("No payload in pubsub element.").into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PubSubOwner> for Element {
|
|
||||||
fn from(pubsub: PubSubOwner) -> Element {
|
|
||||||
Element::builder("pubsub", ns::PUBSUB_OWNER)
|
|
||||||
.append_all(match pubsub {
|
|
||||||
PubSubOwner::Affiliations(affiliations) => vec![Element::from(affiliations)],
|
|
||||||
PubSubOwner::Configure(configure) => vec![Element::from(configure)],
|
|
||||||
PubSubOwner::Default(default) => vec![Element::from(default)],
|
|
||||||
PubSubOwner::Delete(delete) => vec![Element::from(delete)],
|
|
||||||
PubSubOwner::Purge(purge) => vec![Element::from(purge)],
|
|
||||||
PubSubOwner::Subscriptions(subscriptions) => vec![Element::from(subscriptions)],
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -194,6 +134,7 @@ mod tests {
|
||||||
use crate::data_forms::{DataFormType, Field, FieldType};
|
use crate::data_forms::{DataFormType, Field, FieldType};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use jid::BareJid;
|
use jid::BareJid;
|
||||||
|
use minidom::Element;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn affiliations() {
|
fn affiliations() {
|
||||||
|
|
@ -202,7 +143,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Affiliations(Affiliations {
|
let payload = Payload::Affiliations {
|
||||||
node: NodeName(String::from("foo")),
|
node: NodeName(String::from("foo")),
|
||||||
affiliations: vec![
|
affiliations: vec![
|
||||||
Affiliation {
|
Affiliation {
|
||||||
|
|
@ -214,7 +155,8 @@ mod tests {
|
||||||
affiliation: AffiliationAttribute::Outcast,
|
affiliation: AffiliationAttribute::Outcast,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
let pubsub = Owner { payload };
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
@ -227,7 +169,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Configure(Configure {
|
let payload = Payload::Configure {
|
||||||
node: Some(NodeName(String::from("foo"))),
|
node: Some(NodeName(String::from("foo"))),
|
||||||
form: Some(DataForm::new(
|
form: Some(DataForm::new(
|
||||||
DataFormType::Submit,
|
DataFormType::Submit,
|
||||||
|
|
@ -235,7 +177,8 @@ mod tests {
|
||||||
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
||||||
.with_value("whitelist")],
|
.with_value("whitelist")],
|
||||||
)),
|
)),
|
||||||
});
|
};
|
||||||
|
let pubsub = Owner { payload };
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
@ -251,10 +194,11 @@ mod tests {
|
||||||
|
|
||||||
let form = DataForm::try_from(elem).unwrap();
|
let form = DataForm::try_from(elem).unwrap();
|
||||||
|
|
||||||
let configure = PubSubOwner::Configure(Configure {
|
let payload = Payload::Configure {
|
||||||
node: Some(NodeName(String::from("foo"))),
|
node: Some(NodeName(String::from("foo"))),
|
||||||
form: Some(form),
|
form: Some(form),
|
||||||
});
|
};
|
||||||
|
let configure = Owner { payload };
|
||||||
let serialized: Element = configure.into();
|
let serialized: Element = configure.into();
|
||||||
assert_eq!(serialized, reference);
|
assert_eq!(serialized, reference);
|
||||||
}
|
}
|
||||||
|
|
@ -266,14 +210,15 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Default(Default {
|
let payload = Payload::Default {
|
||||||
form: Some(DataForm::new(
|
form: Some(DataForm::new(
|
||||||
DataFormType::Submit,
|
DataFormType::Submit,
|
||||||
ns::PUBSUB_CONFIGURE,
|
ns::PUBSUB_CONFIGURE,
|
||||||
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
||||||
.with_value("whitelist")],
|
.with_value("whitelist")],
|
||||||
)),
|
)),
|
||||||
});
|
};
|
||||||
|
let pubsub = Owner { payload };
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
@ -286,12 +231,11 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Delete(Delete {
|
let payload = Payload::Delete {
|
||||||
node: NodeName(String::from("foo")),
|
node: NodeName(String::from("foo")),
|
||||||
redirect: Some(Redirect {
|
redirect_uri: Some(String::from("xmpp:hamlet@denmark.lit?;node=blog")),
|
||||||
uri: String::from("xmpp:hamlet@denmark.lit?;node=blog"),
|
};
|
||||||
}),
|
let pubsub = Owner { payload };
|
||||||
});
|
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
@ -304,9 +248,10 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Purge(Purge {
|
let payload = Payload::Purge {
|
||||||
node: NodeName(String::from("foo")),
|
node: NodeName(String::from("foo")),
|
||||||
});
|
};
|
||||||
|
let pubsub = Owner { payload };
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
@ -319,7 +264,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let elem1 = elem.clone();
|
let elem1 = elem.clone();
|
||||||
|
|
||||||
let pubsub = PubSubOwner::Subscriptions(Subscriptions {
|
let payload = Payload::Subscriptions {
|
||||||
node: NodeName(String::from("foo")),
|
node: NodeName(String::from("foo")),
|
||||||
subscriptions: vec![
|
subscriptions: vec![
|
||||||
SubscriptionElem {
|
SubscriptionElem {
|
||||||
|
|
@ -343,7 +288,8 @@ mod tests {
|
||||||
subid: Some(String::from("004-yyy")),
|
subid: Some(String::from("004-yyy")),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
let pubsub = Owner { payload };
|
||||||
|
|
||||||
let elem2 = Element::from(pubsub);
|
let elem2 = Element::from(pubsub);
|
||||||
assert_eq!(elem1, elem2);
|
assert_eq!(elem1, elem2);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue