@@ -7,11 +7,37 @@
use crate::data_forms::DataForm;
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::ns;
-use crate::pubsub::NodeName;
+use crate::pubsub::{AffiliationAttribute, NodeName, Subscription};
use crate::util::error::Error;
use crate::Element;
+use jid::Jid;
use std::convert::TryFrom;
+generate_element!(
+ /// A list of affiliations you have on a service, or on a node.
+ Affiliations, "affiliations", PUBSUB_OWNER,
+ attributes: [
+ /// The node name this request pertains to.
+ node: Required<NodeName> = "node",
+ ],
+ children: [
+ /// The actual list of affiliation elements.
+ affiliations: Vec<Affiliation> = ("affiliation", PUBSUB_OWNER) => Affiliation
+ ]
+);
+
+generate_element!(
+ /// An affiliation element.
+ Affiliation, "affiliation", PUBSUB_OWNER,
+ attributes: [
+ /// The node this affiliation pertains to.
+ jid: Required<Jid> = "jid",
+
+ /// The affiliation you currently have on this node.
+ affiliation: Required<AffiliationAttribute> = "affiliation",
+ ]
+);
+
generate_element!(
/// Request to configure a node.
Configure, "configure", PUBSUB_OWNER,
@@ -25,16 +51,91 @@ generate_element!(
]
);
+generate_element!(
+ /// Request to change default configuration.
+ Default, "default", PUBSUB_OWNER,
+ children: [
+ /// The form to configure it.
+ form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
+ ]
+);
+
+generate_element!(
+ /// Request to delete a node.
+ Delete, "delete", PUBSUB_OWNER,
+ attributes: [
+ /// The node to be configured.
+ node: Required<NodeName> = "node",
+ ],
+ children: [
+ /// Redirection to replace the deleted node.
+ redirect: Vec<Redirect> = ("redirect", PUBSUB_OWNER) => Redirect
+ ]
+);
+
+generate_element!(
+ /// A redirect element.
+ Redirect, "redirect", PUBSUB_OWNER,
+ attributes: [
+ /// The node this node will be redirected to.
+ uri: Required<String> = "uri",
+ ]
+);
+
+generate_element!(
+ /// Request to delete a node.
+ Purge, "purge", PUBSUB_OWNER,
+ attributes: [
+ /// The node to be configured.
+ node: Required<NodeName> = "node",
+ ]
+);
+
+generate_element!(
+ /// A request for current subscriptions.
+ Subscriptions, "subscriptions", PUBSUB_OWNER,
+ attributes: [
+ /// The node to query.
+ node: Required<NodeName> = "node",
+ ],
+ children: [
+ /// The list of subscription elements returned.
+ subscriptions: Vec<SubscriptionElem> = ("subscription", PUBSUB_OWNER) => SubscriptionElem
+ ]
+);
+
+generate_element!(
+ /// A subscription element, describing the state of a subscription.
+ SubscriptionElem, "subscription", PUBSUB_OWNER,
+ attributes: [
+ /// The JID affected by this subscription.
+ jid: Required<Jid> = "jid",
+
+ /// The state of the subscription.
+ subscription: Required<Subscription> = "subscription",
+
+ /// Subscription unique id.
+ subid: Option<String> = "subid",
+ ]
+);
+
/// Main payload used to communicate with a PubSubOwner service.
///
/// `<pubsub xmlns="http://jabber.org/protocol/pubsub#owner"/>`
#[derive(Debug, Clone)]
pub enum PubSubOwner {
+ /// Manage the affiliations of a node.
+ Affiliations(Affiliations),
/// Request to configure a node, with optional suggested name and suggested configuration.
- Configure {
- /// The configure request for the new node.
- configure: Configure,
- },
+ Configure(Configure),
+ /// Request the default node configuration.
+ Default(Default),
+ /// Delete a node.
+ Delete(Delete),
+ /// Purge all items from node.
+ Purge(Purge),
+ /// Request subscriptions of a node.
+ Subscriptions(Subscriptions),
}
impl IqGetPayload for PubSubOwner {}
@@ -57,9 +158,7 @@ impl TryFrom<Element> for PubSubOwner {
));
}
let configure = Configure::try_from(child.clone())?;
- payload = Some(PubSubOwner::Configure {
- configure: configure,
- });
+ payload = Some(PubSubOwner::Configure(configure));
} else {
return Err(Error::ParseError("Unknown child in pubsub element."));
}
@@ -72,7 +171,12 @@ impl From<PubSubOwner> for Element {
fn from(pubsub: PubSubOwner) -> Element {
Element::builder("pubsub", ns::PUBSUB_OWNER)
.append_all(match pubsub {
- PubSubOwner::Configure { configure } => vec![Element::from(configure)],
+ 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()
}
@@ -82,36 +186,59 @@ impl From<PubSubOwner> for Element {
mod tests {
use super::*;
use crate::data_forms::{DataForm, DataFormType, Field, FieldType};
+ use jid::BareJid;
use std::str::FromStr;
+ #[test]
+ fn affiliations() {
+ 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>"
+ .parse()
+ .unwrap();
+ let elem1 = elem.clone();
+
+ let pubsub = PubSubOwner::Affiliations(Affiliations {
+ node: NodeName(String::from("foo")),
+ affiliations: vec![
+ Affiliation {
+ jid: Jid::Bare(BareJid::from_str("hamlet@denmark.lit").unwrap()),
+ affiliation: AffiliationAttribute::Owner,
+ },
+ Affiliation {
+ jid: Jid::Bare(BareJid::from_str("polonius@denmark.lit").unwrap()),
+ affiliation: AffiliationAttribute::Outcast,
+ },
+ ],
+ });
+
+ let elem2 = Element::from(pubsub);
+ assert_eq!(elem1, elem2);
+ }
+
#[test]
fn configure() {
- // XXX: Do we want xmpp-parsers to always specify the field type in the output Element?
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>"
.parse()
.unwrap();
let elem1 = elem.clone();
- let pubsub = PubSubOwner::Configure {
- configure: Configure {
- node: Some(NodeName(String::from("foo"))),
- form: Some(DataForm {
- type_: DataFormType::Submit,
- form_type: Some(String::from(ns::PUBSUB_CONFIGURE)),
- title: None,
- instructions: None,
- fields: vec![Field {
- var: String::from("pubsub#access_model"),
- type_: FieldType::ListSingle,
- label: None,
- required: false,
- options: vec![],
- values: vec![String::from("whitelist")],
- media: vec![],
- }],
- }),
- },
- };
+ let pubsub = PubSubOwner::Configure(Configure {
+ node: Some(NodeName(String::from("foo"))),
+ form: Some(DataForm {
+ type_: DataFormType::Submit,
+ form_type: Some(String::from(ns::PUBSUB_CONFIGURE)),
+ title: None,
+ instructions: None,
+ fields: vec![Field {
+ var: String::from("pubsub#access_model"),
+ type_: FieldType::ListSingle,
+ label: None,
+ required: false,
+ options: vec![],
+ values: vec![String::from("whitelist")],
+ media: vec![],
+ }],
+ }),
+ });
let elem2 = Element::from(pubsub);
assert_eq!(elem1, elem2);
@@ -127,13 +254,110 @@ mod tests {
let form = DataForm::try_from(elem).unwrap();
- let configure = PubSubOwner::Configure {
- configure: Configure {
- node: Some(NodeName(String::from("foo"))),
- form: Some(form),
- },
- };
+ let configure = PubSubOwner::Configure(Configure {
+ node: Some(NodeName(String::from("foo"))),
+ form: Some(form),
+ });
let serialized: Element = configure.into();
assert_eq!(serialized, reference);
}
+
+ #[test]
+ fn default() {
+ 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>"
+ .parse()
+ .unwrap();
+ let elem1 = elem.clone();
+
+ let pubsub = PubSubOwner::Default(Default {
+ form: Some(DataForm {
+ type_: DataFormType::Submit,
+ form_type: Some(String::from(ns::PUBSUB_CONFIGURE)),
+ title: None,
+ instructions: None,
+ fields: vec![Field {
+ var: String::from("pubsub#access_model"),
+ type_: FieldType::ListSingle,
+ label: None,
+ required: false,
+ options: vec![],
+ values: vec![String::from("whitelist")],
+ media: vec![],
+ }],
+ }),
+ });
+
+ let elem2 = Element::from(pubsub);
+ assert_eq!(elem1, elem2);
+ }
+
+ #[test]
+ fn delete() {
+ let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><delete node='foo'><redirect uri='xmpp:hamlet@denmark.lit?;node=blog'/></delete></pubsub>"
+ .parse()
+ .unwrap();
+ let elem1 = elem.clone();
+
+ let pubsub = PubSubOwner::Delete(Delete {
+ node: NodeName(String::from("foo")),
+ redirect: vec![Redirect {
+ uri: String::from("xmpp:hamlet@denmark.lit?;node=blog"),
+ }],
+ });
+
+ let elem2 = Element::from(pubsub);
+ assert_eq!(elem1, elem2);
+ }
+
+ #[test]
+ fn purge() {
+ let elem: Element = "<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'><purge node='foo'></purge></pubsub>"
+ .parse()
+ .unwrap();
+ let elem1 = elem.clone();
+
+ let pubsub = PubSubOwner::Purge(Purge {
+ node: NodeName(String::from("foo")),
+ });
+
+ let elem2 = Element::from(pubsub);
+ assert_eq!(elem1, elem2);
+ }
+
+ #[test]
+ fn subscriptions() {
+ 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>"
+ .parse()
+ .unwrap();
+ let elem1 = elem.clone();
+
+ let pubsub = PubSubOwner::Subscriptions(Subscriptions {
+ node: NodeName(String::from("foo")),
+ subscriptions: vec![
+ SubscriptionElem {
+ jid: Jid::Bare(BareJid::from_str("hamlet@denmark.lit").unwrap()),
+ subscription: Subscription::Subscribed,
+ subid: None,
+ },
+ SubscriptionElem {
+ jid: Jid::Bare(BareJid::from_str("polonius@denmark.lit").unwrap()),
+ subscription: Subscription::Unconfigured,
+ subid: None,
+ },
+ SubscriptionElem {
+ jid: Jid::Bare(BareJid::from_str("bernardo@denmark.lit").unwrap()),
+ subscription: Subscription::Subscribed,
+ subid: Some(String::from("123-abc")),
+ },
+ SubscriptionElem {
+ jid: Jid::Bare(BareJid::from_str("bernardo@denmark.lit").unwrap()),
+ subscription: Subscription::Subscribed,
+ subid: Some(String::from("004-yyy")),
+ },
+ ],
+ });
+
+ let elem2 = Element::from(pubsub);
+ assert_eq!(elem1, elem2);
+ }
}
@@ -7,7 +7,9 @@
use crate::data_forms::DataForm;
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::ns;
-use crate::pubsub::{Item as PubSubItem, NodeName, Subscription, SubscriptionId};
+use crate::pubsub::{
+ AffiliationAttribute, Item as PubSubItem, NodeName, Subscription, SubscriptionId,
+};
use crate::util::error::Error;
use crate::Element;
use jid::Jid;
@@ -28,29 +30,6 @@ generate_element!(
]
);
-generate_attribute!(
- /// A list of possible affiliations to a node.
- AffiliationAttribute, "affiliation", {
- /// You are a member of this node, you can subscribe and retrieve items.
- Member => "member",
-
- /// You donβt have a specific affiliation with this node, you can only subscribe to it.
- None => "none",
-
- /// You are banned from this node.
- Outcast => "outcast",
-
- /// You are an owner of this node, and can do anything with it.
- Owner => "owner",
-
- /// You are a publisher on this node, you can publish and retract items to it.
- Publisher => "publisher",
-
- /// You can publish and retract items on this node, but not subscribe or retrieve items.
- PublishOnly => "publish-only",
- }
-);
-
generate_element!(
/// An affiliation element.
Affiliation, "affiliation", PUBSUB,