use std::collections::BTreeMap;
use jmap_metadata_types::MetadataTextMatch;
use jmap_types::{Id, PatchObject, UTCDate, impl_string_enum};
use serde::{Deserialize, Serialize};
use crate::collision::{self, CollisionError};
const CONTACT_CARD_TYPED_FIELDS: &[&str] = &[
"id",
"addressBookIds",
"version",
"created",
"kind",
"language",
"members",
"prodId",
"relatedTo",
"uid",
"updated",
"name",
"nicknames",
"organizations",
"speakToAs",
"titles",
"emails",
"onlineServices",
"phones",
"preferredLanguages",
"calendars",
"schedulingAddresses",
"addresses",
"cryptoKeys",
"directories",
"links",
"media",
"localizations",
"anniversaries",
"keywords",
"notes",
"personalInfo",
"metadata",
"privateMetadata",
];
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContactCard {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<Id>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address_book_ids: Option<BTreeMap<Id, bool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub members: Option<BTreeMap<String, bool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prod_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub related_to: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nicknames: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub organizations: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub speak_to_as: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub titles: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub emails: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub online_services: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phones: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_languages: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub calendars: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scheduling_addresses: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub addresses: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub crypto_keys: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub directories: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub links: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub media: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub localizations: Option<BTreeMap<String, PatchObject>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub anniversaries: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<BTreeMap<String, bool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub personal_info: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Map<String, serde_json::Value>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub private_metadata: Option<serde_json::Map<String, serde_json::Value>>,
#[serde(flatten, default, skip_serializing_if = "serde_json::Map::is_empty")]
pub extra: serde_json::Map<String, serde_json::Value>,
}
impl ContactCard {
pub fn validate_extras(&self) -> Result<(), CollisionError> {
collision::check(&self.extra, CONTACT_CARD_TYPED_FIELDS)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ContactCardFilterCondition {
#[serde(skip_serializing_if = "Option::is_none")]
pub in_address_book: Option<Id>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_member: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_before: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_after: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_before: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_after: Option<UTCDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(rename = "name/given", skip_serializing_if = "Option::is_none")]
pub name_given: Option<String>,
#[serde(rename = "name/surname", skip_serializing_if = "Option::is_none")]
pub name_surname: Option<String>,
#[serde(rename = "name/surname2", skip_serializing_if = "Option::is_none")]
pub name_surname2: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nickname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub organization: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub online_service: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata_exists: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_metadata_exists: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata_text_contains: Option<MetadataTextMatch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_metadata_text_contains: Option<MetadataTextMatch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata_text_equals: Option<MetadataTextMatch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_metadata_text_equals: Option<MetadataTextMatch>,
}
impl ContactCardFilterCondition {
pub fn has_metadata_condition(&self) -> bool {
self.metadata_exists.is_some()
|| self.private_metadata_exists.is_some()
|| self.metadata_text_contains.is_some()
|| self.private_metadata_text_contains.is_some()
|| self.metadata_text_equals.is_some()
|| self.private_metadata_text_equals.is_some()
}
}
pub type ContactCardFilter = jmap_types::Filter<ContactCardFilterCondition>;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ContactCardComparatorProperty {
Created,
Updated,
NameGiven,
NameSurname,
NameSurname2,
Other(String),
}
impl_string_enum!(ContactCardComparatorProperty, "a ContactCard sort property string",
"created" => Created,
"updated" => Updated,
"name/given" => NameGiven,
"name/surname" => NameSurname,
"name/surname2" => NameSurname2,
);
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContactCardComparator {
pub property: ContactCardComparatorProperty,
#[serde(default = "bool_true", skip_serializing_if = "is_true")]
pub is_ascending: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub collation: Option<String>,
}
impl ContactCardComparator {
pub fn new(property: ContactCardComparatorProperty) -> Self {
Self {
property,
is_ascending: true,
collation: None,
}
}
}
fn bool_true() -> bool {
true
}
fn is_true(b: &bool) -> bool {
*b
}