cal_core/
user.rs

1// File: cal-core/src/user.rs
2
3use crate::{object_id_as_string, RecordReference};
4use bson::DateTime;
5use serde::{Deserialize, Deserializer, Serialize};
6#[cfg(feature = "openapi")]
7use utoipa::ToSchema;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[cfg_attr(feature = "openapi", derive(ToSchema))]
11pub struct User {
12    #[serde(deserialize_with = "object_id_as_string", rename = "_id")]
13    pub id: String,
14    pub email: String,
15    pub password: String,
16    #[serde(rename = "firstName")]
17    pub first_name: String,
18    #[serde(rename = "lastName")]
19    pub last_name: String,
20    pub groups: Vec<String>,
21    pub account: RecordReference,
22    #[serde(default)]
23    pub customers: Vec<RecordReference>,
24    #[serde(rename = "emailVerified", default)]
25    pub email_verified: bool,
26    #[serde(rename = "recordingFilter", skip_serializing_if = "Option::is_none")]
27    pub recording_filter: Option<RecordingFilter>,
28    #[serde(rename = "lastLogin", skip_serializing_if = "Option::is_none")]
29    pub last_login: Option<DateTime>,
30    #[serde(rename = "agentSettings", skip_serializing_if = "Option::is_none")]
31    pub agent_settings: Option<AgentSettings>,
32    #[serde(rename = "_class", skip_serializing_if = "Option::is_none")]
33    pub class: Option<String>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct UserLite {
38    pub id: String,
39    pub email: String,
40    #[serde(rename = "firstName")]
41    pub first_name: String,
42    #[serde(rename = "lastName")]
43    pub last_name: String,
44    pub groups: Vec<String>,
45    pub account: RecordReference,
46    #[serde(default)]
47    pub customers: Vec<RecordReference>,
48}
49
50impl From<User> for UserLite {
51    fn from(user: User) -> Self {
52        UserLite {
53            id: user.id.clone(),
54            email: user.email,
55            first_name: user.first_name,
56            last_name: user.last_name,
57            groups: user.groups,
58            account: user.account,
59            customers: user.customers,
60        }
61    }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct RecordingFilter {
66    #[serde(default)]
67    pub caller: String,
68    #[serde(default)]
69    pub called: String,
70    #[serde(default)]
71    pub extension: String,
72}
73
74// Create a flexible type that can handle any value
75#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(untagged)]
77pub enum FlexibleValue {
78    String(String),
79    RecordReference(RecordReference),
80    Other(serde_json::Value), // Catch any other type
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct AgentSettings {
85    #[serde(rename = "agentName", skip_serializing_if = "Option::is_none")]
86    pub agent_name: Option<String>,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub ddi: Option<RecordReference>,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub whatsapp: Option<RecordReference>,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub client: Option<RecordReference>,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub account: Option<RecordReference>,
95    #[serde(default, deserialize_with = "deserialize_flexible_vec")]
96    pub favourites: Vec<RecordReference>,
97    #[serde(default, deserialize_with = "deserialize_flexible_vec")]
98    pub apps: Vec<RecordReference>,
99    #[serde(default, deserialize_with = "deserialize_flexible_vec")]
100    pub channels: Vec<RecordReference>,
101    #[serde(rename = "contactGroups", default, deserialize_with = "deserialize_flexible_vec")]
102    pub contact_groups: Vec<RecordReference>,
103    #[serde(default)]
104    pub queues: Vec<RecordReference>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub park: Option<RecordReference>,
107    #[serde(default = "default_status")]
108    pub status: String,
109    #[serde(rename = "wrapUpTime", default = "default_wrap_up_time")]
110    pub wrap_up_time: i32,
111    #[serde(rename = "representTime", default = "default_represent_time")]
112    pub represent_time: i32,
113    #[serde(rename = "notifyTime", default = "default_notify_time")]
114    pub notify_time: i32,
115    #[serde(rename = "autoAnswer", default)]
116    pub auto_answer: bool,
117    #[serde(default)]
118    pub wall_boards: Vec<String>,
119    #[serde(rename = "wallboardRotateTime", default = "default_wallboard_rotate_time")]
120    pub wallboard_rotate_time: i32,
121    #[serde(rename = "disableNotifyAudio", default)]
122    pub disable_notify_audio: bool,
123    #[serde(default)]
124    pub disposition: bool,
125    #[serde(default)]
126    pub transcribe: bool,
127    #[serde(default)]
128    pub summary: bool,
129}
130
131// More flexible deserializer that handles any type
132fn deserialize_flexible_vec<'de, D>(deserializer: D) -> Result<Vec<RecordReference>, D::Error>
133where
134    D: Deserializer<'de>,
135{
136    // First, try to deserialize as an Option to handle null/missing values
137    let opt_items: Option<Vec<FlexibleValue>> = Option::deserialize(deserializer)?;
138
139    match opt_items {
140        None => Ok(Vec::new()),
141        Some(items) => {
142            Ok(items.into_iter().filter_map(|item| {
143                match item {
144                    FlexibleValue::RecordReference(r) => Some(r),
145                    FlexibleValue::String(_) => None, // Skip string values
146                    FlexibleValue::Other(_) => None,  // Skip any other values
147                }
148            }).collect())
149        }
150    }
151}
152
153// Default value functions
154fn default_status() -> String {
155    "available".to_string()
156}
157
158fn default_wrap_up_time() -> i32 {
159    5
160}
161
162fn default_represent_time() -> i32 {
163    5
164}
165
166fn default_notify_time() -> i32 {
167    6
168}
169
170fn default_wallboard_rotate_time() -> i32 {
171    30
172}