diff --git a/xmpp-parsers/src/pubsub/mod.rs b/xmpp-parsers/src/pubsub/mod.rs index 5b15ef24445dcd82572d7f871710dbcf5ae26ed8..008d7a0489418ccbdc4182b3a232123d08b38b9c 100644 --- a/xmpp-parsers/src/pubsub/mod.rs +++ b/xmpp-parsers/src/pubsub/mod.rs @@ -52,6 +52,29 @@ generate_attribute!( }, Default = None ); +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", + } +); + /// An item from a PubSub node. #[derive(Debug, Clone, PartialEq)] pub struct Item { diff --git a/xmpp-parsers/src/pubsub/owner.rs b/xmpp-parsers/src/pubsub/owner.rs index b6d1d1c456a26473685db096aba541cf5fd56b8e..b5b394bde25e263fc79f5e9ea32c02d9d67208e1 100644 --- a/xmpp-parsers/src/pubsub/owner.rs +++ b/xmpp-parsers/src/pubsub/owner.rs @@ -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 = "node", + ], + children: [ + /// The actual list of affiliation elements. + affiliations: Vec = ("affiliation", PUBSUB_OWNER) => Affiliation + ] +); + +generate_element!( + /// An affiliation element. + Affiliation, "affiliation", PUBSUB_OWNER, + attributes: [ + /// The node this affiliation pertains to. + jid: Required = "jid", + + /// The affiliation you currently have on this node. + affiliation: Required = "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 = ("x", DATA_FORMS) => DataForm + ] +); + +generate_element!( + /// Request to delete a node. + Delete, "delete", PUBSUB_OWNER, + attributes: [ + /// The node to be configured. + node: Required = "node", + ], + children: [ + /// Redirection to replace the deleted node. + redirect: Vec = ("redirect", PUBSUB_OWNER) => Redirect + ] +); + +generate_element!( + /// A redirect element. + Redirect, "redirect", PUBSUB_OWNER, + attributes: [ + /// The node this node will be redirected to. + uri: Required = "uri", + ] +); + +generate_element!( + /// Request to delete a node. + Purge, "purge", PUBSUB_OWNER, + attributes: [ + /// The node to be configured. + node: Required = "node", + ] +); + +generate_element!( + /// A request for current subscriptions. + Subscriptions, "subscriptions", PUBSUB_OWNER, + attributes: [ + /// The node to query. + node: Required = "node", + ], + children: [ + /// The list of subscription elements returned. + subscriptions: Vec = ("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", + + /// The state of the subscription. + subscription: Required = "subscription", + + /// Subscription unique id. + subid: Option = "subid", + ] +); + /// Main payload used to communicate with a PubSubOwner service. /// /// `` #[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 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 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 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 = "" + .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 = "http://jabber.org/protocol/pubsub#node_configwhitelist" .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 = "http://jabber.org/protocol/pubsub#node_configwhitelist" + .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 = "" + .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 = "" + .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 = "" + .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); + } } diff --git a/xmpp-parsers/src/pubsub/pubsub.rs b/xmpp-parsers/src/pubsub/pubsub.rs index 6184e40241fe06071e3d03caaa0bc8a2f054a664..458dba7d04d9ea06f875c4cbc7596bb7798f1bc8 100644 --- a/xmpp-parsers/src/pubsub/pubsub.rs +++ b/xmpp-parsers/src/pubsub/pubsub.rs @@ -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,