122 lines
3.7 KiB
Rust
122 lines
3.7 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use crate::db::{Model, Storable, DB, DbError, DbResult};
|
|
use crate::models::mcc::event::Event;
|
|
use chrono::Utc;
|
|
|
|
/// Contact represents a contact entry in an address book
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Contact {
|
|
// Database ID
|
|
pub id: u32, // Database ID (assigned by DBHandler)
|
|
// Content fields
|
|
pub created_at: i64, // Unix epoch timestamp
|
|
pub modified_at: i64, // Unix epoch timestamp
|
|
pub first_name: String,
|
|
pub last_name: String,
|
|
pub email: String,
|
|
pub group: String, // Reference to a dns name, each group has a globally unique dns
|
|
pub groups: Vec<u32>, // Groups this contact belongs to (references Circle IDs)
|
|
}
|
|
|
|
impl Contact {
|
|
/// Create a new contact
|
|
pub fn new(id: u32, first_name: String, last_name: String, email: String, group: String) -> Self {
|
|
let now = Utc::now().timestamp();
|
|
Self {
|
|
id,
|
|
created_at: now,
|
|
modified_at: now,
|
|
first_name,
|
|
last_name,
|
|
email,
|
|
group,
|
|
groups: Vec::new(),
|
|
}
|
|
}
|
|
|
|
/// Add a group to this contact
|
|
pub fn add_group(&mut self, group_id: u32) {
|
|
if !self.groups.contains(&group_id) {
|
|
self.groups.push(group_id);
|
|
}
|
|
}
|
|
|
|
/// Remove a group from this contact
|
|
pub fn remove_group(&mut self, group_id: u32) {
|
|
self.groups.retain(|&id| id != group_id);
|
|
}
|
|
|
|
/// Filter by groups - returns true if this contact belongs to any of the specified groups
|
|
pub fn filter_by_groups(&self, groups: &[u32]) -> bool {
|
|
groups.iter().any(|g| self.groups.contains(g))
|
|
}
|
|
|
|
/// Search by name - returns true if the name contains the query (case-insensitive)
|
|
pub fn search_by_name(&self, query: &str) -> bool {
|
|
let full_name = self.full_name().to_lowercase();
|
|
query.to_lowercase().split_whitespace().all(|word| full_name.contains(word))
|
|
}
|
|
|
|
/// Search by email - returns true if the email contains the query (case-insensitive)
|
|
pub fn search_by_email(&self, query: &str) -> bool {
|
|
self.email.to_lowercase().contains(&query.to_lowercase())
|
|
}
|
|
|
|
/// Get events where this contact is an attendee
|
|
pub fn get_events(&self, db: &DB) -> DbResult<Vec<Event>> {
|
|
let all_events = db.list::<Event>()?;
|
|
let contact_events = all_events
|
|
.into_iter()
|
|
.filter(|event| event.attendees.contains(&self.email))
|
|
.collect();
|
|
|
|
Ok(contact_events)
|
|
}
|
|
|
|
/// Update the contact's information
|
|
pub fn update(&mut self, first_name: Option<String>, last_name: Option<String>, email: Option<String>, group: Option<String>) {
|
|
if let Some(first_name) = first_name {
|
|
self.first_name = first_name;
|
|
}
|
|
|
|
if let Some(last_name) = last_name {
|
|
self.last_name = last_name;
|
|
}
|
|
|
|
if let Some(email) = email {
|
|
self.email = email;
|
|
}
|
|
|
|
if let Some(group) = group {
|
|
self.group = group;
|
|
}
|
|
|
|
self.modified_at = Utc::now().timestamp();
|
|
}
|
|
|
|
/// Update the contact's groups
|
|
pub fn update_groups(&mut self, groups: Vec<u32>) {
|
|
self.groups = groups;
|
|
self.modified_at = Utc::now().timestamp();
|
|
}
|
|
|
|
/// Get the full name of the contact
|
|
pub fn full_name(&self) -> String {
|
|
format!("{} {}", self.first_name, self.last_name)
|
|
}
|
|
}
|
|
|
|
// Implement Storable trait (provides default dump/load)
|
|
impl Storable for Contact {}
|
|
|
|
// Implement SledModel trait
|
|
impl Model for Contact {
|
|
fn get_id(&self) -> u32 {
|
|
self.id
|
|
}
|
|
|
|
fn db_prefix() -> &'static str {
|
|
"contact"
|
|
}
|
|
}
|