Mailbox ACLs

main
Mauro D 2022-06-22 19:58:20 +00:00
parent c085cf5c89
commit 8b7cfda3d7
8 changed files with 114 additions and 25 deletions

View File

@ -30,7 +30,7 @@ pub enum Credentials {
pub struct Client { pub struct Client {
session: Session, session: Session,
session_url: String, session_url: String,
session_outdated: AtomicBool, session_updated: AtomicBool,
#[cfg(feature = "websockets")] #[cfg(feature = "websockets")]
pub(crate) authorization: String, pub(crate) authorization: String,
upload_url: Vec<URLPart<blob::URLParameter>>, upload_url: Vec<URLPart<blob::URLParameter>>,
@ -91,7 +91,7 @@ impl Client {
event_source_url: URLPart::parse(session.event_source_url())?, event_source_url: URLPart::parse(session.event_source_url())?,
session, session,
session_url: url.to_string(), session_url: url.to_string(),
session_outdated: false.into(), session_updated: true.into(),
#[cfg(feature = "websockets")] #[cfg(feature = "websockets")]
authorization, authorization,
timeout: DEFAULT_TIMEOUT_MS, timeout: DEFAULT_TIMEOUT_MS,
@ -147,7 +147,7 @@ impl Client {
)?; )?;
if response.session_state() != self.session.state() { if response.session_state() != self.session.state() {
self.session_outdated.store(true, Ordering::Relaxed); self.session_updated.store(false, Ordering::Relaxed);
} }
Ok(response) Ok(response)
@ -172,12 +172,12 @@ impl Client {
self.upload_url = URLPart::parse(session.upload_url())?; self.upload_url = URLPart::parse(session.upload_url())?;
self.event_source_url = URLPart::parse(session.event_source_url())?; self.event_source_url = URLPart::parse(session.event_source_url())?;
self.session = session; self.session = session;
self.session_outdated.store(false, Ordering::Relaxed); self.session_updated.store(true, Ordering::Relaxed);
Ok(()) Ok(())
} }
pub fn is_session_updated(&self) -> bool { pub fn is_session_updated(&self) -> bool {
!self.session_outdated.load(Ordering::Relaxed) self.session_updated.load(Ordering::Relaxed)
} }
pub fn set_default_account_id(&mut self, defaul_account_id: impl Into<String>) -> &mut Self { pub fn set_default_account_id(&mut self, defaul_account_id: impl Into<String>) -> &mut Self {

View File

@ -143,7 +143,7 @@ impl Client {
pub async fn email_query( pub async fn email_query(
&self, &self,
filter: Option<impl Into<Filter<super::query::Filter>>>, filter: Option<impl Into<Filter<super::query::Filter>>>,
sort: Option<Vec<Comparator<super::query::Comparator>>>, sort: Option<impl IntoIterator<Item = Comparator<super::query::Comparator>>>,
) -> crate::Result<QueryResponse> { ) -> crate::Result<QueryResponse> {
let mut request = self.build(); let mut request = self.build();
let query_request = request.query_email(); let query_request = request.query_email();

View File

@ -181,8 +181,8 @@ pub struct Email<State = Get> {
#[serde(flatten)] #[serde(flatten)]
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[serde(skip_serializing_if = "HashMap::is_empty")] #[serde(skip_serializing_if = "Option::is_none")]
patch: HashMap<String, bool>, patch: Option<HashMap<String, bool>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -32,7 +32,9 @@ impl Email<Set> {
pub fn mailbox_id(&mut self, mailbox_id: &str, set: bool) -> &mut Self { pub fn mailbox_id(&mut self, mailbox_id: &str, set: bool) -> &mut Self {
self.mailbox_ids = None; self.mailbox_ids = None;
self.patch.insert(format!("mailboxIds/{}", mailbox_id), set); self.patch
.get_or_insert_with(HashMap::new)
.insert(format!("mailboxIds/{}", mailbox_id), set);
self self
} }
@ -47,7 +49,9 @@ impl Email<Set> {
pub fn keyword(&mut self, keyword: &str, set: bool) -> &mut Self { pub fn keyword(&mut self, keyword: &str, set: bool) -> &mut Self {
self.keywords = None; self.keywords = None;
self.patch.insert(format!("keywords/{}", keyword), set); self.patch
.get_or_insert_with(HashMap::new)
.insert(format!("keywords/{}", keyword), set);
self self
} }

View File

@ -1,6 +1,8 @@
use crate::{core::get::GetObject, Get, Set}; use std::collections::HashMap;
use super::{Mailbox, Role}; use crate::{core::get::GetObject, principal::ACL, Get, Set};
use super::{Mailbox, MailboxRights, Role};
impl Mailbox<Get> { impl Mailbox<Get> {
pub fn id(&self) -> &str { pub fn id(&self) -> &str {
@ -47,40 +49,70 @@ impl Mailbox<Get> {
*self.is_subscribed.as_ref().unwrap_or(&false) *self.is_subscribed.as_ref().unwrap_or(&false)
} }
pub fn my_rights(&self) -> Option<&MailboxRights> {
self.my_rights.as_ref()
}
pub fn acl(&self) -> Option<&HashMap<String, Vec<ACL>>> {
self.acl.as_ref()
}
}
impl MailboxRights {
pub fn may_read_items(&self) -> bool { pub fn may_read_items(&self) -> bool {
self.my_rights.as_ref().unwrap().may_read_items self.may_read_items
} }
pub fn may_add_items(&self) -> bool { pub fn may_add_items(&self) -> bool {
self.my_rights.as_ref().unwrap().may_add_items self.may_add_items
} }
pub fn may_remove_items(&self) -> bool { pub fn may_remove_items(&self) -> bool {
self.my_rights.as_ref().unwrap().may_remove_items self.may_remove_items
} }
pub fn may_set_seen(&self) -> bool { pub fn may_set_seen(&self) -> bool {
self.my_rights.as_ref().unwrap().may_set_seen self.may_set_seen
} }
pub fn may_set_keywords(&self) -> bool { pub fn may_set_keywords(&self) -> bool {
self.my_rights.as_ref().unwrap().may_set_keywords self.may_set_keywords
} }
pub fn may_create_child(&self) -> bool { pub fn may_create_child(&self) -> bool {
self.my_rights.as_ref().unwrap().may_create_child self.may_create_child
} }
pub fn may_rename(&self) -> bool { pub fn may_rename(&self) -> bool {
self.my_rights.as_ref().unwrap().may_rename self.may_rename
} }
pub fn may_delete(&self) -> bool { pub fn may_delete(&self) -> bool {
self.my_rights.as_ref().unwrap().may_delete self.may_delete
} }
pub fn may_submit(&self) -> bool { pub fn may_submit(&self) -> bool {
self.my_rights.as_ref().unwrap().may_submit self.may_submit
}
pub fn acl_list(&self) -> Vec<ACL> {
let mut acl_list = Vec::new();
for (is_set, acl) in [
(self.may_read_items, ACL::ReadItems),
(self.may_add_items, ACL::AddItems),
(self.may_remove_items, ACL::RemoveItems),
(self.may_set_seen, ACL::SetSeen),
(self.may_set_keywords, ACL::SetKeywords),
(self.may_create_child, ACL::CreateChild),
(self.may_rename, ACL::Modify),
(self.may_delete, ACL::Delete),
(self.may_submit, ACL::Submit),
] {
if is_set {
acl_list.push(acl);
}
}
acl_list
} }
} }

View File

@ -9,6 +9,7 @@ use crate::{
response::{MailboxGetResponse, MailboxSetResponse}, response::{MailboxGetResponse, MailboxSetResponse},
set::{SetObject, SetRequest}, set::{SetObject, SetRequest},
}, },
principal::ACL,
Get, Method, Set, Get, Method, Set,
}; };
@ -75,6 +76,20 @@ impl Client {
.updated(id) .updated(id)
} }
pub async fn mailbox_update_acl(
&self,
id: &str,
account_id: &str,
acl: impl IntoIterator<Item = ACL>,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
request.set_mailbox().update(id).acl(account_id, acl);
request
.send_single::<MailboxSetResponse>()
.await?
.updated(id)
}
pub async fn mailbox_update_sort_order( pub async fn mailbox_update_sort_order(
&self, &self,
id: &str, id: &str,
@ -104,7 +119,7 @@ impl Client {
pub async fn mailbox_get( pub async fn mailbox_get(
&self, &self,
id: &str, id: &str,
properties: Option<Vec<Property>>, properties: Option<impl IntoIterator<Item = Property>>,
) -> crate::Result<Option<Mailbox>> { ) -> crate::Result<Option<Mailbox>> {
let mut request = self.build(); let mut request = self.build();
let get_request = request.get_mailbox().ids([id]); let get_request = request.get_mailbox().ids([id]);

View File

@ -3,12 +3,14 @@ pub mod helpers;
pub mod query; pub mod query;
pub mod set; pub mod set;
use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use crate::core::changes::ChangesObject; use crate::core::changes::ChangesObject;
use crate::core::set::string_not_set; use crate::core::set::{map_not_set, string_not_set};
use crate::core::Object; use crate::core::Object;
use crate::mailbox::set::role_not_set; use crate::mailbox::set::role_not_set;
use crate::principal::ACL;
use crate::{Get, Set}; use crate::{Get, Set};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -84,6 +86,14 @@ pub struct Mailbox<State = Get> {
#[serde(rename = "isSubscribed")] #[serde(rename = "isSubscribed")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
is_subscribed: Option<bool>, is_subscribed: Option<bool>,
#[serde(skip_serializing_if = "map_not_set")]
acl: Option<HashMap<String, Vec<ACL>>>,
#[serde(flatten)]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "Option::is_none")]
acl_patch: Option<HashMap<String, Vec<ACL>>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -93,7 +103,7 @@ pub enum Role {
Archive, Archive,
#[serde(rename = "drafts", alias = "DRAFTS")] #[serde(rename = "drafts", alias = "DRAFTS")]
Drafts, Drafts,
#[serde(rename = "importante", alias = "IMPORTANT")] #[serde(rename = "important", alias = "IMPORTANT")]
Important, Important,
#[serde(rename = "inbox", alias = "INBOX")] #[serde(rename = "inbox", alias = "INBOX")]
Inbox, Inbox,
@ -160,6 +170,8 @@ pub enum Property {
MyRights, MyRights,
#[serde(rename = "isSubscribed")] #[serde(rename = "isSubscribed")]
IsSubscribed, IsSubscribed,
#[serde(rename = "acl")]
ACL,
} }
impl Display for Property { impl Display for Property {
@ -176,6 +188,7 @@ impl Display for Property {
Property::UnreadThreads => write!(f, "unreadThreads"), Property::UnreadThreads => write!(f, "unreadThreads"),
Property::MyRights => write!(f, "myRights"), Property::MyRights => write!(f, "myRights"),
Property::IsSubscribed => write!(f, "isSubscribed"), Property::IsSubscribed => write!(f, "isSubscribed"),
Property::ACL => write!(f, "acl"),
} }
} }
} }

View File

@ -1,4 +1,6 @@
use crate::{core::set::SetObject, Get, Set}; use std::collections::HashMap;
use crate::{core::set::SetObject, principal::ACL, Get, Set};
use super::{Mailbox, Role, SetArguments}; use super::{Mailbox, Role, SetArguments};
@ -31,6 +33,27 @@ impl Mailbox<Set> {
self.sort_order = sort_order.into(); self.sort_order = sort_order.into();
self self
} }
pub fn acls<T, U, V>(&mut self, acls: T) -> &mut Self
where
T: IntoIterator<Item = (U, V)>,
U: Into<String>,
V: IntoIterator<Item = ACL>,
{
self.acl = Some(
acls.into_iter()
.map(|(id, acls)| (id.into(), acls.into_iter().collect()))
.collect(),
);
self
}
pub fn acl(&mut self, id: &str, acl: impl IntoIterator<Item = ACL>) -> &mut Self {
self.acl_patch
.get_or_insert_with(HashMap::new)
.insert(format!("acl/{}", id), acl.into_iter().collect());
self
}
} }
pub fn role_not_set(role: &Option<Role>) -> bool { pub fn role_not_set(role: &Option<Role>) -> bool {
@ -55,6 +78,8 @@ impl SetObject for Mailbox<Set> {
unread_threads: None, unread_threads: None,
my_rights: None, my_rights: None,
is_subscribed: None, is_subscribed: None,
acl: HashMap::with_capacity(0).into(),
acl_patch: None,
} }
} }