2023-12-26 15:09:49 +00:00
|
|
|
use serde::{Serialize, Deserialize, Deserializer};
|
2023-12-27 00:03:33 +00:00
|
|
|
use std::fmt;
|
2023-12-21 16:31:21 +00:00
|
|
|
use rand::{thread_rng, Rng};
|
2024-01-19 11:54:24 +00:00
|
|
|
use chrono::prelude::{DateTime, Utc, NaiveDate, Datelike};
|
2023-12-21 16:31:21 +00:00
|
|
|
|
|
|
|
/// ID
|
|
|
|
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct Id(pub u64);
|
2023-12-28 10:40:38 +00:00
|
|
|
|
2023-12-21 16:31:21 +00:00
|
|
|
impl Into<String> for Id {
|
|
|
|
fn into(self) -> String {
|
|
|
|
format!("{:x}", self.0)
|
|
|
|
}
|
|
|
|
}
|
2023-12-27 00:03:33 +00:00
|
|
|
impl fmt::Display for Id {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.0)
|
|
|
|
}
|
|
|
|
}
|
2023-12-21 16:31:21 +00:00
|
|
|
|
|
|
|
pub fn generate_id() -> Id {
|
|
|
|
Id(thread_rng().gen())
|
|
|
|
}
|
|
|
|
|
2023-12-26 15:09:49 +00:00
|
|
|
|
2024-01-13 16:51:06 +00:00
|
|
|
/// https://serde.rs/field-attrs.html
|
2023-12-26 15:09:49 +00:00
|
|
|
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))
|
|
|
|
}
|
2024-01-13 16:51:06 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2024-01-13 16:51:23 +00:00
|
|
|
|
|
|
|
pub fn parse_datetime(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_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
|
|
|
|
))
|
|
|
|
}
|
2024-01-19 11:54:24 +00:00
|
|
|
|
|
|
|
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 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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn normalize_first_name(subject: String) -> String {
|
|
|
|
subject
|
|
|
|
.to_lowercase()
|
|
|
|
.replace(" ", "-")
|
|
|
|
.split("-")
|
|
|
|
.map(|x| capitalize(x))
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join("-")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn normalize_last_name(subject: String) -> String {
|
|
|
|
subject
|
|
|
|
.to_uppercase()
|
|
|
|
}
|
|
|
|
|