// Copyright (c) ??? // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::data_forms::DataForm; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; use crate::pubsub::NodeName; use crate::util::error::Error; use crate::Element; use std::convert::TryFrom; generate_element!( /// Request to configure a node. Configure, "configure", PUBSUB_OWNER, attributes: [ /// The node to be configured. node: Option = "node", ], children: [ /// The form to configure it. form: Option = ("x", DATA_FORMS) => DataForm ] ); /// Main payload used to communicate with a PubSubOwner service. /// /// `` #[derive(Debug, Clone)] pub enum PubSubOwner { /// Request to configure a node, with optional suggested name and suggested configuration. Configure { /// The configure request for the new node. configure: Configure, }, } impl IqGetPayload for PubSubOwner {} impl IqSetPayload for PubSubOwner {} impl IqResultPayload for PubSubOwner {} impl TryFrom for PubSubOwner { type Error = Error; fn try_from(elem: Element) -> Result { 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::ParseError( "Payload is already defined in pubsub owner element.", )); } let configure = Configure::try_from(child.clone())?; payload = Some(PubSubOwner::Configure { configure: configure, }); } else { return Err(Error::ParseError("Unknown child in pubsub element.")); } } Ok(payload.ok_or(Error::ParseError("No payload in pubsub element."))?) } } 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)], }) .build() } } #[cfg(test)] mod tests { use super::*; use crate::data_forms::{DataForm, DataFormType, Field, FieldType}; use std::str::FromStr; #[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 elem2 = Element::from(pubsub); assert_eq!(elem1, elem2); } #[test] fn test_serialize_configure() { let reference: Element = "" .parse() .unwrap(); let elem: Element = "".parse().unwrap(); let form = DataForm::try_from(elem).unwrap(); let configure = PubSubOwner::Configure { configure: Configure { node: Some(NodeName(String::from("foo"))), form: Some(form), }, }; let serialized: Element = configure.into(); assert_eq!(serialized, reference); } }