io_jmap/rfc9610/contact_card/
copy.rs1use alloc::{collections::BTreeMap, string::String, vec, vec::Vec};
58
59use secrecy::SecretString;
60use serde::{Deserialize, Serialize};
61use thiserror::Error;
62
63use crate::{
64 coroutine::*,
65 jmap_try,
66 rfc8620::{
67 JMAP_CORE_CAPABILITY, error::JmapMethodError, request::JmapBatch, send::*,
68 session::JmapSession,
69 },
70 rfc9610::{JMAP_CONTACTS_CAPABILITY, contact_card::JmapContactCard},
71};
72
73#[derive(Clone, Debug, Default, Serialize)]
76#[serde(rename_all = "camelCase")]
77pub struct JmapContactCardCopyArgs {
78 pub id: String,
80 pub address_book_ids: BTreeMap<String, bool>,
82}
83
84#[derive(Clone, Debug, Deserialize)]
87#[serde(tag = "type", rename_all = "camelCase")]
88pub enum JmapContactCardCopyItemError {
89 AlreadyExists {
91 description: Option<String>,
93 },
94 NotFound {
96 description: Option<String>,
98 },
99 InvalidProperties {
102 description: Option<String>,
104 #[serde(default)]
106 properties: Vec<String>,
107 },
108 #[serde(other)]
110 Unknown,
111}
112
113#[derive(Debug, Error)]
115pub enum JmapContactCardCopyError {
116 #[error("JMAP ContactCard/copy failed: missing response in method_responses")]
118 MissingResponse,
119 #[error("JMAP ContactCard/copy failed: {0}")]
121 Send(#[from] JmapSendError),
122 #[error("JMAP ContactCard/copy failed: serialize args: {0}")]
124 SerializeArgs(#[source] serde_json::Error),
125 #[error("JMAP ContactCard/copy failed: parse response: {0}")]
127 ParseResponse(#[source] serde_json::Error),
128 #[error("JMAP ContactCard/copy failed: {0}")]
130 Method(#[from] JmapMethodError),
131}
132
133#[derive(Clone, Debug)]
135pub struct JmapContactCardCopyOutput {
136 pub new_state: String,
138 pub created: BTreeMap<String, JmapContactCard>,
140 pub not_created: BTreeMap<String, JmapContactCardCopyItemError>,
142 pub keep_alive: bool,
144}
145
146pub struct JmapContactCardCopy {
148 state: State,
149}
150
151impl JmapContactCardCopy {
152 pub fn new(
154 session: &JmapSession,
155 http_auth: &SecretString,
156 from_account_id: impl Into<String>,
157 cards: BTreeMap<String, JmapContactCardCopyArgs>,
158 ) -> Result<Self, JmapContactCardCopyError> {
159 let account_id = session
160 .primary_accounts
161 .get(JMAP_CONTACTS_CAPABILITY)
162 .cloned()
163 .unwrap_or_default();
164 let api_url = &session.api_url;
165
166 let args = serde_json::to_value(ContactCardCopyArgs {
167 from_account_id: from_account_id.into(),
168 account_id,
169 create: cards,
170 })
171 .map_err(JmapContactCardCopyError::SerializeArgs)?;
172
173 let mut batch = JmapBatch::new();
174 batch.add("ContactCard/copy", args);
175 let request = batch.into_request(vec![
176 JMAP_CORE_CAPABILITY.into(),
177 JMAP_CONTACTS_CAPABILITY.into(),
178 ]);
179
180 Ok(Self {
181 state: State::Send(JmapSend::new(http_auth, api_url, request)?),
182 })
183 }
184}
185
186impl JmapCoroutine for JmapContactCardCopy {
187 type Yield = JmapYield;
188 type Return = Result<JmapContactCardCopyOutput, JmapContactCardCopyError>;
189
190 fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
191 match &mut self.state {
192 State::Send(send) => {
193 let JmapSendOutput {
194 response,
195 keep_alive,
196 } = jmap_try!(send, arg);
197
198 let Some((name, args, _)) = response.method_responses.into_iter().next() else {
199 return JmapCoroutineState::Complete(Err(
200 JmapContactCardCopyError::MissingResponse,
201 ));
202 };
203
204 if name == "error" {
205 let err = serde_json::from_value::<JmapMethodError>(args)
206 .unwrap_or(JmapMethodError::Unknown);
207 return JmapCoroutineState::Complete(Err(err.into()));
208 }
209
210 match serde_json::from_value::<ContactCardCopyResponse>(args) {
211 Ok(r) => JmapCoroutineState::Complete(Ok(JmapContactCardCopyOutput {
212 new_state: r.new_state,
213 created: r.created,
214 not_created: r.not_created,
215 keep_alive,
216 })),
217 Err(err) => JmapCoroutineState::Complete(Err(
218 JmapContactCardCopyError::ParseResponse(err),
219 )),
220 }
221 }
222 }
223 }
224}
225
226enum State {
227 Send(JmapSend),
228}
229
230#[derive(Serialize)]
231#[serde(rename_all = "camelCase")]
232struct ContactCardCopyArgs {
233 from_account_id: String,
234 account_id: String,
235 create: BTreeMap<String, JmapContactCardCopyArgs>,
236}
237
238#[derive(Deserialize)]
239#[serde(rename_all = "camelCase")]
240struct ContactCardCopyResponse {
241 new_state: String,
242 #[serde(default)]
243 created: BTreeMap<String, JmapContactCard>,
244 #[serde(default)]
245 not_created: BTreeMap<String, JmapContactCardCopyItemError>,
246}