1use std::str::FromStr;
2use std::collections::HashMap;
3
4use serde::ser::{Serialize, Serializer, SerializeStruct};
5
6use crate::error::{FormError, ValidationError};
7use crate::value::{ValueMap, Value};
8use crate::types::{
9 Method, Element, InputType, SelectType, ButtonType, Constraint, Attr};
10
11#[derive(Debug)]
35pub struct HtmlForm<'a> {
36 pub action: &'a str,
37 pub method: Method,
38 pub errors: HashMap<String, String>,
39 pub fields: Vec<Field<'a>>,
40}
41
42impl <'a> HtmlForm<'a> {
43 pub fn new(action: &'a str, method: Method) -> HtmlForm<'a> {
45 HtmlForm {
46 action,
47 method,
48 errors: HashMap::new(),
49 fields: Vec::new(),
50 }
51 }
52
53 pub fn update(&mut self, values: &ValueMap, check_required: bool) {
81 self.errors.drain();
82 for field in &mut self.fields {
83 if let Some(values) = values.values(&field.name) {
84 if !field.element.multi() && values.len() > 1 {
85 self.errors.insert(
86 field.name.to_string(),
87 String::from("field can only have one value"));
88 } else {
89 let values: Vec<&Value> = values.iter()
90 .map(|v| v)
91 .collect();
92 if let Err(e) = field.validate(&values) {
93 self.errors.insert(
94 field.name.to_string(), format!("{}", e));
95 }
96 field.set_values(values);
97 }
98 } else {
99 field.empty();
101 if check_required && field.required {
102 self.errors.insert(
103 field.name.to_string(),
104 String::from("no value for required field"));
105 }
106 }
107 }
108 }
109
110 pub fn field(self, name: &str) -> Result<Field<'a>, FormError> {
113 for field in self.fields {
114 if field.name == name {
115 return Ok(field);
116 }
117 }
118 Err(FormError::new(&format!("no field named {}", name)))
119 }
120
121 pub fn get<T>(&self, name: &str) ->
125 Result<Vec<T>, FormError>
126 where T: FromStr {
127 for field in &self.fields {
128 if field.name == name {
129 return match &field.values {
130 Some(_) => {
131 let mut converted: Vec<T> = Vec::new();
132 for value in field.values() {
133 converted.push(value.parse()?);
134 }
135 Ok(converted)
136 },
137 None => Err(FormError::new(
138 &format!("field {} has no value", name))),
139 };
140 }
141 }
142 Err(FormError::new(
143 &format!("field {} not found", name)))
144 }
145
146 pub fn getone<T>(&self, name: &str) ->
150 Result<T, FormError>
151 where T: FromStr {
152 for field in &self.fields {
153 if field.name == name {
154 return match &field.values {
155 Some(_) => {
156 let values = field.values();
157 match values.len() {
158 0 => {
159 Err(FormError::new(
160 &format!(
161 "field {} has no value",
162 name)))
163 },
164 1 => {
165 Ok(values[0].parse()?)
166 },
167 _ => {
168 Err(FormError::new(
169 &format!(
170 "field {} has more than one value",
171 name)))
172 },
173 }
174 },
175 None => Err(FormError::new(
176 &format!("field {} has no value", name))),
177 };
178 }
179 }
180 Err(FormError::new(&format!("field {} not found", name)))
181 }
182
183 pub fn get_strings(&self, name: &str) -> Result<Vec<String>, FormError> {
186 for field in &self.fields {
187 if field.name == name {
188 return match &field.values {
189 Some(values) => {
190 Ok(values.iter().map(|v| v.as_string()).collect())
191 },
192 None => Err(FormError::new(
193 &format!("field {} has no value", name))),
194 };
195 }
196 }
197 Err(FormError::new(
198 &format!("field {} not found", name)))
199 }
200
201 pub fn get_string(&self, name: &str) -> Result<String, FormError> {
205 self.getone::<String>(name)
206 }
207
208 pub fn input(
213 self, input_type: InputType, name: &'a str, label: &'a str,
214 required: bool, constraints: Vec<Constraint<'a>>,
215 attributes: Vec<Attr<'a>>)
216 -> Result<Self, FormError> {
217 self.element(
218 Element::Input(input_type), name, label, required, None,
219 &[], constraints, attributes)
220 }
221
222 pub fn checkbox(
225 self, name: &'a str, label: &'a str,
226 required: bool, choices: &'a[(&'a str, &'a str)],
227 attributes: Vec<Attr<'a>>)
228 -> Result<Self, FormError> {
229 self.element(
230 Element::Input(InputType::Checkbox), name, label, required,
231 None, choices, vec![], attributes)
232 }
233
234 pub fn radio(
237 self, name: &'a str, label: &'a str,
238 required: bool, choices: &'a[(&'a str, &'a str)],
239 attributes: Vec<Attr<'a>>)
240 -> Result<Self, FormError> {
241 self.element(
242 Element::Input(InputType::Radio), name, label, required,
243 None, choices, vec![], attributes)
244 }
245
246 pub fn datalist_input(
249 self, input_type: InputType, name: &'a str, label: &'a str,
250 required: bool, datalist: &'a[(&'a str, &'a str)],
251 attributes: Vec<Attr<'a>>)
252 -> Result<Self, FormError> {
253 match input_type {
254 InputType::Password |
255 InputType::Radio |
256 InputType::Checkbox |
257 InputType::File |
258 InputType::Hidden |
259 InputType::Button |
260 InputType::Submit |
261 InputType::Reset => {
262 return Err(FormError::new(
263 &format!(
264 "invalid input type {:?} for datalist input",
265 input_type)));
266 },
267 _ => (),
268 }
269 self.element(
270 Element::Input(input_type), name, label, required, None,
271 datalist, vec![], attributes)
272 }
273
274 pub fn hidden(
275 self, name: &'a str, value: Option<&str>,
276 required: bool, constraints: Vec<Constraint<'a>>,
277 attributes: Vec<Attr<'a>>)
278 -> Result<Self, FormError> {
279 let values = match value {
280 Some(value) => Some(vec![value]),
281 None => None,
282 };
283 self.element(
284 Element::Input(InputType::Hidden), name, "", required, values,
285 &[], constraints, attributes)
286 }
287
288 pub fn textarea(
291 self, name: &'a str, label: &'a str, required: bool,
292 constraints: Vec<Constraint<'a>>, attributes: Vec<Attr<'a>>)
293 -> Result<Self, FormError> {
294 self.element(
295 Element::Textarea, name, label, required, None,
296 &[], constraints, attributes)
297 }
298
299 pub fn select(
302 self, name: &'a str, label: &'a str, multi: bool,
303 required: bool, choices: &'a[(&'a str, &'a str)],
304 attributes: Vec<Attr<'a>>)
305 -> Result<Self, FormError> {
306 let element = Element::Select(
307 if multi {
308 SelectType::Single
309 } else {
310 SelectType::Multi
311 });
312 self.element(
313 element, name, label, required, None, choices, vec![],
314 attributes)
315 }
316
317 pub fn submit(
320 self, name: Option<&'a str>, label: &'a str,
321 attributes: Vec<Attr<'a>>)
322 -> Result<Self, FormError> {
323 let name = match name {
324 Some(name) => name,
325 None => "",
326 };
327 self.element(
328 Element::Input(InputType::Submit), name, label, false, None,
329 &[], vec![], attributes)
330 }
331
332 pub fn reset(
335 self, label: &'a str, attributes: Vec<Attr<'a>>)
336 -> Result<Self, FormError> {
337 self.element(
338 Element::Input(InputType::Submit), "", label, false, None,
339 &[], vec![], attributes)
340 }
341
342 pub fn button(
345 self, button_type: ButtonType, name: &'a str, label: &'a str,
346 attributes: Vec<Attr<'a>>)
347 -> Result<Self, FormError> {
348 self.element(
349 Element::Button(button_type), name, label, false, None,
350 &[], vec![], attributes)
351 }
352
353 pub fn element(
357 mut self, element: Element, name: &'a str, label: &'a str,
358 required: bool, values: Option<Vec<&str>>,
359 choices: &'a[(&'a str, &'a str)],
360 constraints: Vec<Constraint<'a>>,
361 attributes: Vec<Attr<'a>>)
362 -> Result<Self, FormError> {
363 let values = match values {
364 Some(values) => {
365 let values: Vec<Value> = values.iter()
366 .map(|v| Value::new(v))
367 .collect();
368 for value in values.iter() {
369 if let Err(e) = element.validate(&value) {
370 return Err(FormError::new(&e.to_string()));
371 }
372 }
373 Some(values)
374 },
375 None => None,
376 };
377 for constraint in constraints.iter() {
378 if !constraint.allowed_on(&element) {
379 return Err(FormError::new(
380 &format!("constraint {:?} not allowed", constraint)));
381 }
382 }
383 for attribute in attributes.iter() {
384 if !attribute.allowed_on(&element) {
385 return Err(FormError::new(
386 &format!("attribute {:?} not allowed", attribute)));
387 }
388 }
389 self.fields.push(Field::new(
390 name, label, element, required, values, choices,
391 constraints, attributes));
392 Ok(self)
393 }
394}
395
396impl <'a> Serialize for HtmlForm<'a> {
397 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
398 where S: Serializer {
399 let mut s = serializer.serialize_struct("Field", 4)?;
400 s.serialize_field("action", &self.action)?;
401 s.serialize_field("method", &self.method.attrvalue())?;
402 s.serialize_field("errors", &self.errors)?;
403 s.serialize_field("fields", &self.fields)?;
404 s.end()
405 }
406}
407
408#[derive(Debug)]
416pub struct Field<'a> {
417 name: &'a str,
418 label: &'a str,
419 element: Element,
420 required: bool,
421 choices: &'a[(&'a str, &'a str)],
422 values: Option<Vec<Value>>,
423 attributes: Vec<Attr<'a>>,
424 constraints: Vec<Constraint<'a>>,
425}
426
427impl <'a> Field<'a> {
428 pub fn new(
434 name: &'a str, label: &'a str, element: Element,
435 required: bool, values: Option<Vec<Value>>,
436 choices: &'a[(&'a str, &'a str)],
437 constraints: Vec<Constraint<'a>>, attributes: Vec<Attr<'a>>)
438 -> Field<'a> {
439 Field {
440 name,
441 label,
442 element,
443 required,
444 choices,
445 constraints,
446 attributes,
447 values,
448 }
449 }
450
451 pub fn values(&self) -> Vec<Value> {
453 match &self.values {
454 None => Vec::new(),
455 Some(value) =>
456 value.iter()
457 .filter(|value| value.as_string() != "")
458 .map(|value| Value::new(&value.as_string()))
459 .collect(),
460 }
461 }
462
463 pub fn validate(&self, values: &[&Value])
473 -> Result<(), ValidationError> {
474 match self.element {
478 Element::Input(InputType::Checkbox) |
479 Element::Select(SelectType::Multi) => {
480 let choicevalues: Vec<&str> = self.choices.iter()
481 .map(|(value, _)| {
482 *value
483 })
484 .collect();
485 for value in values {
486 let value_str = value.as_string();
487 if !choicevalues.contains(&value_str.as_str()) {
488 return Err(ValidationError::new(
489 &format!(
490 "{} is not a valid choice.", value_str)));
491 }
492 let split: Vec<&[&Value]> = values
493 .split(|v| v == value)
494 .collect();
495 if split.len() > 2 {
496 return Err(
497 ValidationError::new(
498 &format!(
499 "Value {} provided more than once.",
500 value_str)));
501 }
502 }
503 },
504 _ => (),
505 }
506 for value in values {
507 self.element.validate(&value)?;
508 for constraint in self.constraints.iter() {
509 constraint.validate(&value)?;
510 }
511 }
512 Ok(())
513 }
514
515 pub fn empty(&mut self) {
517 self.values = Some(Vec::new());
518 }
519
520 pub fn set_values(&mut self, values: Vec<&Value>) {
522 let mut clone = Vec::new();
523 for value in values {
524 clone.push(Value::new(&value.as_string()));
525 }
526 self.values = Some(clone);
527 }
528}
529
530impl <'a> Serialize for Field<'a> {
531 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
532 where S: Serializer {
533 let mut s = serializer.serialize_struct("Field", 9)?;
534 s.serialize_field("name", &self.name)?;
535 s.serialize_field("label", &self.label)?;
536 s.serialize_field("element", &self.element.element_name())?;
537 s.serialize_field("type", &self.element.element_type())?;
538 s.serialize_field("required", &self.required)?;
539 s.serialize_field("multi", &self.element.multi())?;
540 s.serialize_field("choices", &self.choices)?;
541
542 let mut attributesmap = HashMap::new();
544 for constraint in &self.constraints {
545 if let Some((name, value)) = constraint.attrpair() {
546 attributesmap.insert(name, value);
547 }
548 }
549 for attribute in self.attributes.iter() {
550 let (name, value) = attribute.attrpair();
551 attributesmap.insert(name, value);
552 }
553 s.serialize_field("attributes", &attributesmap)?;
554
555 match &self.element.multi() {
558 true => {
559 s.serialize_field("value", &self.values)?;
560 },
561 false => {
562 match &self.values {
563 Some(value) => {
564 let strvalue = if value.len() == 1 {
565 match self.element {
566 Element::Input(InputType::Password) =>
567 String::new(),
568 _ => value[0].as_string(),
569 }
570 } else {
571 String::new()
572 };
573 s.serialize_field("value", &strvalue)?;
574 },
575 None => {
576 s.serialize_field("value", &self.values)?;
577 },
578 }
579 },
580 }
581 s.end()
582 }
583}