2025-04-13 01:04:04 +02:00
|
|
|
use chrono::{DateTime, NaiveDate, Utc};
|
2026-02-02 23:56:40 +01:00
|
|
|
use uuid::Uuid;
|
2025-04-13 01:04:04 +02:00
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct AddressBook {
|
2026-02-08 13:40:23 +01:00
|
|
|
id: Uuid,
|
|
|
|
|
name: String,
|
|
|
|
|
owner_id: String,
|
|
|
|
|
description: Option<String>,
|
|
|
|
|
color: Option<String>,
|
|
|
|
|
is_public: bool,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-02-08 13:40:23 +01:00
|
|
|
impl AddressBook {
|
|
|
|
|
/// Creates a new AddressBook with generated id and timestamps
|
|
|
|
|
pub fn new(
|
|
|
|
|
name: String,
|
|
|
|
|
owner_id: String,
|
|
|
|
|
description: Option<String>,
|
|
|
|
|
color: Option<String>,
|
|
|
|
|
is_public: bool,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let now = Utc::now();
|
2025-04-13 01:04:04 +02:00
|
|
|
Self {
|
|
|
|
|
id: Uuid::new_v4(),
|
2026-02-08 13:40:23 +01:00
|
|
|
name,
|
|
|
|
|
owner_id,
|
|
|
|
|
description,
|
|
|
|
|
color,
|
|
|
|
|
is_public,
|
|
|
|
|
created_at: now,
|
|
|
|
|
updated_at: now,
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
2026-02-15 17:53:25 +01:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2026-02-08 13:40:23 +01:00
|
|
|
pub fn from_raw(
|
|
|
|
|
id: Uuid,
|
|
|
|
|
name: String,
|
|
|
|
|
owner_id: String,
|
|
|
|
|
description: Option<String>,
|
|
|
|
|
color: Option<String>,
|
|
|
|
|
is_public: bool,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
|
|
|
|
) -> Self {
|
2026-02-14 01:29:34 +01:00
|
|
|
Self {
|
|
|
|
|
id,
|
|
|
|
|
name,
|
|
|
|
|
owner_id,
|
|
|
|
|
description,
|
|
|
|
|
color,
|
|
|
|
|
is_public,
|
|
|
|
|
created_at,
|
|
|
|
|
updated_at,
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Getters ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn id(&self) -> &Uuid {
|
|
|
|
|
&self.id
|
|
|
|
|
}
|
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
pub fn owner_id(&self) -> &str {
|
|
|
|
|
&self.owner_id
|
|
|
|
|
}
|
|
|
|
|
pub fn description(&self) -> Option<&str> {
|
|
|
|
|
self.description.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn color(&self) -> Option<&str> {
|
|
|
|
|
self.color.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn is_public(&self) -> bool {
|
|
|
|
|
self.is_public
|
|
|
|
|
}
|
|
|
|
|
pub fn created_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.created_at
|
|
|
|
|
}
|
|
|
|
|
pub fn updated_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.updated_at
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Setters for mutable operations ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn set_name(&mut self, name: String) {
|
|
|
|
|
self.name = name;
|
|
|
|
|
self.updated_at = Utc::now();
|
|
|
|
|
}
|
|
|
|
|
pub fn set_description(&mut self, description: Option<String>) {
|
|
|
|
|
self.description = description;
|
|
|
|
|
self.updated_at = Utc::now();
|
|
|
|
|
}
|
|
|
|
|
pub fn set_color(&mut self, color: Option<String>) {
|
|
|
|
|
self.color = color;
|
|
|
|
|
self.updated_at = Utc::now();
|
|
|
|
|
}
|
|
|
|
|
pub fn set_is_public(&mut self, is_public: bool) {
|
|
|
|
|
self.is_public = is_public;
|
|
|
|
|
self.updated_at = Utc::now();
|
|
|
|
|
}
|
|
|
|
|
pub fn set_updated_at(&mut self, updated_at: DateTime<Utc>) {
|
|
|
|
|
self.updated_at = updated_at;
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for AddressBook {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::new(
|
|
|
|
|
"Default Address Book".to_string(),
|
|
|
|
|
"default".to_string(),
|
|
|
|
|
None,
|
|
|
|
|
None,
|
|
|
|
|
false,
|
|
|
|
|
)
|
|
|
|
|
}
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct Email {
|
|
|
|
|
pub email: String,
|
|
|
|
|
pub r#type: String, // home, work, other
|
|
|
|
|
pub is_primary: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct Phone {
|
|
|
|
|
pub number: String,
|
|
|
|
|
pub r#type: String, // mobile, home, work, fax, other
|
|
|
|
|
pub is_primary: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct Address {
|
|
|
|
|
pub street: Option<String>,
|
|
|
|
|
pub city: Option<String>,
|
|
|
|
|
pub state: Option<String>,
|
|
|
|
|
pub postal_code: Option<String>,
|
|
|
|
|
pub country: Option<String>,
|
|
|
|
|
pub r#type: String, // home, work, other
|
|
|
|
|
pub is_primary: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct Contact {
|
2026-02-08 13:40:23 +01:00
|
|
|
id: Uuid,
|
|
|
|
|
address_book_id: Uuid,
|
|
|
|
|
uid: String,
|
|
|
|
|
full_name: Option<String>,
|
|
|
|
|
first_name: Option<String>,
|
|
|
|
|
last_name: Option<String>,
|
|
|
|
|
nickname: Option<String>,
|
|
|
|
|
email: Vec<Email>,
|
|
|
|
|
phone: Vec<Phone>,
|
|
|
|
|
address: Vec<Address>,
|
|
|
|
|
organization: Option<String>,
|
|
|
|
|
title: Option<String>,
|
|
|
|
|
notes: Option<String>,
|
|
|
|
|
photo_url: Option<String>,
|
|
|
|
|
birthday: Option<NaiveDate>,
|
|
|
|
|
anniversary: Option<NaiveDate>,
|
|
|
|
|
vcard: String,
|
|
|
|
|
etag: String,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Contact {
|
|
|
|
|
/// Creates a new Contact with generated id, uid, etag and timestamps
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
|
pub fn new(
|
|
|
|
|
address_book_id: Uuid,
|
|
|
|
|
full_name: Option<String>,
|
|
|
|
|
first_name: Option<String>,
|
|
|
|
|
last_name: Option<String>,
|
|
|
|
|
nickname: Option<String>,
|
|
|
|
|
email: Vec<Email>,
|
|
|
|
|
phone: Vec<Phone>,
|
|
|
|
|
address: Vec<Address>,
|
|
|
|
|
organization: Option<String>,
|
|
|
|
|
title: Option<String>,
|
|
|
|
|
notes: Option<String>,
|
|
|
|
|
photo_url: Option<String>,
|
|
|
|
|
birthday: Option<NaiveDate>,
|
|
|
|
|
anniversary: Option<NaiveDate>,
|
|
|
|
|
vcard: String,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let now = Utc::now();
|
|
|
|
|
Self {
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
address_book_id,
|
|
|
|
|
uid: format!("{}@oxicloud", Uuid::new_v4()),
|
|
|
|
|
full_name,
|
|
|
|
|
first_name,
|
|
|
|
|
last_name,
|
|
|
|
|
nickname,
|
|
|
|
|
email,
|
|
|
|
|
phone,
|
|
|
|
|
address,
|
|
|
|
|
organization,
|
|
|
|
|
title,
|
|
|
|
|
notes,
|
|
|
|
|
photo_url,
|
|
|
|
|
birthday,
|
|
|
|
|
anniversary,
|
|
|
|
|
vcard,
|
|
|
|
|
etag: Uuid::new_v4().to_string(),
|
|
|
|
|
created_at: now,
|
|
|
|
|
updated_at: now,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reconstructs from persistence (no validation)
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
|
pub fn from_raw(
|
|
|
|
|
id: Uuid,
|
|
|
|
|
address_book_id: Uuid,
|
|
|
|
|
uid: String,
|
|
|
|
|
full_name: Option<String>,
|
|
|
|
|
first_name: Option<String>,
|
|
|
|
|
last_name: Option<String>,
|
|
|
|
|
nickname: Option<String>,
|
|
|
|
|
email: Vec<Email>,
|
|
|
|
|
phone: Vec<Phone>,
|
|
|
|
|
address: Vec<Address>,
|
|
|
|
|
organization: Option<String>,
|
|
|
|
|
title: Option<String>,
|
|
|
|
|
notes: Option<String>,
|
|
|
|
|
photo_url: Option<String>,
|
|
|
|
|
birthday: Option<NaiveDate>,
|
|
|
|
|
anniversary: Option<NaiveDate>,
|
|
|
|
|
vcard: String,
|
|
|
|
|
etag: String,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
2026-02-14 01:29:34 +01:00
|
|
|
id,
|
|
|
|
|
address_book_id,
|
|
|
|
|
uid,
|
|
|
|
|
full_name,
|
|
|
|
|
first_name,
|
|
|
|
|
last_name,
|
|
|
|
|
nickname,
|
|
|
|
|
email,
|
|
|
|
|
phone,
|
|
|
|
|
address,
|
|
|
|
|
organization,
|
|
|
|
|
title,
|
|
|
|
|
notes,
|
|
|
|
|
photo_url,
|
|
|
|
|
birthday,
|
|
|
|
|
anniversary,
|
|
|
|
|
vcard,
|
|
|
|
|
etag,
|
|
|
|
|
created_at,
|
|
|
|
|
updated_at,
|
2026-02-08 13:40:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Getters ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn id(&self) -> &Uuid {
|
|
|
|
|
&self.id
|
|
|
|
|
}
|
|
|
|
|
pub fn address_book_id(&self) -> &Uuid {
|
|
|
|
|
&self.address_book_id
|
|
|
|
|
}
|
|
|
|
|
pub fn uid(&self) -> &str {
|
|
|
|
|
&self.uid
|
|
|
|
|
}
|
|
|
|
|
pub fn full_name(&self) -> Option<&str> {
|
|
|
|
|
self.full_name.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn first_name(&self) -> Option<&str> {
|
|
|
|
|
self.first_name.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn last_name(&self) -> Option<&str> {
|
|
|
|
|
self.last_name.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn nickname(&self) -> Option<&str> {
|
|
|
|
|
self.nickname.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn email(&self) -> &[Email] {
|
|
|
|
|
&self.email
|
|
|
|
|
}
|
|
|
|
|
pub fn phone(&self) -> &[Phone] {
|
|
|
|
|
&self.phone
|
|
|
|
|
}
|
|
|
|
|
pub fn address(&self) -> &[Address] {
|
|
|
|
|
&self.address
|
|
|
|
|
}
|
|
|
|
|
pub fn organization(&self) -> Option<&str> {
|
|
|
|
|
self.organization.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn title(&self) -> Option<&str> {
|
|
|
|
|
self.title.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn notes(&self) -> Option<&str> {
|
|
|
|
|
self.notes.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn photo_url(&self) -> Option<&str> {
|
|
|
|
|
self.photo_url.as_deref()
|
|
|
|
|
}
|
|
|
|
|
pub fn birthday(&self) -> Option<&NaiveDate> {
|
|
|
|
|
self.birthday.as_ref()
|
|
|
|
|
}
|
|
|
|
|
pub fn anniversary(&self) -> Option<&NaiveDate> {
|
|
|
|
|
self.anniversary.as_ref()
|
|
|
|
|
}
|
|
|
|
|
pub fn vcard(&self) -> &str {
|
|
|
|
|
&self.vcard
|
|
|
|
|
}
|
|
|
|
|
pub fn etag(&self) -> &str {
|
|
|
|
|
&self.etag
|
|
|
|
|
}
|
|
|
|
|
pub fn created_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.created_at
|
|
|
|
|
}
|
|
|
|
|
pub fn updated_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.updated_at
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Owned getters for persistence layer bind() calls ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn full_name_owned(&self) -> Option<String> {
|
|
|
|
|
self.full_name.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn first_name_owned(&self) -> Option<String> {
|
|
|
|
|
self.first_name.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn last_name_owned(&self) -> Option<String> {
|
|
|
|
|
self.last_name.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn nickname_owned(&self) -> Option<String> {
|
|
|
|
|
self.nickname.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn organization_owned(&self) -> Option<String> {
|
|
|
|
|
self.organization.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn title_owned(&self) -> Option<String> {
|
|
|
|
|
self.title.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn notes_owned(&self) -> Option<String> {
|
|
|
|
|
self.notes.clone()
|
|
|
|
|
}
|
|
|
|
|
pub fn photo_url_owned(&self) -> Option<String> {
|
|
|
|
|
self.photo_url.clone()
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Setters for mutable operations (contact_service.rs needs these) ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn set_full_name(&mut self, v: Option<String>) {
|
|
|
|
|
self.full_name = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_first_name(&mut self, v: Option<String>) {
|
|
|
|
|
self.first_name = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_last_name(&mut self, v: Option<String>) {
|
|
|
|
|
self.last_name = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_nickname(&mut self, v: Option<String>) {
|
|
|
|
|
self.nickname = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_organization(&mut self, v: Option<String>) {
|
|
|
|
|
self.organization = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_title(&mut self, v: Option<String>) {
|
|
|
|
|
self.title = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_notes(&mut self, v: Option<String>) {
|
|
|
|
|
self.notes = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_photo_url(&mut self, v: Option<String>) {
|
|
|
|
|
self.photo_url = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_birthday(&mut self, v: Option<NaiveDate>) {
|
|
|
|
|
self.birthday = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_anniversary(&mut self, v: Option<NaiveDate>) {
|
|
|
|
|
self.anniversary = v;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_vcard(&mut self, vcard: String) {
|
|
|
|
|
self.vcard = vcard;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_etag(&mut self, etag: String) {
|
|
|
|
|
self.etag = etag;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_updated_at(&mut self, updated_at: DateTime<Utc>) {
|
|
|
|
|
self.updated_at = updated_at;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_address_book_id(&mut self, id: Uuid) {
|
|
|
|
|
self.address_book_id = id;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_uid(&mut self, uid: String) {
|
|
|
|
|
self.uid = uid;
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Collection mutators ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn push_email(&mut self, e: Email) {
|
|
|
|
|
self.email.push(e);
|
|
|
|
|
}
|
|
|
|
|
pub fn push_phone(&mut self, p: Phone) {
|
|
|
|
|
self.phone.push(p);
|
|
|
|
|
}
|
|
|
|
|
pub fn set_email(&mut self, email: Vec<Email>) {
|
|
|
|
|
self.email = email;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_phone(&mut self, phone: Vec<Phone>) {
|
|
|
|
|
self.phone = phone;
|
|
|
|
|
}
|
|
|
|
|
pub fn set_address(&mut self, address: Vec<Address>) {
|
|
|
|
|
self.address = address;
|
|
|
|
|
}
|
|
|
|
|
pub fn email_is_empty(&self) -> bool {
|
|
|
|
|
self.email.is_empty()
|
|
|
|
|
}
|
|
|
|
|
pub fn phone_is_empty(&self) -> bool {
|
|
|
|
|
self.phone.is_empty()
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Consuming methods for ownership transfer ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn into_email(self) -> Vec<Email> {
|
|
|
|
|
self.email
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
pub fn into_parts(self) -> ContactParts {
|
|
|
|
|
ContactParts {
|
|
|
|
|
id: self.id,
|
|
|
|
|
address_book_id: self.address_book_id,
|
|
|
|
|
uid: self.uid,
|
|
|
|
|
full_name: self.full_name,
|
|
|
|
|
first_name: self.first_name,
|
|
|
|
|
last_name: self.last_name,
|
|
|
|
|
nickname: self.nickname,
|
|
|
|
|
email: self.email,
|
|
|
|
|
phone: self.phone,
|
|
|
|
|
address: self.address,
|
|
|
|
|
organization: self.organization,
|
|
|
|
|
title: self.title,
|
|
|
|
|
notes: self.notes,
|
|
|
|
|
photo_url: self.photo_url,
|
|
|
|
|
birthday: self.birthday,
|
|
|
|
|
anniversary: self.anniversary,
|
|
|
|
|
vcard: self.vcard,
|
|
|
|
|
etag: self.etag,
|
|
|
|
|
created_at: self.created_at,
|
|
|
|
|
updated_at: self.updated_at,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Holds all Contact fields by value, for when ownership transfer is needed
|
|
|
|
|
pub struct ContactParts {
|
2025-04-13 01:04:04 +02:00
|
|
|
pub id: Uuid,
|
|
|
|
|
pub address_book_id: Uuid,
|
|
|
|
|
pub uid: String,
|
|
|
|
|
pub full_name: Option<String>,
|
|
|
|
|
pub first_name: Option<String>,
|
|
|
|
|
pub last_name: Option<String>,
|
|
|
|
|
pub nickname: Option<String>,
|
|
|
|
|
pub email: Vec<Email>,
|
|
|
|
|
pub phone: Vec<Phone>,
|
|
|
|
|
pub address: Vec<Address>,
|
|
|
|
|
pub organization: Option<String>,
|
|
|
|
|
pub title: Option<String>,
|
|
|
|
|
pub notes: Option<String>,
|
|
|
|
|
pub photo_url: Option<String>,
|
|
|
|
|
pub birthday: Option<NaiveDate>,
|
|
|
|
|
pub anniversary: Option<NaiveDate>,
|
|
|
|
|
pub vcard: String,
|
|
|
|
|
pub etag: String,
|
|
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
pub updated_at: DateTime<Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Contact {
|
|
|
|
|
fn default() -> Self {
|
2026-02-08 13:40:23 +01:00
|
|
|
let now = Utc::now();
|
2025-04-13 01:04:04 +02:00
|
|
|
Self {
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
address_book_id: Uuid::new_v4(),
|
|
|
|
|
uid: format!("{}@oxicloud", Uuid::new_v4()),
|
|
|
|
|
full_name: None,
|
|
|
|
|
first_name: None,
|
|
|
|
|
last_name: None,
|
|
|
|
|
nickname: None,
|
|
|
|
|
email: Vec::new(),
|
|
|
|
|
phone: Vec::new(),
|
|
|
|
|
address: Vec::new(),
|
|
|
|
|
organization: None,
|
|
|
|
|
title: None,
|
|
|
|
|
notes: None,
|
|
|
|
|
photo_url: None,
|
|
|
|
|
birthday: None,
|
|
|
|
|
anniversary: None,
|
|
|
|
|
vcard: "BEGIN:VCARD\nVERSION:3.0\nEND:VCARD".to_string(),
|
|
|
|
|
etag: Uuid::new_v4().to_string(),
|
2026-02-08 13:40:23 +01:00
|
|
|
created_at: now,
|
|
|
|
|
updated_at: now,
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 23:56:40 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2025-04-13 01:04:04 +02:00
|
|
|
pub struct ContactGroup {
|
2026-02-08 13:40:23 +01:00
|
|
|
id: Uuid,
|
|
|
|
|
address_book_id: Uuid,
|
|
|
|
|
name: String,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ContactGroup {
|
|
|
|
|
/// Creates a new ContactGroup with generated id and timestamps
|
|
|
|
|
pub fn new(address_book_id: Uuid, name: String) -> Self {
|
|
|
|
|
let now = Utc::now();
|
2026-02-14 01:29:34 +01:00
|
|
|
Self {
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
address_book_id,
|
|
|
|
|
name,
|
|
|
|
|
created_at: now,
|
|
|
|
|
updated_at: now,
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reconstructs from persistence
|
|
|
|
|
pub fn from_raw(
|
|
|
|
|
id: Uuid,
|
|
|
|
|
address_book_id: Uuid,
|
|
|
|
|
name: String,
|
|
|
|
|
created_at: DateTime<Utc>,
|
|
|
|
|
updated_at: DateTime<Utc>,
|
|
|
|
|
) -> Self {
|
2026-02-14 01:29:34 +01:00
|
|
|
Self {
|
|
|
|
|
id,
|
|
|
|
|
address_book_id,
|
|
|
|
|
name,
|
|
|
|
|
created_at,
|
|
|
|
|
updated_at,
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Getters ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn id(&self) -> &Uuid {
|
|
|
|
|
&self.id
|
|
|
|
|
}
|
|
|
|
|
pub fn address_book_id(&self) -> &Uuid {
|
|
|
|
|
&self.address_book_id
|
|
|
|
|
}
|
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
pub fn created_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.created_at
|
|
|
|
|
}
|
|
|
|
|
pub fn updated_at(&self) -> &DateTime<Utc> {
|
|
|
|
|
&self.updated_at
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
// --- Setters ---
|
2026-02-14 01:29:34 +01:00
|
|
|
pub fn set_name(&mut self, name: String) {
|
|
|
|
|
self.name = name;
|
|
|
|
|
self.updated_at = Utc::now();
|
|
|
|
|
}
|
|
|
|
|
pub fn set_updated_at(&mut self, updated_at: DateTime<Utc>) {
|
|
|
|
|
self.updated_at = updated_at;
|
|
|
|
|
}
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for ContactGroup {
|
|
|
|
|
fn default() -> Self {
|
2026-02-08 13:40:23 +01:00
|
|
|
ContactGroup::new(Uuid::new_v4(), "New Group".to_string())
|
2025-04-13 01:04:04 +02:00
|
|
|
}
|
2026-02-14 01:29:34 +01:00
|
|
|
}
|