io_jmap/rfc8621/vacation_response/
set.rs1use alloc::{collections::BTreeMap, string::String, vec};
61
62use secrecy::SecretString;
63use serde::{Deserialize, Serialize};
64use thiserror::Error;
65
66use crate::{
67 coroutine::*,
68 jmap_try,
69 rfc8620::{
70 JMAP_CORE_CAPABILITY, error::JmapMethodError, request::JmapBatch, send::*,
71 session::JmapSession,
72 },
73 rfc8621::{
74 JMAP_MAIL_CAPABILITY,
75 vacation_response::{JMAP_VACATION_RESPONSE_CAPABILITY, JmapVacationResponse},
76 },
77};
78
79#[derive(Clone, Debug, Default, Serialize)]
83#[serde(rename_all = "camelCase")]
84pub struct JmapVacationResponseUpdate {
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub is_enabled: Option<bool>,
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub from_date: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub to_date: Option<String>,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub subject: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub text_body: Option<String>,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub html_body: Option<String>,
103}
104
105#[derive(Debug, Error)]
107pub enum JmapVacationResponseSetError {
108 #[error("JMAP VacationResponse/set failed: missing response in method_responses")]
110 MissingResponse,
111 #[error("JMAP VacationResponse/set failed: {0}")]
113 Send(#[from] JmapSendError),
114 #[error("JMAP VacationResponse/set failed: serialize args: {0}")]
116 SerializeArgs(#[source] serde_json::Error),
117 #[error("JMAP VacationResponse/set failed: parse response: {0}")]
119 ParseResponse(#[source] serde_json::Error),
120 #[error("JMAP VacationResponse/set failed: {0}")]
122 Method(#[from] JmapMethodError),
123}
124
125#[derive(Clone, Debug)]
127pub struct JmapVacationResponseSetOutput {
128 pub new_state: String,
130 pub updated: Option<JmapVacationResponse>,
132 pub keep_alive: bool,
134}
135
136pub struct JmapVacationResponseSet {
138 state: State,
139}
140
141impl JmapVacationResponseSet {
142 pub fn new(
144 session: &JmapSession,
145 http_auth: &SecretString,
146 patch: JmapVacationResponseUpdate,
147 ) -> Result<Self, JmapVacationResponseSetError> {
148 let account_id = session
149 .primary_accounts
150 .get(JMAP_VACATION_RESPONSE_CAPABILITY)
151 .or_else(|| session.primary_accounts.get(JMAP_MAIL_CAPABILITY))
152 .cloned()
153 .unwrap_or_default();
154 let api_url = &session.api_url;
155
156 let args = serde_json::to_value(VacationResponseSetArgs {
157 account_id,
158 update: BTreeMap::from([("singleton", patch)]),
159 })
160 .map_err(JmapVacationResponseSetError::SerializeArgs)?;
161
162 let mut using = vec![JMAP_CORE_CAPABILITY.into(), JMAP_MAIL_CAPABILITY.into()];
163 if session
164 .capabilities
165 .contains_key(JMAP_VACATION_RESPONSE_CAPABILITY)
166 {
167 using.push(JMAP_VACATION_RESPONSE_CAPABILITY.into());
168 }
169
170 let mut batch = JmapBatch::new();
171 batch.add("VacationResponse/set", args);
172 let request = batch.into_request(using);
173
174 Ok(Self {
175 state: State::Send(JmapSend::new(http_auth, api_url, request)?),
176 })
177 }
178}
179
180impl JmapCoroutine for JmapVacationResponseSet {
181 type Yield = JmapYield;
182 type Return = Result<JmapVacationResponseSetOutput, JmapVacationResponseSetError>;
183
184 fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
185 match &mut self.state {
186 State::Send(send) => {
187 let JmapSendOutput {
188 response,
189 keep_alive,
190 } = jmap_try!(send, arg);
191
192 let Some((name, args, _)) = response.method_responses.into_iter().next() else {
193 return JmapCoroutineState::Complete(Err(
194 JmapVacationResponseSetError::MissingResponse,
195 ));
196 };
197
198 if name == "error" {
199 let err = serde_json::from_value::<JmapMethodError>(args)
200 .unwrap_or(JmapMethodError::Unknown);
201 return JmapCoroutineState::Complete(Err(err.into()));
202 }
203
204 match serde_json::from_value::<VacationResponseSetResponse>(args) {
205 Ok(r) => JmapCoroutineState::Complete(Ok(JmapVacationResponseSetOutput {
206 new_state: r.new_state,
207 updated: r.updated.unwrap_or_default().into_values().flatten().next(),
208 keep_alive,
209 })),
210 Err(err) => JmapCoroutineState::Complete(Err(
211 JmapVacationResponseSetError::ParseResponse(err),
212 )),
213 }
214 }
215 }
216 }
217}
218
219enum State {
220 Send(JmapSend),
221}
222
223#[derive(Serialize)]
224#[serde(rename_all = "camelCase")]
225struct VacationResponseSetArgs {
226 account_id: String,
227 update: BTreeMap<&'static str, JmapVacationResponseUpdate>,
228}
229
230#[derive(Deserialize)]
231#[serde(rename_all = "camelCase")]
232struct VacationResponseSetResponse {
233 new_state: String,
234 #[serde(default)]
235 updated: Option<BTreeMap<String, Option<JmapVacationResponse>>>,
236}