io_jmap/rfc8621/mailbox/
set.rs1use core::fmt;
58
59use alloc::{collections::BTreeMap, string::String, vec, vec::Vec};
60
61use log::trace;
62use secrecy::SecretString;
63use serde::Serialize;
64use thiserror::Error;
65
66use crate::{
67 coroutine::*,
68 jmap_try,
69 rfc8620::{CORE_CAPABILITY, JmapBatch, JmapSession, send::*, set::*},
70 rfc8621::{
71 MAIL_CAPABILITY,
72 mailbox::{JmapMailbox, JmapMailboxCreate, JmapMailboxSetItemError, JmapMailboxUpdate},
73 },
74};
75
76#[derive(Debug, Error)]
78pub enum JmapMailboxSetError {
79 #[error("JMAP Mailbox/set failed: {0}")]
80 Send(#[from] JmapSendError),
81 #[error("JMAP Mailbox/set failed: serialize args: {0}")]
82 SerializeArgs(#[source] serde_json::Error),
83 #[error("JMAP Mailbox/set failed: {0}")]
84 Set(#[from] JmapSetError),
85}
86
87#[derive(Clone, Debug, Default, Serialize)]
89#[serde(rename_all = "camelCase")]
90pub struct JmapMailboxSetArgs {
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub create: Option<BTreeMap<String, JmapMailboxCreate>>,
94
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub update: Option<BTreeMap<String, JmapMailboxUpdate>>,
98
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub destroy: Option<Vec<String>>,
102
103 #[serde(skip_serializing_if = "Option::is_none")]
105 pub on_destroy_remove_emails: Option<bool>,
106}
107
108#[derive(Clone, Debug)]
110pub struct JmapMailboxSetOutput {
111 pub new_state: String,
112 pub created: BTreeMap<String, JmapMailbox>,
113 pub updated: BTreeMap<String, Option<JmapMailbox>>,
114 pub destroyed: Vec<String>,
115 pub not_created: BTreeMap<String, JmapMailboxSetItemError>,
116 pub not_updated: BTreeMap<String, JmapMailboxSetItemError>,
117 pub not_destroyed: BTreeMap<String, JmapMailboxSetItemError>,
118 pub keep_alive: bool,
119}
120
121pub struct JmapMailboxSet {
123 state: State,
124}
125
126impl JmapMailboxSet {
127 pub fn new(
128 session: &JmapSession,
129 http_auth: &SecretString,
130 args: JmapMailboxSetArgs,
131 ) -> Result<Self, JmapMailboxSetError> {
132 let account_id = session
133 .primary_accounts
134 .get(MAIL_CAPABILITY)
135 .cloned()
136 .unwrap_or_default();
137 let api_url = &session.api_url;
138
139 let json_args = serde_json::to_value(MailboxSetRequest { account_id, args })
140 .map_err(JmapMailboxSetError::SerializeArgs)?;
141
142 let mut batch = JmapBatch::new();
143 batch.add("Mailbox/set", json_args);
144 let request = batch.into_request(vec![CORE_CAPABILITY.into(), MAIL_CAPABILITY.into()]);
145
146 let send = JmapSend::new(http_auth, api_url, request)?;
147 Ok(Self {
148 state: State::Set(JmapSet::from_send(send)),
149 })
150 }
151}
152
153impl JmapCoroutine for JmapMailboxSet {
154 type Yield = JmapYield;
155 type Return = Result<JmapMailboxSetOutput, JmapMailboxSetError>;
156
157 fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
158 trace!("Mailbox/set: {}", self.state);
159 match &mut self.state {
160 State::Set(set) => {
161 let JmapSetOutput {
162 new_state,
163 created,
164 updated,
165 destroyed,
166 not_created,
167 not_updated,
168 not_destroyed,
169 keep_alive,
170 } = jmap_try!(set, arg);
171 let parse = |map: BTreeMap<String, serde_json::Value>| {
172 map.into_iter()
173 .map(|(k, v)| {
174 let e = serde_json::from_value(v)
175 .unwrap_or(JmapMailboxSetItemError::Unknown);
176 (k, e)
177 })
178 .collect()
179 };
180 JmapCoroutineState::Complete(Ok(JmapMailboxSetOutput {
181 new_state,
182 created,
183 updated,
184 destroyed,
185 not_created: parse(not_created),
186 not_updated: parse(not_updated),
187 not_destroyed: parse(not_destroyed),
188 keep_alive,
189 }))
190 }
191 }
192 }
193}
194
195enum State {
196 Set(JmapSet<JmapMailbox>),
197}
198
199impl fmt::Display for State {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match self {
202 Self::Set(_) => f.write_str("set"),
203 }
204 }
205}
206
207#[derive(Serialize)]
208struct MailboxSetRequest {
209 #[serde(rename = "accountId")]
210 account_id: String,
211 #[serde(flatten)]
212 args: JmapMailboxSetArgs,
213}