io_email/flag/jmap/
store.rs1use alloc::{collections::BTreeMap, string::String};
17
18use io_jmap::{
19 coroutine::{JmapCoroutine, JmapCoroutineState, JmapYield},
20 rfc8620::JmapSession,
21 rfc8621::email::set::{
22 JmapEmailSet as InnerSet, JmapEmailSetArgs, JmapEmailSetError as InnerErr,
23 },
24};
25use log::trace;
26use secrecy::SecretString;
27use thiserror::Error;
28
29use crate::{
30 flag::types::{Flag, FlagOp},
31 jmap::convert::keyword_from,
32};
33
34#[derive(Debug, Error)]
36pub enum JmapFlagStoreError {
37 #[error(transparent)]
38 Set(#[from] InnerErr),
39 #[error("Email/set returned per-id failures: {0:?}")]
40 NotUpdated(alloc::vec::Vec<String>),
41}
42
43pub struct JmapFlagStore {
45 inner: InnerSet,
46}
47
48impl JmapFlagStore {
49 pub fn new(
50 session: &JmapSession,
51 http_auth: &SecretString,
52 _mailbox: &str,
53 ids: &[&str],
54 flags: &[Flag],
55 op: FlagOp,
56 ) -> Result<Self, JmapFlagStoreError> {
57 trace!("prepare JMAP flag store ({op:?})");
58 let mut args = JmapEmailSetArgs::default();
59 for id in ids {
60 match op {
61 FlagOp::Add => {
62 for flag in flags {
63 args.set_keyword(*id, keyword_from(flag));
64 }
65 }
66 FlagOp::Remove => {
67 for flag in flags {
68 args.unset_keyword(*id, keyword_from(flag));
69 }
70 }
71 FlagOp::Set => {
72 let bag: BTreeMap<String, bool> =
73 flags.iter().map(|f| (keyword_from(f), true)).collect();
74 args.replace_keywords(*id, bag);
75 }
76 }
77 }
78 Ok(Self {
79 inner: InnerSet::new(session, http_auth, args)?,
80 })
81 }
82}
83
84impl JmapCoroutine for JmapFlagStore {
85 type Yield = JmapYield;
86 type Return = Result<(), JmapFlagStoreError>;
87
88 fn resume(&mut self, bytes: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
89 match self.inner.resume(bytes) {
90 JmapCoroutineState::Yielded(y) => JmapCoroutineState::Yielded(y),
91 JmapCoroutineState::Complete(Ok(ok)) => {
92 if ok.not_updated.is_empty() {
93 JmapCoroutineState::Complete(Ok(()))
94 } else {
95 JmapCoroutineState::Complete(Err(JmapFlagStoreError::NotUpdated(
96 ok.not_updated.into_keys().collect(),
97 )))
98 }
99 }
100 JmapCoroutineState::Complete(Err(err)) => JmapCoroutineState::Complete(Err(err.into())),
101 }
102 }
103}