Support desc element in field

From [XEP-0004: Data Forms](https://xmpp.org/extensions/xep-0004.html#protocol-field):

> ...
> The <field/> element MAY contain any of the following child elements:
>
> <desc/>
> The XML character data of this element provides a natural-language
> description of the field, intended for presentation in a
> user-agent (e.g., as a "tool-tip", help button, or explanatory text
> provided near the field). The <desc/> element SHOULD NOT contain
> newlines (the \n and \r characters), since layout is the
> responsibility of a user agent, and any handling of
> newlines (e.g., presentation in a user interface) is unspecified
> herein. (Note: To provide a description of a field, it
> is RECOMMENDED to use a <desc/> element rather than
> a separate <field/> element of type "fixed".)
> ...
This commit is contained in:
mb 2023-08-30 17:01:17 +02:00 committed by Marc Bauer
parent cb3da52ba2
commit a1bee56ee1
4 changed files with 46 additions and 2 deletions

View file

@ -82,6 +82,9 @@ pub struct Field {
/// The form will be rejected if this field isnt present. /// The form will be rejected if this field isnt present.
pub required: bool, pub required: bool,
/// The natural-language description of the field, intended for presentation in a user-agent
pub desc: Option<String>,
/// A list of allowed values. /// A list of allowed values.
pub options: Vec<Option_>, pub options: Vec<Option_>,
@ -100,6 +103,7 @@ impl Field {
type_, type_,
label: None, label: None,
required: false, required: false,
desc: None,
options: Vec::new(), options: Vec::new(),
media: Vec::new(), media: Vec::new(),
values: Vec::new(), values: Vec::new(),
@ -174,6 +178,7 @@ impl TryFrom<Element> for Field {
type_: get_attr!(elem, "type", Default), type_: get_attr!(elem, "type", Default),
label: get_attr!(elem, "label", Option), label: get_attr!(elem, "label", Option),
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![], values: vec![],
media: vec![], media: vec![],
@ -204,6 +209,10 @@ impl TryFrom<Element> for Field {
} else if element.is("media", ns::MEDIA_ELEMENT) { } else if element.is("media", ns::MEDIA_ELEMENT) {
let media_element = MediaElement::try_from(element.clone())?; let media_element = MediaElement::try_from(element.clone())?;
field.media.push(media_element); field.media.push(media_element);
} else if element.is("desc", ns::DATA_FORMS) {
check_no_children!(element, "value");
check_no_attributes!(element, "value");
field.desc = Some(element.text());
} else { } else {
return Err(Error::ParseError( return Err(Error::ParseError(
"Field child isnt a value, option or media element.", "Field child isnt a value, option or media element.",
@ -374,7 +383,7 @@ mod tests {
fn test_size() { fn test_size() {
assert_size!(Option_, 24); assert_size!(Option_, 24);
assert_size!(FieldType, 1); assert_size!(FieldType, 1);
assert_size!(Field, 64); assert_size!(Field, 76);
assert_size!(DataFormType, 1); assert_size!(DataFormType, 1);
assert_size!(DataForm, 52); assert_size!(DataForm, 52);
} }
@ -384,7 +393,7 @@ mod tests {
fn test_size() { fn test_size() {
assert_size!(Option_, 48); assert_size!(Option_, 48);
assert_size!(FieldType, 1); assert_size!(FieldType, 1);
assert_size!(Field, 128); assert_size!(Field, 152);
assert_size!(DataFormType, 1); assert_size!(DataFormType, 1);
assert_size!(DataForm, 104); assert_size!(DataForm, 104);
} }
@ -428,6 +437,7 @@ mod tests {
type_: FieldType::Fixed, type_: FieldType::Fixed,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec!["Section 1: Bot Info".to_string()], values: vec!["Section 1: Bot Info".to_string()],
media: vec![], media: vec![],
@ -435,6 +445,30 @@ mod tests {
); );
} }
#[test]
fn test_desc() {
let elem: Element =
"<x xmlns='jabber:x:data' type='form'><field type='jid-multi' label='People to invite' var='invitelist'><desc>Tell all your friends about your new bot!</desc></field></x>"
.parse()
.unwrap();
let form = DataForm::try_from(elem).unwrap();
assert_eq!(form.type_, DataFormType::Form);
assert!(form.form_type.is_none());
assert_eq!(
form.fields,
vec![Field {
var: Some("invitelist".to_string()),
type_: FieldType::JidMulti,
label: Some("People to invite".to_string()),
required: false,
desc: Some("Tell all your friends about your new bot!".to_string()),
options: vec![],
values: vec![],
media: vec![],
}]
);
}
#[test] #[test]
fn test_invalid() { fn test_invalid() {
let elem: Element = "<x xmlns='jabber:x:data'/>".parse().unwrap(); let elem: Element = "<x xmlns='jabber:x:data'/>".parse().unwrap();

View file

@ -233,6 +233,7 @@ mod tests {
type_: FieldType::ListSingle, type_: FieldType::ListSingle,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![String::from("whitelist")], values: vec![String::from("whitelist")],
media: vec![], media: vec![],
@ -280,6 +281,7 @@ mod tests {
type_: FieldType::ListSingle, type_: FieldType::ListSingle,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![String::from("whitelist")], values: vec![String::from("whitelist")],
media: vec![], media: vec![],

View file

@ -625,6 +625,7 @@ mod tests {
type_: FieldType::ListSingle, type_: FieldType::ListSingle,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![String::from("whitelist")], values: vec![String::from("whitelist")],
media: vec![], media: vec![],

View file

@ -91,6 +91,7 @@ pub fn generate_address_field<S: Into<String>>(var: S, values: Vec<String>) -> F
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values, values,
media: vec![], media: vec![],
@ -126,6 +127,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![], values: vec![],
media: vec![], media: vec![],
@ -135,6 +137,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![ values: vec![
String::from("xmpp:admin@foo.bar"), String::from("xmpp:admin@foo.bar"),
@ -148,6 +151,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![], values: vec![],
media: vec![], media: vec![],
@ -157,6 +161,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![], values: vec![],
media: vec![], media: vec![],
@ -166,6 +171,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![ values: vec![
String::from("xmpp:security@foo.bar"), String::from("xmpp:security@foo.bar"),
@ -178,6 +184,7 @@ mod tests {
type_: FieldType::ListMulti, type_: FieldType::ListMulti,
label: None, label: None,
required: false, required: false,
desc: None,
options: vec![], options: vec![],
values: vec![String::from("mailto:support@foo.bar")], values: vec![String::from("mailto:support@foo.bar")],
media: vec![], media: vec![],