zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use once_cell::sync::Lazy;
use regex::Regex;
use validator::{Validate, ValidationError, ValidationErrors, ValidationErrorsKind};

static EMAIL_RE: Lazy<Regex> = Lazy::new(|| {
    // 这是一个常用的、较宽松的邮箱正则(不是完全 RFC5322)
    Regex::new(r"(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$").unwrap()
});

pub fn to_valid_email(email: &str) -> bool {
    let email = email.trim();

    EMAIL_RE.is_match(email)
}

pub fn validation_flatten(data: &impl Validate) -> Option<String> {
    if let Err(_e) = data.validate() {
        let errors = _flatten_errors(&_e, None, None);

        if !errors.is_empty() {
            let message = errors
                .iter()
                .map(|(_, field, err)| format!("{}: {}", field, err))
                .collect::<Vec<_>>()
                .join("<br />")
                .to_string();

            return Some(message);
        }
    }

    None
}

fn _flatten_errors(
    errors: &ValidationErrors,
    path: Option<String>,
    indent: Option<u16>,
) -> Vec<(u16, String, &ValidationError)> {
    errors
        .errors()
        .iter()
        .flat_map(|(field, err)| {
            let indent = indent.unwrap_or(0);

            let actual_path = path
                .as_ref()
                .map(|path| [path.as_str(), field].join("."))
                .unwrap_or_else(|| field.clone().into_owned().to_string());

            match err {
                ValidationErrorsKind::Field(field_errors) => field_errors
                    .iter()
                    .map(|error| (indent, actual_path.clone(), error))
                    .collect::<Vec<_>>(),

                ValidationErrorsKind::List(list_error) => list_error
                    .iter()
                    .flat_map(|(index, errors)| {
                        let actual_path = format!("{}[{}]", actual_path.as_str(), index);
                        _flatten_errors(errors, Some(actual_path), Some(indent + 1))
                    })
                    .collect::<Vec<_>>(),

                ValidationErrorsKind::Struct(struct_errors) => {
                    _flatten_errors(struct_errors, Some(actual_path), Some(indent + 1))
                }
            }
        })
        .collect::<Vec<_>>()
}