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 {
session: Session,
session_url: String,
session_outdated: AtomicBool,
session_updated: AtomicBool,
#[cfg(feature = "websockets")]
pub(crate) authorization: String,
upload_url: Vec<URLPart<blob::URLParameter>>,
@ -91,7 +91,7 @@ impl Client {
event_source_url: URLPart::parse(session.event_source_url())?,
session,
session_url: url.to_string(),
session_outdated: false.into(),
session_updated: true.into(),
#[cfg(feature = "websockets")]
authorization,
timeout: DEFAULT_TIMEOUT_MS,
@ -147,7 +147,7 @@ impl Client {
)?;
if response.session_state() != self.session.state() {
self.session_outdated.store(true, Ordering::Relaxed);
self.session_updated.store(false, Ordering::Relaxed);
}
Ok(response)
@ -172,12 +172,12 @@ impl Client {
self.upload_url = URLPart::parse(session.upload_url())?;
self.event_source_url = URLPart::parse(session.event_source_url())?;
self.session = session;
self.session_outdated.store(false, Ordering::Relaxed);
self.session_updated.store(true, Ordering::Relaxed);
Ok(())
}
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 {

View File

@ -143,7 +143,7 @@ impl Client {
pub async fn email_query(
&self,
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> {
let mut request = self.build();
let query_request = request.query_email();

View File

@ -181,8 +181,8 @@ pub struct Email<State = Get> {
#[serde(flatten)]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "HashMap::is_empty")]
patch: HashMap<String, bool>,
#[serde(skip_serializing_if = "Option::is_none")]
patch: Option<HashMap<String, bool>>,
}
#[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 {
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
}
@ -47,7 +49,9 @@ impl Email<Set> {
pub fn keyword(&mut self, keyword: &str, set: bool) -> &mut Self {
self.keywords = None;
self.patch.insert(format!("keywords/{}", keyword), set);
self.patch
.get_or_insert_with(HashMap::new)
.insert(format!("keywords/{}", keyword), set);
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> {
pub fn id(&self) -> &str {
@ -47,40 +49,70 @@ impl Mailbox<Get> {
*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 {
self.my_rights.as_ref().unwrap().may_read_items
self.may_read_items
}
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 {
self.my_rights.as_ref().unwrap().may_remove_items
self.may_remove_items
}
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 {
self.my_rights.as_ref().unwrap().may_set_keywords
self.may_set_keywords
}
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 {
self.my_rights.as_ref().unwrap().may_rename
self.may_rename
}
pub fn may_delete(&self) -> bool {
self.my_rights.as_ref().unwrap().may_delete
self.may_delete
}
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},
set::{SetObject, SetRequest},
},
principal::ACL,
Get, Method, Set,
};
@ -75,6 +76,20 @@ impl Client {
.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(
&self,
id: &str,
@ -104,7 +119,7 @@ impl Client {
pub async fn mailbox_get(
&self,
id: &str,
properties: Option<Vec<Property>>,
properties: Option<impl IntoIterator<Item = Property>>,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
let get_request = request.get_mailbox().ids([id]);

View File

@ -3,12 +3,14 @@ pub mod helpers;
pub mod query;
pub mod set;
use std::collections::HashMap;
use std::fmt::Display;
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::mailbox::set::role_not_set;
use crate::principal::ACL;
use crate::{Get, Set};
use serde::{Deserialize, Serialize};
@ -84,6 +86,14 @@ pub struct Mailbox<State = Get> {
#[serde(rename = "isSubscribed")]
#[serde(skip_serializing_if = "Option::is_none")]
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)]
@ -93,7 +103,7 @@ pub enum Role {
Archive,
#[serde(rename = "drafts", alias = "DRAFTS")]
Drafts,
#[serde(rename = "importante", alias = "IMPORTANT")]
#[serde(rename = "important", alias = "IMPORTANT")]
Important,
#[serde(rename = "inbox", alias = "INBOX")]
Inbox,
@ -160,6 +170,8 @@ pub enum Property {
MyRights,
#[serde(rename = "isSubscribed")]
IsSubscribed,
#[serde(rename = "acl")]
ACL,
}
impl Display for Property {
@ -176,6 +188,7 @@ impl Display for Property {
Property::UnreadThreads => write!(f, "unreadThreads"),
Property::MyRights => write!(f, "myRights"),
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};
@ -31,6 +33,27 @@ impl Mailbox<Set> {
self.sort_order = sort_order.into();
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 {
@ -55,6 +78,8 @@ impl SetObject for Mailbox<Set> {
unread_threads: None,
my_rights: None,
is_subscribed: None,
acl: HashMap::with_capacity(0).into(),
acl_patch: None,
}
}