use jmap_types::{GetObject, JmapObject, PatchObject, QueryObject, SetObject};
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AddressBookProperty {
Id,
Name,
Description,
SortOrder,
IsDefault,
IsSubscribed,
ShareWith,
MyRights,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ContactCardProperty {
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,
}
impl JmapObject for crate::AddressBook {
const TYPE_NAME: &'static str = "AddressBook";
type Property = AddressBookProperty;
}
impl GetObject for crate::AddressBook {}
impl SetObject for crate::AddressBook {
type Patch = PatchObject;
const SERVER_SET: &'static [&'static str] = &["id", "isDefault", "myRights"];
const CLIENT_SETTABLE: &'static [&'static str] = &[
"name",
"description",
"sortOrder",
"isSubscribed",
"shareWith",
"metadata",
"privateMetadata",
];
const IMMUTABLE: &'static [&'static str] = &[];
}
impl JmapObject for crate::ContactCard {
const TYPE_NAME: &'static str = "ContactCard";
type Property = ContactCardProperty;
}
impl GetObject for crate::ContactCard {}
impl SetObject for crate::ContactCard {
type Patch = PatchObject;
const SERVER_SET: &'static [&'static str] = &["id"];
const CLIENT_SETTABLE: &'static [&'static str] = &[
"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",
];
const IMMUTABLE: &'static [&'static str] = &[];
}
impl QueryObject for crate::ContactCard {
type Filter = crate::ContactCardFilter;
type Comparator = crate::ContactCardComparator;
}
#[cfg(test)]
mod tests {
use jmap_types::{Id, PatchObject, UTCDate, check_property_classification};
use serde_json::{Map, Value, json};
use std::collections::BTreeMap;
fn de<T: serde::de::DeserializeOwned>(v: Value) -> T {
serde_json::from_value(v).expect("hand-written fixture deserializes")
}
fn rights() -> crate::AddressBookRights {
de(json!({"mayRead": true, "mayWrite": true, "mayShare": true, "mayDelete": true}))
}
#[test]
fn address_book_properties_are_classified() {
let obj = crate::AddressBook {
id: Id::from("a1"),
name: "n".into(),
description: Some("d".into()),
sort_order: 1,
is_default: true,
is_subscribed: true,
share_with: Some(BTreeMap::from([(Id::from("p1"), rights())])),
my_rights: rights(),
metadata: Some(de(json!({"acme.example.com": {"memo": "m"}}))),
private_metadata: Some(de(json!({"acme.example.com": {"memo": "p"}}))),
extra: Map::new(),
};
assert_eq!(check_property_classification(&obj), Ok(()));
}
#[test]
fn contact_card_properties_are_classified() {
let v = || Some(json!({}));
let patch: PatchObject = de(json!({"name/full": "N"}));
let obj = crate::ContactCard {
id: Some(Id::from("c1")),
address_book_ids: Some(BTreeMap::from([(Id::from("a1"), true)])),
version: Some("1.0".into()),
created: Some(UTCDate::from("2026-01-01T00:00:00Z")),
kind: Some("individual".into()),
language: Some("en".into()),
members: Some(BTreeMap::from([("u2".into(), true)])),
prod_id: Some("p".into()),
related_to: v(),
uid: Some("u".into()),
updated: Some(UTCDate::from("2026-01-01T00:00:00Z")),
name: v(),
nicknames: v(),
organizations: v(),
speak_to_as: v(),
titles: v(),
emails: v(),
online_services: v(),
phones: v(),
preferred_languages: v(),
calendars: v(),
scheduling_addresses: v(),
addresses: v(),
crypto_keys: v(),
directories: v(),
links: v(),
media: v(),
localizations: Some(BTreeMap::from([("de".into(), patch)])),
anniversaries: v(),
keywords: Some(BTreeMap::from([("k".into(), true)])),
notes: v(),
personal_info: v(),
metadata: Some(de(json!({"acme.example.com": {"memo": "m"}}))),
private_metadata: Some(de(json!({"acme.example.com": {"memo": "p"}}))),
extra: Map::new(),
};
assert_eq!(check_property_classification(&obj), Ok(()));
}
}