jmap_chat_client/methods/
misc.rs1use jmap_types::{Id, PatchObject, State};
8
9use super::{
10 ChangesResponse, GetResponse, PresenceStatusPatch, PushSubscriptionCreateInput,
11 PushSubscriptionCreateResponse, PushSubscriptionPatch, SetResponse,
12};
13
14impl super::SessionClient {
15 pub async fn read_position_get(
20 &self,
21 ids: Option<&[Id]>,
22 ) -> Result<GetResponse<jmap_chat_types::ReadPosition>, jmap_base_client::ClientError> {
23 let (api_url, account_id) = self.session_parts()?;
24 let mut args = serde_json::json!({ "accountId": account_id });
27 if let Some(id_slice) = ids {
28 args["ids"] = serde_json::to_value(id_slice).expect("Id slice Serialize is infallible");
29 }
30 let req = super::build_request("ReadPosition/get", args, super::USING_CHAT);
31 let resp = self.call_internal(api_url, &req).await?;
32 jmap_base_client::extract_response(&resp, super::CALL_ID)
33 }
34
35 pub async fn read_position_update(
44 &self,
45 read_position_id: &Id,
46 last_read_message_id: &Id,
47 ) -> Result<SetResponse, jmap_base_client::ClientError> {
48 let (api_url, account_id) = self.session_parts()?;
49 let args = serde_json::json!({
50 "accountId": account_id,
51 "update": {
52 read_position_id.as_ref(): { "lastReadMessageId": last_read_message_id }
53 },
54 });
55 let req = super::build_request("ReadPosition/set", args, super::USING_CHAT);
56 let resp = self.call_internal(api_url, &req).await?;
57 jmap_base_client::extract_response(&resp, super::CALL_ID)
58 }
59
60 pub async fn presence_status_get(
65 &self,
66 ) -> Result<GetResponse<jmap_chat_types::PresenceStatus>, jmap_base_client::ClientError> {
67 let (api_url, account_id) = self.session_parts()?;
68 let args = serde_json::json!({
69 "accountId": account_id,
70 "ids": None::<&[Id]>,
71 });
72 let req = super::build_request("PresenceStatus/get", args, super::USING_CHAT);
73 let resp = self.call_internal(api_url, &req).await?;
74 jmap_base_client::extract_response(&resp, super::CALL_ID)
75 }
76
77 pub async fn read_position_changes(
81 &self,
82 since_state: &State,
83 max_changes: Option<u64>,
84 ) -> Result<ChangesResponse, jmap_base_client::ClientError> {
85 if since_state.as_ref().is_empty() {
87 return Err(jmap_base_client::ClientError::InvalidArgument(
88 "read_position_changes: since_state may not be empty".into(),
89 ));
90 }
91 let (api_url, account_id) = self.session_parts()?;
92 let mut args = serde_json::json!({
93 "accountId": account_id,
94 "sinceState": since_state,
95 });
96 if let Some(mc) = max_changes {
97 args["maxChanges"] = mc.into();
98 }
99 let req = super::build_request("ReadPosition/changes", args, super::USING_CHAT);
100 let resp = self.call_internal(api_url, &req).await?;
101 jmap_base_client::extract_response(&resp, super::CALL_ID)
102 }
103
104 pub async fn presence_status_update(
110 &self,
111 id: &Id,
112 patch: &PresenceStatusPatch<'_>,
113 ) -> Result<SetResponse, jmap_base_client::ClientError> {
114 let (api_url, account_id) = self.session_parts()?;
115 let mut patch_map = serde_json::Map::new();
116 if let Some(p) = &patch.presence {
117 patch_map.insert(
118 "presence".into(),
119 serde_json::to_value(p).map_err(jmap_base_client::ClientError::Parse)?,
120 );
121 }
122 if let Some(entry) = patch
123 .status_text
124 .map_entry()
125 .map_err(jmap_base_client::ClientError::Parse)?
126 {
127 patch_map.insert("statusText".into(), entry);
128 }
129 if let Some(entry) = patch
130 .status_emoji
131 .map_entry()
132 .map_err(jmap_base_client::ClientError::Parse)?
133 {
134 patch_map.insert("statusEmoji".into(), entry);
135 }
136 if let Some(entry) = patch
137 .expires_at
138 .map_entry()
139 .map_err(jmap_base_client::ClientError::Parse)?
140 {
141 patch_map.insert("expiresAt".into(), entry);
142 }
143 if let Some(rs) = patch.receipt_sharing {
144 patch_map.insert("receiptSharing".into(), rs.into());
145 }
146 let patch_value = serde_json::Value::Object(PatchObject::from_map(patch_map).into_inner());
150 let args = serde_json::json!({
151 "accountId": account_id,
152 "update": { id.as_ref(): patch_value },
153 });
154 let req = super::build_request("PresenceStatus/set", args, super::USING_CHAT);
155 let resp = self.call_internal(api_url, &req).await?;
156 jmap_base_client::extract_response(&resp, super::CALL_ID)
157 }
158
159 pub async fn presence_status_changes(
163 &self,
164 since_state: &State,
165 max_changes: Option<u64>,
166 ) -> Result<ChangesResponse, jmap_base_client::ClientError> {
167 if since_state.as_ref().is_empty() {
169 return Err(jmap_base_client::ClientError::InvalidArgument(
170 "presence_status_changes: since_state may not be empty".into(),
171 ));
172 }
173 let (api_url, account_id) = self.session_parts()?;
174 let mut args = serde_json::json!({
175 "accountId": account_id,
176 "sinceState": since_state,
177 });
178 if let Some(mc) = max_changes {
179 args["maxChanges"] = mc.into();
180 }
181 let req = super::build_request("PresenceStatus/changes", args, super::USING_CHAT);
182 let resp = self.call_internal(api_url, &req).await?;
183 jmap_base_client::extract_response(&resp, super::CALL_ID)
184 }
185
186 pub async fn push_subscription_create(
202 &self,
203 input: &PushSubscriptionCreateInput<'_>,
204 ) -> Result<PushSubscriptionCreateResponse, jmap_base_client::ClientError> {
205 if input.device_client_id.is_empty() {
206 return Err(jmap_base_client::ClientError::InvalidArgument(
207 "push_subscription_create: device_client_id may not be empty".into(),
208 ));
209 }
210 if input.url.is_empty() {
211 return Err(jmap_base_client::ClientError::InvalidArgument(
212 "push_subscription_create: url may not be empty".into(),
213 ));
214 }
215 let api_url = self.api_url();
217 let client_id = super::resolve_client_id(input.client_id);
218 let mut create_obj = serde_json::json!({
219 "deviceClientId": input.device_client_id,
220 "url": input.url,
221 });
222 if let Some(exp) = input.expires {
223 create_obj["expires"] = exp.as_ref().into();
224 }
225 if let Some(types) = input.types {
226 create_obj["types"] = serde_json::Value::Array(
227 types.iter().copied().map(serde_json::Value::from).collect(),
228 );
229 }
230 let has_chat_push = input.chat_push.is_some();
231 if let Some(cp) = input.chat_push {
232 let mut seen = std::collections::HashSet::new();
233 for (account_id, _) in cp {
234 if !seen.insert(account_id) {
235 return Err(jmap_base_client::ClientError::InvalidArgument(format!(
236 "push_subscription_create: duplicate accountId '{}' in chat_push",
237 account_id
238 )));
239 }
240 }
241 let mut chat_push_map = serde_json::Map::new();
242 for (account_id, config) in cp {
243 chat_push_map.insert(
244 account_id.as_ref().to_owned(),
245 serde_json::to_value(config).map_err(jmap_base_client::ClientError::Parse)?,
246 );
247 }
248 create_obj["chatPush"] = serde_json::Value::Object(chat_push_map);
249 }
250 let args = serde_json::json!({
251 "create": { client_id: create_obj }
252 });
253 let using = if has_chat_push {
255 super::USING_CHAT_PUSH
256 } else {
257 super::USING_CORE
258 };
259 let req = super::build_request("PushSubscription/set", args, using);
260 let resp = self.call_internal(api_url, &req).await?;
261 jmap_base_client::extract_response(&resp, super::CALL_ID)
262 }
263
264 pub async fn push_subscription_update(
283 &self,
284 id: &Id,
285 patch: &PushSubscriptionPatch<'_>,
286 ) -> Result<SetResponse, jmap_base_client::ClientError> {
287 if id.as_ref().is_empty() {
289 return Err(jmap_base_client::ClientError::InvalidArgument(
290 "push_subscription_update: id may not be empty".into(),
291 ));
292 }
293 if patch.types.is_some() && patch.clear_types {
294 return Err(jmap_base_client::ClientError::InvalidArgument(
295 "push_subscription_update: types and clear_types are mutually exclusive".into(),
296 ));
297 }
298 if patch.chat_push.is_some() && patch.clear_chat_push {
299 return Err(jmap_base_client::ClientError::InvalidArgument(
300 "push_subscription_update: chat_push and clear_chat_push are mutually exclusive"
301 .into(),
302 ));
303 }
304
305 let api_url = self.api_url();
306 let mut patch_map = serde_json::Map::new();
307 if let Some(code) = patch.verification_code {
308 patch_map.insert("verificationCode".into(), code.into());
309 }
310 if let Some(entry) = patch
311 .expires
312 .map_entry()
313 .map_err(jmap_base_client::ClientError::Parse)?
314 {
315 patch_map.insert("expires".into(), entry);
316 }
317 if let Some(types) = patch.types {
318 patch_map.insert(
319 "types".into(),
320 serde_json::Value::Array(
321 types.iter().copied().map(serde_json::Value::from).collect(),
322 ),
323 );
324 } else if patch.clear_types {
325 patch_map.insert("types".into(), serde_json::Value::Null);
326 }
327 if let Some(cp) = patch.chat_push {
328 let mut seen = std::collections::HashSet::new();
329 for (account_id, _) in cp {
330 if !seen.insert(account_id) {
331 return Err(jmap_base_client::ClientError::InvalidArgument(format!(
332 "push_subscription_update: duplicate accountId '{}' in chat_push",
333 account_id
334 )));
335 }
336 }
337 let mut chat_push_map = serde_json::Map::new();
338 for (account_id, config) in cp {
339 chat_push_map.insert(
340 account_id.as_ref().to_owned(),
341 serde_json::to_value(config).map_err(jmap_base_client::ClientError::Parse)?,
342 );
343 }
344 patch_map.insert("chatPush".into(), serde_json::Value::Object(chat_push_map));
345 } else if patch.clear_chat_push {
346 patch_map.insert("chatPush".into(), serde_json::Value::Null);
347 }
348
349 let patch_value = serde_json::Value::Object(PatchObject::from_map(patch_map).into_inner());
350 let args = serde_json::json!({
351 "update": { id.as_ref(): patch_value }
352 });
353 let using = if patch.chat_push.is_some() || patch.clear_chat_push {
354 super::USING_CHAT_PUSH
355 } else {
356 super::USING_CORE
357 };
358 let req = super::build_request("PushSubscription/set", args, using);
359 let resp = self.call_internal(api_url, &req).await?;
360 jmap_base_client::extract_response(&resp, super::CALL_ID)
361 }
362
363 pub async fn push_subscription_destroy(
379 &self,
380 ids: &[Id],
381 ) -> Result<SetResponse, jmap_base_client::ClientError> {
382 if ids.is_empty() {
383 return Err(jmap_base_client::ClientError::InvalidArgument(
384 "push_subscription_destroy: ids may not be empty".into(),
385 ));
386 }
387 let api_url = self.api_url();
388 let args = serde_json::json!({
389 "destroy": ids,
390 });
391 let req = super::build_request("PushSubscription/set", args, super::USING_CORE);
392 let resp = self.call_internal(api_url, &req).await?;
393 jmap_base_client::extract_response(&resp, super::CALL_ID)
394 }
395}