use serde::{Serialize, Deserialize, Deserializer}; use std::fmt; use rand::{thread_rng, Rng}; use chrono::prelude::{DateTime, Utc, NaiveDate, Datelike}; /// ID #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash)] pub struct Id(pub u64); impl From<Id> for String { fn from(val: Id) -> Self { format!("{:x}", val.0) } } impl fmt::Display for Id { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } pub fn generate_id() -> Id { Id(thread_rng().gen()) } pub fn parse_date_iso(inp: &str) -> Option<DateTime<Utc>> { let date = NaiveDate::parse_from_str(inp, "%Y-%m-%d").ok()?; Some(DateTime::<Utc>::from_naive_utc_and_offset( date.and_hms_opt(0, 0, 0).unwrap(), Utc )) } pub fn parse_datetime_american(inp: &str) -> Option<DateTime<Utc>> { let date = NaiveDate::parse_from_str(inp, "%m/%d/%Y").ok()?; Some(DateTime::<Utc>::from_naive_utc_and_offset( date.and_hms_opt(0, 0, 0).unwrap(), Utc )) } pub fn parse_datetime_french(inp: &str) -> Option<DateTime<Utc>> { let date = NaiveDate::parse_from_str(inp, "%d/%m/%Y").ok()?; Some(DateTime::<Utc>::from_naive_utc_and_offset( date.and_hms_opt(0, 0, 0).unwrap(), Utc )) } pub fn parse_normalize_phone(inp: String) -> Option<String> { let parsed = match phonenumber::parse( Some(phonenumber::country::Id::FR), inp ) { Ok(r) => r, Err(_e) => { return None; } }; Some(parsed.to_string()) } pub fn complete_date(inp: NaiveDate) -> DateTime<Utc> { DateTime::<Utc>::from_naive_utc_and_offset( inp.and_hms_opt(0, 0, 0).unwrap(), Utc ) } pub fn normalize_str(subject: String) -> String { subject.trim().replace('\n', ";").to_string() } /// remove year precision to comply with GDPR eu rules pub fn parse_and_get_birthday_year(raw_date: String) -> Option<u32> { let d_res = NaiveDate::parse_from_str(raw_date.trim(), "%d/%m/%Y"); let d = d_res.ok()?; d.year().try_into().ok() } pub fn capitalize(s: &str) -> String { let mut c = s.chars(); match c.next() { None => String::new(), Some(f) => f.to_uppercase().collect::<String>() + c.as_str(), } } /// normalisation d'un prénom pub fn normalize_first_name(subject: String) -> String { subject .trim() .to_lowercase() .replace(' ', "-") .split('-') .map(capitalize) .collect::<Vec<String>>() .join("-") } pub fn normalize_last_name(subject: String) -> String { subject .to_uppercase() } /// https://serde.rs/field-attrs.html pub fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; DateTime::parse_from_rfc3339(&s) .map_err(serde::de::Error::custom) .map(|dt| dt.with_timezone(&Utc)) } pub fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; NaiveDate::parse_from_str(&s, "%Y-%m-%d") .map_err(serde::de::Error::custom) } pub fn deserialize_json_list<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; serde_json::from_str(&s).map_err(serde::de::Error::custom) }