cal-core 0.2.158

Callable core lib
Documentation
// File: cal-core/src/contact.rs

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,
        }
    }
}

// You can also implement it for references if needed
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
    }
}

// Display implementations
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)
    }
}