use crate::RecordReference;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct Contact {
#[serde(deserialize_with = "crate::shared::object_id_as_string", rename = "_id")]
pub id: String,
pub account: RecordReference,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub organisation: Option<RecordReference>,
pub primary: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secondary: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tertiary: Option<String>,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub nickname: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device: Option<ContactDevice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub opt_out: Option<bool>,
#[serde(rename = "_class", skip_serializing_if = "Option::is_none")]
pub class_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContactRef {
pub primary: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secondary: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tertiary: Option<String>,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub nickname: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device: Option<ContactDevice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub opt_out: Option<bool>,
#[serde(rename = "_class", skip_serializing_if = "Option::is_none")]
pub class_name: Option<String>,
}
impl From<Contact> for ContactRef {
fn from(contact: Contact) -> Self {
ContactRef {
primary: contact.primary,
secondary: contact.secondary,
tertiary: contact.tertiary,
name: contact.name,
nickname: contact.nickname,
email: contact.email,
capabilities: contact.capabilities,
groups: contact.groups,
device: contact.device,
group: contact.group,
opt_out: contact.opt_out,
class_name: contact.class_name,
}
}
}
impl From<&Contact> for ContactRef {
fn from(contact: &Contact) -> Self {
ContactRef {
primary: contact.primary.clone(),
secondary: contact.secondary.clone(),
tertiary: contact.tertiary.clone(),
name: contact.name.clone(),
nickname: contact.nickname.clone(),
email: contact.email.clone(),
capabilities: contact.capabilities.clone(),
groups: contact.groups.clone(),
device: contact.device.clone(),
group: contact.group.clone(),
opt_out: contact.opt_out,
class_name: contact.class_name.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContactDevice {
#[serde(rename = "_id")]
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub class_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub meta: Option<BTreeMap<String, String>>,
}
impl Contact {
pub fn new(
id: String,
account: RecordReference,
primary: String,
name: String,
) -> Self {
Self {
id,
account,
name,
primary,
organisation: None,
secondary: None,
tertiary: None,
nickname: None,
email: None,
capabilities: Vec::new(),
groups: Vec::new(),
device: None,
group: None,
opt_out: None,
class_name: None,
}
}
pub fn with_email(mut self, email: String) -> Self {
self.email = Some(email);
self
}
pub fn with_nickname(mut self, nickname: String) -> Self {
self.nickname = Some(nickname);
self
}
pub fn with_capabilities(mut self, capabilities: Vec<String>) -> Self {
self.capabilities = capabilities;
self
}
pub fn with_groups(mut self, groups: Vec<String>) -> Self {
self.groups = groups;
self
}
pub fn with_device(mut self, device: ContactDevice) -> Self {
self.device = Some(device);
self
}
pub fn has_capability(&self, capability: &str) -> bool {
self.capabilities.iter().any(|c| c == capability)
}
pub fn is_in_group(&self, group: &str) -> bool {
self.groups.iter().any(|g| g == group)
}
}
impl ContactDevice {
pub fn new(id: String, name: String) -> Self {
Self {
id,
name,
class_name: None,
meta: None,
}
}
pub fn with_meta(mut self, meta: BTreeMap<String, String>) -> Self {
self.meta = Some(meta);
self
}
pub fn with_class_name(mut self, class_name: String) -> Self {
self.class_name = Some(class_name);
self
}
}
impl std::fmt::Display for Contact {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Contact {{ id: {}, name: {}, primary: {}, organisation: {:?}, account: {:?} }}",
self.id, self.name, self.primary, self.organisation, self.account
)
}
}
impl std::fmt::Display for ContactDevice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ContactDevice {{ id: {}, name: {} }}", self.id, self.name)
}
}