acorn_lib/schema/
validate.rs

1use crate::constants::*;
2use fancy_regex::Regex;
3use std::collections::HashMap;
4use validator::ValidationError;
5use validator::{Validate, ValidationErrorsKind};
6
7pub fn format_errors(found: Vec<Option<HashMap<String, ValidationErrorsKind>>>) -> HashMap<String, ValidationErrorsKind> {
8    found.clone().into_iter().flatten().fold(HashMap::new(), |mut acc, x| {
9        for (key, value) in x.iter() {
10            acc.insert(key.clone(), value.clone());
11        }
12        acc
13    })
14}
15pub fn get_validation_errors<T: Validate>(attribute: T) -> Option<HashMap<String, ValidationErrorsKind>> {
16    match attribute.validate() {
17        | Ok(_) => None,
18        | Err(err) => Some(
19            err.into_errors()
20                .into_iter()
21                .map(|(k, v)| (k.to_string(), v))
22                .collect::<HashMap<String, ValidationErrorsKind>>(),
23        ),
24    }
25}
26pub fn get_error_count(errors: HashMap<String, ValidationErrorsKind>) -> usize {
27    errors
28        .clone()
29        .into_values()
30        .map(|v| match v {
31            | ValidationErrorsKind::Field(_) => 1,
32            | ValidationErrorsKind::Struct(errors) => errors.into_errors().len(),
33            | ValidationErrorsKind::List(_) => 0,
34        })
35        .sum()
36}
37pub fn has_image_extension(value: &str) -> Result<(), ValidationError> {
38    const MESSAGE: &str = "Please provide a path with a PNG, JPEG, or SVG extension";
39    match RE_IMAGE_EXTENSION.is_match(value) {
40        | Ok(value) if value => Ok(()),
41        | _ => Err(ValidationError::new("image").with_message(MESSAGE.into())),
42    }
43}
44pub fn is_doi(value: &str) -> Result<(), ValidationError> {
45    const MESSAGE: &str = "Please provide a valid DOI, by itself and without domain or 'doi:' prefix.";
46    match RE_DOI.is_match(value) {
47        | Ok(value) if value => Ok(()),
48        | _ => Err(ValidationError::new("doi").with_message(MESSAGE.into())),
49    }
50}
51pub fn is_ip6(value: &str) -> Result<(), ValidationError> {
52    const MESSAGE: &str = "Please provide a valid IP6 address";
53    match RE_IP6.is_match(value) {
54        | Ok(value) if value => Ok(()),
55        | _ => Err(ValidationError::new("IP6").with_message(MESSAGE.into())),
56    }
57}
58pub fn is_kebabcase(value: &str) -> Result<(), ValidationError> {
59    const MESSAGE: &str = "Please provide an ID in kebab-case format";
60    let kebab = match Regex::new(r"[ *_./\!@#$%^&(){}]") {
61        | Ok(re) => re.replace_all(value, "").trim().to_string(),
62        | Err(err) => err.to_string(),
63    };
64    match kebab.to_lowercase().eq(&value) {
65        | true => Ok(()),
66        | _ => Err(ValidationError::new("kebabcase").with_message(MESSAGE.into())),
67    }
68}
69pub fn is_phone_number(value: &str) -> Result<(), ValidationError> {
70    const MESSAGE: &str = "Please provide a valid phone number";
71    match RE_PHONE.is_match(value) {
72        | Ok(value) if value => Ok(()),
73        | _ => Err(ValidationError::new("phone").with_message(MESSAGE.into())),
74    }
75}
76pub fn is_raid(value: &str) -> Result<(), ValidationError> {
77    const MESSAGE: &str = "Please provide a valid RAiD";
78    match RE_DOI.is_match(value) {
79        | Ok(value) if value => Ok(()),
80        | _ => Err(ValidationError::new("raid").with_message(MESSAGE.into())),
81    }
82}
83pub fn is_ror(value: &str) -> Result<(), ValidationError> {
84    const MESSAGE: &str = "Please provide a valid ROR";
85    match RE_ROR.is_match(value) {
86        | Ok(value) if value => Ok(()),
87        | _ => Err(ValidationError::new("ror").with_message(MESSAGE.into())),
88    }
89}
90pub fn validate_attribute_areas(value: &[String]) -> Result<(), ValidationError> {
91    const MAX_LENGTH: usize = MAX_LENGTH_RESEARCH_AREA;
92    let is_valid = value.iter().all(|x| x.len() <= MAX_LENGTH);
93    match is_valid {
94        | true => Ok(()),
95        | _ => Err(ValidationError::new("area").with_message(format!("Each area should be less than {} characters", MAX_LENGTH).into())),
96    }
97}
98pub fn validate_attribute_capabilities(value: &[String]) -> Result<(), ValidationError> {
99    const MAX_LENGTH: usize = MAX_LENGTH_CAPABILIY;
100    let is_valid = value.iter().all(|x| x.len() <= MAX_LENGTH);
101    match is_valid {
102        | true => Ok(()),
103        | _ => Err(ValidationError::new("capability").with_message(format!("Each capability should be less than {} characters", MAX_LENGTH).into())),
104    }
105}
106pub fn validate_attribute_facilities(value: &[String]) -> Result<(), ValidationError> {
107    const MAX_LENGTH: usize = MAX_LENGTH_FACILITY;
108    let is_valid = value.iter().all(|x| x.len() <= MAX_LENGTH);
109    match is_valid {
110        | true => Ok(()),
111        | _ => Err(ValidationError::new("facility").with_message(format!("Each facility should be less than {} characters", MAX_LENGTH).into())),
112    }
113}
114pub fn validate_attribute_impact(value: &[String]) -> Result<(), ValidationError> {
115    const MAX_LENGTH: usize = MAX_LENGTH_IMPACT;
116    let is_valid = value.iter().all(|x| x.len() <= MAX_LENGTH);
117    match is_valid {
118        | true => Ok(()),
119        | _ => Err(ValidationError::new("impact").with_message(format!("Each impact item should be less than {} characters", MAX_LENGTH).into())),
120    }
121}
122pub fn validate_attribute_technical(value: &[String]) -> Result<(), ValidationError> {
123    const MAX_LENGTH: usize = MAX_LENGTH_TECHNICAL;
124    let is_valid = value.iter().all(|x| x.len() <= MAX_LENGTH);
125    match is_valid {
126        | true => Ok(()),
127        | _ => Err(ValidationError::new("technical approach")
128            .with_message(format!("Each element of technical approach should be less than {} characters", MAX_LENGTH).into())),
129    }
130}
131pub fn validate_attribute_outcomes(value: &[String]) -> Result<(), ValidationError> {
132    const MAX_LENGTH: usize = MAX_LENGTH_OUTCOME;
133    match value.iter().all(|x| x.len() <= MAX_LENGTH) {
134        | true => {
135            let is_valid = value.iter().all(|x| !x.trim().ends_with("."));
136            match is_valid {
137                | true => Ok(()),
138                | _ => Err(ValidationError::new("outcome").with_message("Outcomes should be phrases that do not end in periods".into())),
139            }
140        }
141        | _ => Err(ValidationError::new("outcome").with_message(format!("Each outcome should be less than {} characters", MAX_LENGTH).into())),
142    }
143}