Implement all sub element of pubsub#owner
This commit is contained in:
parent
e6d4047160
commit
cc4e0c247e
3 changed files with 286 additions and 60 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue