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
|
||||
&str.
|
||||
- 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:
|
||||
- Stream Features (RFC 6120) (!400)
|
||||
- Spam Reporting (XEP-0377) (!506)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub mod owner;
|
|||
pub mod pubsub;
|
||||
|
||||
pub use self::event::Event;
|
||||
pub use self::owner::PubSubOwner;
|
||||
pub use self::owner::Owner;
|
||||
pub use self::pubsub::PubSub;
|
||||
|
||||
use minidom::Element;
|
||||
|
|
|
|||
|
|
@ -12,21 +12,6 @@ use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
|
|||
use crate::ns;
|
||||
use crate::pubsub::{AffiliationAttribute, NodeName, Subscription};
|
||||
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.
|
||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||
|
|
@ -41,72 +26,6 @@ pub struct Affiliation {
|
|||
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.
|
||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||
#[xml(namespace = ns::PUBSUB_OWNER, name = "subscription")]
|
||||
|
|
@ -124,68 +43,89 @@ pub struct SubscriptionElem {
|
|||
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"/>`
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PubSubOwner {
|
||||
#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
|
||||
#[xml(namespace = ns::PUBSUB_OWNER, exhaustive)]
|
||||
pub enum Payload {
|
||||
/// Manage the affiliations of a node.
|
||||
Affiliations(Affiliations),
|
||||
/// Request to configure a node, with optional suggested name and suggested configuration.
|
||||
Configure(Configure),
|
||||
#[xml(name = "affiliations")]
|
||||
Affiliations {
|
||||
/// 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.
|
||||
Default(Default),
|
||||
#[xml(name = "default")]
|
||||
Default {
|
||||
/// The form to configure it.
|
||||
#[xml(child(default))]
|
||||
form: Option<DataForm>,
|
||||
},
|
||||
|
||||
/// 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(Purge),
|
||||
/// Request subscriptions of a node.
|
||||
Subscriptions(Subscriptions),
|
||||
}
|
||||
#[xml(name = "purge")]
|
||||
Purge {
|
||||
/// The node to be cleared.
|
||||
#[xml(attribute)]
|
||||
node: NodeName,
|
||||
},
|
||||
|
||||
impl IqGetPayload for PubSubOwner {}
|
||||
impl IqSetPayload for PubSubOwner {}
|
||||
impl IqResultPayload for PubSubOwner {}
|
||||
/// Request the current subscriptions to a node.
|
||||
#[xml(name = "subscriptions")]
|
||||
Subscriptions {
|
||||
/// The node to query.
|
||||
#[xml(attribute)]
|
||||
node: NodeName,
|
||||
|
||||
impl TryFrom<Element> for PubSubOwner {
|
||||
type Error = FromElementError;
|
||||
|
||||
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()
|
||||
}
|
||||
/// The list of subscription elements returned.
|
||||
#[xml(child(n = ..))]
|
||||
subscriptions: Vec<SubscriptionElem>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -194,6 +134,7 @@ mod tests {
|
|||
use crate::data_forms::{DataFormType, Field, FieldType};
|
||||
use core::str::FromStr;
|
||||
use jid::BareJid;
|
||||
use minidom::Element;
|
||||
|
||||
#[test]
|
||||
fn affiliations() {
|
||||
|
|
@ -202,7 +143,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Affiliations(Affiliations {
|
||||
let payload = Payload::Affiliations {
|
||||
node: NodeName(String::from("foo")),
|
||||
affiliations: vec![
|
||||
Affiliation {
|
||||
|
|
@ -214,7 +155,8 @@ mod tests {
|
|||
affiliation: AffiliationAttribute::Outcast,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
@ -227,7 +169,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Configure(Configure {
|
||||
let payload = Payload::Configure {
|
||||
node: Some(NodeName(String::from("foo"))),
|
||||
form: Some(DataForm::new(
|
||||
DataFormType::Submit,
|
||||
|
|
@ -235,7 +177,8 @@ mod tests {
|
|||
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
||||
.with_value("whitelist")],
|
||||
)),
|
||||
});
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
@ -251,10 +194,11 @@ mod tests {
|
|||
|
||||
let form = DataForm::try_from(elem).unwrap();
|
||||
|
||||
let configure = PubSubOwner::Configure(Configure {
|
||||
let payload = Payload::Configure {
|
||||
node: Some(NodeName(String::from("foo"))),
|
||||
form: Some(form),
|
||||
});
|
||||
};
|
||||
let configure = Owner { payload };
|
||||
let serialized: Element = configure.into();
|
||||
assert_eq!(serialized, reference);
|
||||
}
|
||||
|
|
@ -266,14 +210,15 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Default(Default {
|
||||
let payload = Payload::Default {
|
||||
form: Some(DataForm::new(
|
||||
DataFormType::Submit,
|
||||
ns::PUBSUB_CONFIGURE,
|
||||
vec![Field::new("pubsub#access_model", FieldType::ListSingle)
|
||||
.with_value("whitelist")],
|
||||
)),
|
||||
});
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
@ -286,12 +231,11 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Delete(Delete {
|
||||
let payload = Payload::Delete {
|
||||
node: NodeName(String::from("foo")),
|
||||
redirect: Some(Redirect {
|
||||
uri: String::from("xmpp:hamlet@denmark.lit?;node=blog"),
|
||||
}),
|
||||
});
|
||||
redirect_uri: Some(String::from("xmpp:hamlet@denmark.lit?;node=blog")),
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
@ -304,9 +248,10 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Purge(Purge {
|
||||
let payload = Payload::Purge {
|
||||
node: NodeName(String::from("foo")),
|
||||
});
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
@ -319,7 +264,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
|
||||
let pubsub = PubSubOwner::Subscriptions(Subscriptions {
|
||||
let payload = Payload::Subscriptions {
|
||||
node: NodeName(String::from("foo")),
|
||||
subscriptions: vec![
|
||||
SubscriptionElem {
|
||||
|
|
@ -343,7 +288,8 @@ mod tests {
|
|||
subid: Some(String::from("004-yyy")),
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
let pubsub = Owner { payload };
|
||||
|
||||
let elem2 = Element::from(pubsub);
|
||||
assert_eq!(elem1, elem2);
|
||||
|
|
|
|||
Loading…
Reference in a new issue