DAV file management delete

This commit is contained in:
mdecimus
2025-03-07 19:06:06 +01:00
parent eadd36f4cb
commit 110ec14fe6
40 changed files with 1162 additions and 416 deletions

View File

@@ -101,7 +101,7 @@ impl MailboxDestroy for Server {
// otherwise delete it.
let mut destroy_ids = RoaringBitmap::new();
for (message_id, mailbox_ids) in self
.get_properties::<HashedValue<Archive>, _, _>(
.get_properties::<HashedValue<Archive>, _>(
account_id,
Collection::Email,
&message_ids,
@@ -190,7 +190,7 @@ impl MailboxDestroy for Server {
}
// Obtain mailbox
if let Some(mailbox) = self
if let Some(mailbox_) = self
.get_property::<HashedValue<Archive>>(
account_id,
Collection::Mailbox,
@@ -200,8 +200,8 @@ impl MailboxDestroy for Server {
.await
.caused_by(trc::location!())?
{
let mailbox = mailbox
.into_deserialized::<Mailbox>()
let mailbox = mailbox_
.to_unarchived::<Mailbox>()
.caused_by(trc::location!())?;
// Validate ACLs
if access_token.is_shared(account_id) {
@@ -224,7 +224,7 @@ impl MailboxDestroy for Server {
.with_collection(Collection::Mailbox)
.delete_document(document_id)
.clear(Property::EmailIds)
.custom(ObjectIndexBuilder::new().with_current(mailbox))
.custom(ObjectIndexBuilder::<_, ()>::new().with_current(mailbox))
.caused_by(trc::location!())?;
match self.core.storage.data.write(batch.build()).await {

View File

@@ -5,13 +5,13 @@
*/
use common::{
config::jmap::settings::SpecialUse,
config::jmap::settings::{ArchivedSpecialUse, SpecialUse},
storage::{
folder::FolderHierarchy,
index::{IndexValue, IndexableObject},
index::{IndexValue, IndexableAndSerializableObject, IndexableObject},
},
};
use jmap_proto::types::property::Property;
use jmap_proto::types::{property::Property, value::AclGrant};
use store::write::{MaybeDynamicId, TagValue};
use super::{ArchivedMailbox, ArchivedUidMailbox, Mailbox, UidMailbox};
@@ -41,14 +41,63 @@ impl IndexableObject for Mailbox {
},
IndexValue::U32List {
field: Property::IsSubscribed.into(),
value: &self.subscribers,
value: (&self.subscribers).into(),
},
IndexValue::Acl {
value: (&self.acls).into(),
},
IndexValue::Acl { value: &self.acls },
]
.into_iter()
}
}
impl IndexableObject for &ArchivedMailbox {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
[
IndexValue::Text {
field: Property::Name.into(),
value: self.name.to_lowercase().into(),
},
IndexValue::Text {
field: Property::Role.into(),
value: self.role.as_str().unwrap_or_default().into(),
},
IndexValue::Tag {
field: Property::Role.into(),
is_set: !matches!(self.role, ArchivedSpecialUse::None),
},
IndexValue::U32 {
field: Property::ParentId.into(),
value: u32::from(self.parent_id).into(),
},
IndexValue::U32 {
field: Property::SortOrder.into(),
value: self.sort_order.as_ref().map(u32::from),
},
IndexValue::U32List {
field: Property::IsSubscribed.into(),
value: self
.subscribers
.iter()
.map(u32::from)
.collect::<Vec<_>>()
.into(),
},
IndexValue::Acl {
value: self
.acls
.iter()
.map(AclGrant::from)
.collect::<Vec<_>>()
.into(),
},
]
.into_iter()
}
}
impl IndexableAndSerializableObject for Mailbox {}
impl FolderHierarchy for ArchivedMailbox {
fn name(&self) -> String {
self.name.to_string()
@@ -57,6 +106,10 @@ impl FolderHierarchy for ArchivedMailbox {
fn parent_id(&self) -> u32 {
u32::from(self.parent_id)
}
fn is_container(&self) -> bool {
true
}
}
impl From<&UidMailbox> for TagValue<MaybeDynamicId> {

View File

@@ -102,7 +102,7 @@ impl MailboxFnc for Server {
}
batch
.create_document_with_id(document_id)
.custom(ObjectIndexBuilder::new().with_changes(object))
.custom(ObjectIndexBuilder::<(), _>::new().with_changes(object))
.caused_by(trc::location!())?;
mailbox_ids.insert(document_id);
}
@@ -133,7 +133,7 @@ impl MailboxFnc for Server {
}
})
.into_iterator()
.map(|(document_id, name)| (name, document_id))
.map(|e| (e.name, e.document_id))
.collect::<AHashMap<String, u32>>();
let mut next_parent_id = 0;
@@ -177,7 +177,7 @@ impl MailboxFnc for Server {
.with_collection(Collection::Mailbox)
.create_document()
.custom(
ObjectIndexBuilder::new()
ObjectIndexBuilder::<(), _>::new()
.with_changes(Mailbox::new(name).with_parent_id(next_parent_id)),
)
.caused_by(trc::location!())?;
@@ -275,8 +275,8 @@ impl MailboxFnc for Server {
folders
.format(|mailbox_id, _| (mailbox_id == INBOX_ID).then(|| "INBOX".to_string()))
.into_iterator()
.find(|(_, folder_name)| folder_name.eq_ignore_ascii_case(path))
.map(|(document_id, _)| document_id)
.find(|e| e.name.eq_ignore_ascii_case(path))
.map(|e| e.document_id)
})
}

View File

@@ -20,6 +20,7 @@ pub const ARCHIVE_ID: u32 = 5;
pub const TOMBSTONE_ID: u32 = u32::MAX - 1;
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone, PartialEq, Eq)]
#[rkyv(derive(Debug))]
pub struct Mailbox {
pub name: String,
pub role: SpecialUse,

View File

@@ -64,7 +64,7 @@ impl EmailDeletion for Server {
// Fetch mailboxes and threadIds
let mut thread_ids: AHashMap<u32, i32> = AHashMap::new();
for (document_id, mailboxes) in self
.get_properties::<Archive, _, _>(
.get_properties::<Archive, _>(
account_id,
Collection::Email,
&document_ids,
@@ -86,7 +86,7 @@ impl EmailDeletion for Server {
);
}
for (document_id, thread_id) in self
.get_properties::<u32, _, _>(
.get_properties::<u32, _>(
account_id,
Collection::Email,
&document_ids,
@@ -343,7 +343,7 @@ impl EmailDeletion for Server {
// Find messages to destroy
let mut destroy_ids = RoaringBitmap::new();
for (document_id, cid) in self
.get_properties::<u64, _, _>(
.get_properties::<u64, _>(
account_id,
Collection::Email,
&deletion_candidates,

View File

@@ -29,7 +29,7 @@ impl SieveScriptDelete for Server {
) -> trc::Result<bool> {
// Fetch record
let account_id = resource_token.account_id;
let obj = self
let obj_ = self
.get_property::<HashedValue<Archive>>(
account_id,
Collection::SieveScript,
@@ -42,8 +42,9 @@ impl SieveScriptDelete for Server {
.into_err()
.caused_by(trc::location!())
.document_id(document_id)
})?
.into_deserialized::<SieveScript>()
})?;
let obj = obj_
.to_unarchived::<SieveScript>()
.caused_by(trc::location!())?;
// Make sure the script is not active
@@ -59,7 +60,7 @@ impl SieveScriptDelete for Server {
.delete_document(document_id)
.clear(Property::EmailIds)
.custom(
ObjectIndexBuilder::new()
ObjectIndexBuilder::<_, ()>::new()
.with_current(obj)
.with_tenant_id(resource_token),
)

View File

@@ -4,10 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use common::storage::index::{IndexValue, IndexableObject};
use common::storage::index::{IndexValue, IndexableAndSerializableObject, IndexableObject};
use jmap_proto::types::property::Property;
use super::SieveScript;
use super::{ArchivedSieveScript, SieveScript};
impl IndexableObject for SieveScript {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
@@ -28,3 +28,27 @@ impl IndexableObject for SieveScript {
.into_iter()
}
}
impl IndexableAndSerializableObject for SieveScript {}
impl IndexableObject for &ArchivedSieveScript {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
[
IndexValue::Text {
field: Property::Name.into(),
value: self.name.to_lowercase().into(),
},
IndexValue::U32 {
field: Property::IsActive.into(),
value: Some(self.is_active as u32),
},
IndexValue::Blob {
value: (&self.blob_hash).into(),
},
IndexValue::Quota {
used: u32::from(self.size),
},
]
.into_iter()
}
}

View File

@@ -40,6 +40,7 @@ pub struct SeenIds {
#[derive(
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
)]
#[rkyv(derive(Debug))]
pub struct SieveScript {
pub name: String,
pub is_active: bool,
@@ -51,6 +52,7 @@ pub struct SieveScript {
#[derive(
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
)]
#[rkyv(derive(Debug))]
pub struct VacationResponse {
pub from_date: Option<u64>,
pub to_date: Option<u64>,

View File

@@ -4,10 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use common::storage::index::{IndexValue, IndexableObject};
use common::storage::index::{IndexValue, IndexableAndSerializableObject, IndexableObject};
use jmap_proto::types::property::Property;
use super::EmailSubmission;
use super::{ArchivedEmailSubmission, EmailSubmission};
impl IndexableObject for EmailSubmission {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
@@ -36,3 +36,33 @@ impl IndexableObject for EmailSubmission {
.into_iter()
}
}
impl IndexableObject for &ArchivedEmailSubmission {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
[
IndexValue::Text {
field: Property::UndoStatus.into(),
value: self.undo_status.as_index().into(),
},
IndexValue::U32 {
field: Property::EmailId.into(),
value: Some(u32::from(self.email_id)),
},
IndexValue::U32 {
field: Property::ThreadId.into(),
value: Some(u32::from(self.thread_id)),
},
IndexValue::U32 {
field: Property::IdentityId.into(),
value: Some(u32::from(self.identity_id)),
},
IndexValue::U64 {
field: Property::SendAt.into(),
value: Some(u64::from(self.send_at)),
},
]
.into_iter()
}
}
impl IndexableAndSerializableObject for EmailSubmission {}

View File

@@ -47,7 +47,7 @@ impl ThreadCache for Server {
} else {
let thread_cache = Arc::new(Threads {
threads: self
.get_properties::<u32, _, _>(
.get_properties::<u32, _>(
account_id,
Collection::Email,
&(),