jmap_client/core/
set.rs

1/*
2 * Copyright Stalwart Labs LLC See the COPYING
3 * file at the top-level directory of this distribution.
4 *
5 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8 * option. This file may not be copied, modified, or distributed
9 * except according to those terms.
10 */
11
12use crate::Error;
13use ahash::AHashMap;
14use chrono::{DateTime, Utc};
15use serde::{Deserialize, Serialize};
16use std::fmt::{self, Display, Formatter};
17
18use super::{request::ResultReference, Object, RequestParams};
19
20pub trait SetObject: Object {
21    type SetArguments: Default;
22
23    fn new(create_id: Option<usize>) -> Self;
24    fn create_id(&self) -> Option<String>;
25}
26
27#[derive(Debug, Clone, Serialize)]
28pub struct SetRequest<O: SetObject> {
29    #[serde(rename = "accountId")]
30    #[serde(skip_serializing_if = "Option::is_none")]
31    account_id: Option<String>,
32
33    #[serde(rename = "ifInState")]
34    #[serde(skip_serializing_if = "Option::is_none")]
35    if_in_state: Option<String>,
36
37    #[serde(skip_serializing_if = "Option::is_none")]
38    create: Option<AHashMap<String, O>>,
39
40    #[serde(skip_serializing_if = "Option::is_none")]
41    update: Option<AHashMap<String, O>>,
42
43    #[serde(skip_serializing_if = "Option::is_none")]
44    destroy: Option<Vec<String>>,
45
46    #[serde(rename = "#destroy")]
47    #[serde(skip_deserializing)]
48    #[serde(skip_serializing_if = "Option::is_none")]
49    destroy_ref: Option<ResultReference>,
50
51    #[serde(flatten)]
52    arguments: O::SetArguments,
53}
54
55#[derive(Debug, Clone, Deserialize)]
56pub struct SetResponse<O: SetObject> {
57    #[serde(rename = "accountId")]
58    account_id: Option<String>,
59
60    #[serde(rename = "oldState")]
61    old_state: Option<String>,
62
63    #[serde(rename = "newState")]
64    new_state: Option<String>,
65
66    #[serde(rename = "created")]
67    created: Option<AHashMap<String, O>>,
68
69    #[serde(rename = "updated")]
70    updated: Option<AHashMap<String, Option<O>>>,
71
72    #[serde(rename = "destroyed")]
73    destroyed: Option<Vec<String>>,
74
75    #[serde(rename = "notCreated")]
76    not_created: Option<AHashMap<String, SetError<O::Property>>>,
77
78    #[serde(rename = "notUpdated")]
79    not_updated: Option<AHashMap<String, SetError<O::Property>>>,
80
81    #[serde(rename = "notDestroyed")]
82    not_destroyed: Option<AHashMap<String, SetError<O::Property>>>,
83}
84
85#[derive(Debug, Clone, Deserialize)]
86pub struct SetError<U>
87where
88    U: Display,
89{
90    #[serde(rename = "type")]
91    pub type_: SetErrorType,
92    description: Option<String>,
93    properties: Option<Vec<U>>,
94}
95
96#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
97pub enum SetErrorType {
98    #[serde(rename = "forbidden")]
99    Forbidden,
100    #[serde(rename = "overQuota")]
101    OverQuota,
102    #[serde(rename = "tooLarge")]
103    TooLarge,
104    #[serde(rename = "rateLimit")]
105    RateLimit,
106    #[serde(rename = "notFound")]
107    NotFound,
108    #[serde(rename = "invalidPatch")]
109    InvalidPatch,
110    #[serde(rename = "willDestroy")]
111    WillDestroy,
112    #[serde(rename = "invalidProperties")]
113    InvalidProperties,
114    #[serde(rename = "singleton")]
115    Singleton,
116    #[serde(rename = "mailboxHasChild")]
117    MailboxHasChild,
118    #[serde(rename = "mailboxHasEmail")]
119    MailboxHasEmail,
120    #[serde(rename = "blobNotFound")]
121    BlobNotFound,
122    #[serde(rename = "tooManyKeywords")]
123    TooManyKeywords,
124    #[serde(rename = "tooManyMailboxes")]
125    TooManyMailboxes,
126    #[serde(rename = "forbiddenFrom")]
127    ForbiddenFrom,
128    #[serde(rename = "invalidEmail")]
129    InvalidEmail,
130    #[serde(rename = "tooManyRecipients")]
131    TooManyRecipients,
132    #[serde(rename = "noRecipients")]
133    NoRecipients,
134    #[serde(rename = "invalidRecipients")]
135    InvalidRecipients,
136    #[serde(rename = "forbiddenMailFrom")]
137    ForbiddenMailFrom,
138    #[serde(rename = "forbiddenToSend")]
139    ForbiddenToSend,
140    #[serde(rename = "cannotUnsend")]
141    CannotUnsend,
142    #[serde(rename = "alreadyExists")]
143    AlreadyExists,
144    #[serde(rename = "invalidScript")]
145    InvalidScript,
146    #[serde(rename = "scriptIsActive")]
147    ScriptIsActive,
148}
149
150impl<O: SetObject> SetRequest<O> {
151    pub fn new(params: RequestParams) -> Self {
152        Self {
153            account_id: if O::requires_account_id() {
154                params.account_id.into()
155            } else {
156                None
157            },
158            if_in_state: None,
159            create: None,
160            update: None,
161            destroy: None,
162            destroy_ref: None,
163            arguments: Default::default(),
164        }
165    }
166
167    pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
168        if O::requires_account_id() {
169            self.account_id = Some(account_id.into());
170        }
171        self
172    }
173
174    pub fn if_in_state(&mut self, if_in_state: impl Into<String>) -> &mut Self {
175        self.if_in_state = Some(if_in_state.into());
176        self
177    }
178
179    pub fn create(&mut self) -> &mut O {
180        let create_id = self.create.as_ref().map_or(0, |c| c.len());
181        let create_id_str = format!("c{}", create_id);
182        self.create
183            .get_or_insert_with(AHashMap::new)
184            .insert(create_id_str.clone(), O::new(create_id.into()));
185        self.create
186            .as_mut()
187            .unwrap()
188            .get_mut(&create_id_str)
189            .unwrap()
190    }
191
192    pub fn create_with_id(&mut self, create_id: impl Into<String>) -> &mut O {
193        let create_id = create_id.into();
194        self.create
195            .get_or_insert_with(AHashMap::new)
196            .insert(create_id.clone(), O::new(0.into()));
197        self.create.as_mut().unwrap().get_mut(&create_id).unwrap()
198    }
199
200    pub fn create_item(&mut self, item: O) -> String {
201        let create_id = self.create.as_ref().map_or(0, |c| c.len());
202        let create_id_str = format!("c{}", create_id);
203        self.create
204            .get_or_insert_with(AHashMap::new)
205            .insert(create_id_str.clone(), item);
206        create_id_str
207    }
208
209    pub fn update(&mut self, id: impl Into<String>) -> &mut O {
210        let id: String = id.into();
211        self.update
212            .get_or_insert_with(AHashMap::new)
213            .insert(id.clone(), O::new(None));
214        self.update.as_mut().unwrap().get_mut(&id).unwrap()
215    }
216
217    pub fn update_item(&mut self, id: impl Into<String>, item: O) {
218        self.update
219            .get_or_insert_with(AHashMap::new)
220            .insert(id.into(), item);
221    }
222
223    pub fn destroy<U, V>(&mut self, ids: U) -> &mut Self
224    where
225        U: IntoIterator<Item = V>,
226        V: Into<String>,
227    {
228        self.destroy
229            .get_or_insert_with(Vec::new)
230            .extend(ids.into_iter().map(|id| id.into()));
231        self.destroy_ref = None;
232        self
233    }
234
235    pub fn destroy_ref(&mut self, reference: ResultReference) -> &mut Self {
236        self.destroy_ref = reference.into();
237        self.destroy = None;
238        self
239    }
240
241    pub fn arguments(&mut self) -> &mut O::SetArguments {
242        &mut self.arguments
243    }
244}
245
246impl<O: SetObject> SetResponse<O> {
247    pub fn account_id(&self) -> Option<&str> {
248        self.account_id.as_deref()
249    }
250
251    pub fn old_state(&self) -> Option<&str> {
252        self.old_state.as_deref()
253    }
254
255    pub fn new_state(&self) -> &str {
256        self.new_state.as_deref().unwrap_or("")
257    }
258
259    pub fn take_new_state(&mut self) -> String {
260        self.new_state.take().unwrap_or_default()
261    }
262
263    pub fn created(&mut self, id: &str) -> crate::Result<O> {
264        if let Some(result) = self.created.as_mut().and_then(|r| r.remove(id)) {
265            Ok(result)
266        } else if let Some(error) = self.not_created.as_mut().and_then(|r| r.remove(id)) {
267            Err(error.to_string_error().into())
268        } else {
269            Err(Error::Internal(format!("Id {} not found.", id)))
270        }
271    }
272
273    pub fn updated(&mut self, id: &str) -> crate::Result<Option<O>> {
274        if let Some(result) = self.updated.as_mut().and_then(|r| r.remove(id)) {
275            Ok(result)
276        } else if let Some(error) = self.not_updated.as_mut().and_then(|r| r.remove(id)) {
277            Err(error.to_string_error().into())
278        } else {
279            Err(Error::Internal(format!("Id {} not found.", id)))
280        }
281    }
282
283    pub fn destroyed(&mut self, id: &str) -> crate::Result<()> {
284        if self
285            .destroyed
286            .as_ref()
287            .map_or(false, |r| r.iter().any(|i| i == id))
288        {
289            Ok(())
290        } else if let Some(error) = self.not_destroyed.as_mut().and_then(|r| r.remove(id)) {
291            Err(error.to_string_error().into())
292        } else {
293            Err(Error::Internal(format!("Id {} not found.", id)))
294        }
295    }
296
297    pub fn created_ids(&self) -> Option<impl Iterator<Item = &String>> {
298        self.created.as_ref().map(|map| map.keys())
299    }
300
301    pub fn updated_ids(&self) -> Option<impl Iterator<Item = &String>> {
302        self.updated.as_ref().map(|map| map.keys())
303    }
304
305    pub fn take_updated_ids(&mut self) -> Option<Vec<String>> {
306        self.updated
307            .take()
308            .map(|map| map.into_iter().map(|(k, _)| k).collect())
309    }
310
311    pub fn destroyed_ids(&self) -> Option<impl Iterator<Item = &String>> {
312        self.destroyed.as_ref().map(|list| list.iter())
313    }
314
315    pub fn take_destroyed_ids(&mut self) -> Option<Vec<String>> {
316        self.destroyed.take()
317    }
318
319    pub fn not_created_ids(&self) -> Option<impl Iterator<Item = &String>> {
320        self.not_created.as_ref().map(|map| map.keys())
321    }
322
323    pub fn not_updated_ids(&self) -> Option<impl Iterator<Item = &String>> {
324        self.not_updated.as_ref().map(|map| map.keys())
325    }
326
327    pub fn not_destroyed_ids(&self) -> Option<impl Iterator<Item = &String>> {
328        self.not_destroyed.as_ref().map(|map| map.keys())
329    }
330
331    pub fn has_updated(&self) -> bool {
332        self.updated.as_ref().map_or(false, |m| !m.is_empty())
333    }
334
335    pub fn has_created(&self) -> bool {
336        self.created.as_ref().map_or(false, |m| !m.is_empty())
337    }
338
339    pub fn has_destroyed(&self) -> bool {
340        self.destroyed.as_ref().map_or(false, |m| !m.is_empty())
341    }
342
343    pub fn unwrap_update_errors(&self) -> crate::Result<()> {
344        if let Some(errors) = &self.not_updated {
345            if let Some(err) = errors.values().next() {
346                return Err(err.to_string_error().into());
347            }
348        }
349        Ok(())
350    }
351
352    pub fn unwrap_create_errors(&self) -> crate::Result<()> {
353        if let Some(errors) = &self.not_created {
354            if let Some(err) = errors.values().next() {
355                return Err(err.to_string_error().into());
356            }
357        }
358        Ok(())
359    }
360}
361
362impl<U: Display> SetError<U> {
363    pub fn error(&self) -> &SetErrorType {
364        &self.type_
365    }
366
367    pub fn description(&self) -> Option<&str> {
368        self.description.as_deref()
369    }
370
371    pub fn properties(&self) -> Option<&[U]> {
372        self.properties.as_deref()
373    }
374
375    pub fn to_string_error(&self) -> SetError<String> {
376        SetError {
377            type_: self.type_.clone(),
378            description: self.description.as_ref().map(|s| s.to_string()),
379            properties: self
380                .properties
381                .as_ref()
382                .map(|s| s.iter().map(|s| s.to_string()).collect()),
383        }
384    }
385}
386
387impl<U: Display> Display for SetError<U> {
388    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
389        self.type_.fmt(f)?;
390        if let Some(description) = &self.description {
391            write!(f, ": {}", description)?;
392        }
393        if let Some(properties) = &self.properties {
394            write!(
395                f,
396                " (properties: {})",
397                properties
398                    .iter()
399                    .map(|v| v.to_string())
400                    .collect::<Vec<String>>()
401                    .join(", ")
402            )?;
403        }
404        Ok(())
405    }
406}
407
408impl Display for SetErrorType {
409    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
410        match self {
411            SetErrorType::Forbidden => write!(f, "forbidden"),
412            SetErrorType::OverQuota => write!(f, "overQuota"),
413            SetErrorType::TooLarge => write!(f, "tooLarge"),
414            SetErrorType::RateLimit => write!(f, "rateLimit"),
415            SetErrorType::NotFound => write!(f, "notFound"),
416            SetErrorType::InvalidPatch => write!(f, "invalidPatch"),
417            SetErrorType::WillDestroy => write!(f, "willDestroy"),
418            SetErrorType::InvalidProperties => write!(f, "invalidProperties"),
419            SetErrorType::Singleton => write!(f, "singleton"),
420            SetErrorType::MailboxHasChild => write!(f, "mailboxHasChild"),
421            SetErrorType::MailboxHasEmail => write!(f, "mailboxHasEmail"),
422            SetErrorType::BlobNotFound => write!(f, "blobNotFound"),
423            SetErrorType::TooManyKeywords => write!(f, "tooManyKeywords"),
424            SetErrorType::TooManyMailboxes => write!(f, "tooManyMailboxes"),
425            SetErrorType::ForbiddenFrom => write!(f, "forbiddenFrom"),
426            SetErrorType::InvalidEmail => write!(f, "invalidEmail"),
427            SetErrorType::TooManyRecipients => write!(f, "tooManyRecipients"),
428            SetErrorType::NoRecipients => write!(f, "noRecipients"),
429            SetErrorType::InvalidRecipients => write!(f, "invalidRecipients"),
430            SetErrorType::ForbiddenMailFrom => write!(f, "forbiddenMailFrom"),
431            SetErrorType::ForbiddenToSend => write!(f, "forbiddenToSend"),
432            SetErrorType::CannotUnsend => write!(f, "cannotUnsend"),
433            SetErrorType::AlreadyExists => write!(f, "alreadyExists"),
434            SetErrorType::InvalidScript => write!(f, "invalidScript"),
435            SetErrorType::ScriptIsActive => write!(f, "scriptIsActive"),
436        }
437    }
438}
439
440pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> {
441    DateTime::from_timestamp(timestamp, 0).unwrap_or_default()
442}
443
444pub fn string_not_set(string: &Option<String>) -> bool {
445    matches!(string, Some(string) if string.is_empty())
446}
447
448pub fn date_not_set(date: &Option<DateTime<Utc>>) -> bool {
449    matches!(date, Some(date) if date.timestamp() == 0)
450}
451
452pub fn list_not_set<O>(list: &Option<Vec<O>>) -> bool {
453    matches!(list, Some(list) if list.is_empty() )
454}
455
456pub fn map_not_set<K, V>(list: &Option<AHashMap<K, V>>) -> bool {
457    matches!(list, Some(list) if list.is_empty() )
458}