use crate::{
data::{
Account, DataError, MyEmailAddress, ObjectType, Validate, ValidationError, validate_sha1sum,
},
emit_error,
};
use core::fmt;
use email_address::EmailAddress;
use iri_string::types::UriString;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{collections::HashSet, str::FromStr};
#[skip_serializing_none]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Person {
#[serde(rename = "objectType")]
#[serde(default = "default_object_type")]
object_type: ObjectType,
name: Vec<String>,
mbox: Vec<MyEmailAddress>,
mbox_sha1sum: Vec<String>,
openid: Vec<UriString>,
account: Vec<Account>,
}
impl Person {
pub fn builder() -> PersonBuilder {
PersonBuilder::default()
}
pub fn check_object_type(&self) -> bool {
self.object_type == ObjectType::Person
}
pub fn names(&self) -> &[String] {
self.name.as_slice()
}
pub fn mboxes(&self) -> &[MyEmailAddress] {
self.mbox.as_slice()
}
pub fn mbox_sha1sums(&self) -> &[String] {
self.mbox_sha1sum.as_slice()
}
pub fn openids(&self) -> &[UriString] {
self.openid.as_slice()
}
pub fn accounts(&self) -> &[Account] {
self.account.as_slice()
}
pub fn unknown() -> Self {
Person {
object_type: ObjectType::Person,
name: vec![],
mbox: vec![],
mbox_sha1sum: vec![],
openid: vec![],
account: vec![],
}
}
}
impl fmt::Display for Person {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut vec = vec![];
let y: Vec<_> = self.name.iter().map(|x| x.to_string()).collect();
if !y.is_empty() {
vec.push(format!("\"name\": [{}]", y.join(", ")))
}
let y: Vec<_> = self.mbox.iter().map(|x| x.as_ref().to_string()).collect();
if !y.is_empty() {
vec.push(format!("\"mbox\": [{}]", y.join(", ")))
}
let y: Vec<_> = self.mbox_sha1sum.iter().map(|x| x.to_string()).collect();
if !y.is_empty() {
vec.push(format!("\"mbox_sha1sum\": [{}]", y.join(", ")))
}
let y: Vec<_> = self.openid.iter().map(|x| x.to_string()).collect();
if !y.is_empty() {
vec.push(format!("\"openid\": [{}]", y.join(", ")))
}
let y: Vec<_> = self.account.iter().map(|x| x.to_string()).collect();
if !y.is_empty() {
vec.push(format!("\"account\": [{}]", y.join(", ")))
}
let res = vec
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ");
write!(f, "Person{{ {res} }}")
}
}
impl Validate for Person {
fn validate(&self) -> Vec<ValidationError> {
let mut vec = vec![];
if !self.check_object_type() {
vec.push(ValidationError::WrongObjectType {
expected: ObjectType::Agent,
found: self.object_type.to_string().into(),
})
}
self.name.iter().for_each(|x| {
if x.trim().is_empty() {
vec.push(ValidationError::Empty("name".into()))
}
});
self.mbox_sha1sum.iter().for_each(|x| {
if x.trim().is_empty() {
vec.push(ValidationError::Empty("mbox_sha1sum".into()))
} else {
validate_sha1sum(x).unwrap_or_else(|x| vec.push(x))
}
});
self.account
.iter()
.for_each(|x| x.check_validity().unwrap_or_else(|x| vec.push(x)));
vec
}
}
#[derive(Default, Debug)]
pub struct PersonBuilder {
_name: HashSet<String>,
_mbox: HashSet<MyEmailAddress>,
_mbox_sha1sum: HashSet<String>,
_openid: HashSet<UriString>,
_account: HashSet<Account>,
}
impl PersonBuilder {
pub fn name(mut self, val: &str) -> Result<Self, DataError> {
let val = val.trim();
if val.is_empty() {
emit_error!(DataError::Validation(ValidationError::Empty("name".into())))
}
self._name.insert(val.to_owned());
Ok(self)
}
pub fn mbox(mut self, val: &str) -> Result<Self, DataError> {
let val = val.trim();
if val.is_empty() {
emit_error!(DataError::Validation(ValidationError::Empty("mbox".into())))
}
let email = if let Some(x) = val.strip_prefix("mailto:") {
EmailAddress::from_str(x)?
} else {
EmailAddress::from_str(val)?
};
self._mbox.insert(MyEmailAddress::from(email));
Ok(self)
}
pub fn mbox_sha1sum(mut self, val: &str) -> Result<Self, DataError> {
let val = val.trim();
if val.is_empty() {
emit_error!(DataError::Validation(ValidationError::Empty(
"mbox_sha1sum".into()
)))
}
validate_sha1sum(val)?;
self._mbox_sha1sum.insert(val.to_owned());
Ok(self)
}
pub fn openid(mut self, val: &str) -> Result<Self, DataError> {
let val = val.trim();
if val.is_empty() {
emit_error!(DataError::Validation(ValidationError::Empty(
"openid".into()
)))
}
let uri = UriString::from_str(val)?;
self._openid.insert(uri);
Ok(self)
}
pub fn account(mut self, val: Account) -> Result<Self, DataError> {
val.check_validity()?;
self._account.insert(val);
Ok(self)
}
pub fn build(self) -> Result<Person, DataError> {
Ok(Person {
object_type: ObjectType::Person,
name: self._name.into_iter().collect(),
mbox: self._mbox.into_iter().collect(),
mbox_sha1sum: self._mbox_sha1sum.into_iter().collect(),
openid: self._openid.into_iter().collect(),
account: self._account.into_iter().collect(),
})
}
}
fn default_object_type() -> ObjectType {
ObjectType::Person
}