Propfind partial implementation
This commit is contained in:
@@ -100,59 +100,64 @@ impl MailboxDestroy for Server {
|
||||
// If the message is in multiple mailboxes, untag it from the current mailbox,
|
||||
// otherwise delete it.
|
||||
let mut destroy_ids = RoaringBitmap::new();
|
||||
for (message_id, message_data_) in self
|
||||
.get_properties::<Archive<AlignedBytes>, _>(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&message_ids,
|
||||
Property::Value,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
// Remove mailbox from list
|
||||
let prev_message_data = message_data_
|
||||
.to_unarchived::<MessageData>()
|
||||
.caused_by(trc::location!())?;
|
||||
let mut batch = BatchBuilder::new();
|
||||
|
||||
if !prev_message_data
|
||||
.inner
|
||||
.mailboxes
|
||||
.iter()
|
||||
.any(|id| id.mailbox_id == document_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
self.get_archives(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&message_ids,
|
||||
Property::Value,
|
||||
|message_id, message_data_| {
|
||||
// Remove mailbox from list
|
||||
let prev_message_data = message_data_
|
||||
.to_unarchived::<MessageData>()
|
||||
.caused_by(trc::location!())?;
|
||||
if !prev_message_data
|
||||
.inner
|
||||
.mailboxes
|
||||
.iter()
|
||||
.any(|id| id.mailbox_id == document_id)
|
||||
{
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if prev_message_data.inner.mailboxes.len() == 1 {
|
||||
// Delete message
|
||||
destroy_ids.insert(message_id);
|
||||
continue;
|
||||
}
|
||||
if prev_message_data.inner.mailboxes.len() == 1 {
|
||||
// Delete message
|
||||
destroy_ids.insert(message_id);
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let mut new_message_data = prev_message_data
|
||||
.deserialize()
|
||||
.caused_by(trc::location!())?;
|
||||
let thread_id = new_message_data.thread_id;
|
||||
let mut new_message_data = prev_message_data
|
||||
.deserialize()
|
||||
.caused_by(trc::location!())?;
|
||||
let thread_id = new_message_data.thread_id;
|
||||
|
||||
new_message_data
|
||||
.mailboxes
|
||||
.retain(|id| id.mailbox_id != document_id);
|
||||
new_message_data
|
||||
.mailboxes
|
||||
.retain(|id| id.mailbox_id != document_id);
|
||||
|
||||
// Untag message from mailbox
|
||||
let mut batch = BatchBuilder::new();
|
||||
batch
|
||||
.with_account_id(account_id)
|
||||
.with_collection(Collection::Email)
|
||||
.update_document(message_id)
|
||||
.custom(
|
||||
ObjectIndexBuilder::new()
|
||||
.with_changes(new_message_data)
|
||||
.with_current(prev_message_data),
|
||||
)
|
||||
.caused_by(trc::location!())?;
|
||||
// Untag message from mailbox
|
||||
batch
|
||||
.with_account_id(account_id)
|
||||
.with_collection(Collection::Email)
|
||||
.update_document(message_id)
|
||||
.custom(
|
||||
ObjectIndexBuilder::new()
|
||||
.with_changes(new_message_data)
|
||||
.with_current(prev_message_data),
|
||||
)
|
||||
.caused_by(trc::location!())?;
|
||||
changes
|
||||
.log_update(Collection::Email, Id::from_parts(thread_id, message_id));
|
||||
Ok(true)
|
||||
},
|
||||
)
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
|
||||
if !batch.is_empty() {
|
||||
match self.core.storage.data.write(batch.build()).await {
|
||||
Ok(_) => changes
|
||||
.log_update(Collection::Email, Id::from_parts(thread_id, message_id)),
|
||||
Ok(_) => {}
|
||||
Err(err) if err.is_assertion_failure() => {
|
||||
return Ok(Err(SetError::forbidden().with_description(concat!(
|
||||
"Another process modified a message in this mailbox ",
|
||||
|
||||
@@ -58,7 +58,7 @@ impl EmailDeletion for Server {
|
||||
async fn emails_tombstone(
|
||||
&self,
|
||||
account_id: u32,
|
||||
mut document_ids: RoaringBitmap,
|
||||
document_ids: RoaringBitmap,
|
||||
) -> trc::Result<(ChangeLogBuilder, RoaringBitmap)> {
|
||||
// Create batch
|
||||
let mut changes = ChangeLogBuilder::with_change_id(0);
|
||||
@@ -68,69 +68,73 @@ impl EmailDeletion for Server {
|
||||
batch
|
||||
.with_account_id(account_id)
|
||||
.with_collection(Collection::Email);
|
||||
let mut batches = Vec::new();
|
||||
let mut deleted_ids = RoaringBitmap::new();
|
||||
self.get_archives(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&document_ids,
|
||||
Property::Value,
|
||||
|document_id, data_| {
|
||||
let data = data_
|
||||
.to_unarchived::<MessageData>()
|
||||
.caused_by(trc::location!())?;
|
||||
let thread_id = u32::from(data.inner.thread_id);
|
||||
|
||||
for (document_id, data_) in self
|
||||
.get_properties::<Archive<AlignedBytes>, _>(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&document_ids,
|
||||
Property::Value,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
let data = data_
|
||||
.to_unarchived::<MessageData>()
|
||||
.caused_by(trc::location!())?;
|
||||
let thread_id = u32::from(data.inner.thread_id);
|
||||
// Log mailbox changes
|
||||
for mailbox in data.inner.mailboxes.iter() {
|
||||
changes.log_child_update(Collection::Mailbox, u32::from(mailbox.mailbox_id));
|
||||
}
|
||||
|
||||
// Log mailbox changes
|
||||
for mailbox in data.inner.mailboxes.iter() {
|
||||
changes.log_child_update(Collection::Mailbox, u32::from(mailbox.mailbox_id));
|
||||
}
|
||||
// Log message deletion
|
||||
changes.log_delete(Collection::Email, Id::from_parts(thread_id, document_id));
|
||||
|
||||
// Log message deletion
|
||||
changes.log_delete(Collection::Email, Id::from_parts(thread_id, document_id));
|
||||
// Log thread changes
|
||||
changes.log_child_update(Collection::Thread, thread_id);
|
||||
|
||||
// Log thread changes
|
||||
changes.log_child_update(Collection::Thread, thread_id);
|
||||
// Add changes to batch
|
||||
batch
|
||||
.update_document(document_id)
|
||||
.custom(ObjectIndexBuilder::<_, ()>::new().with_current(data))
|
||||
.caused_by(trc::location!())?
|
||||
.tag(
|
||||
Property::MailboxIds,
|
||||
TagValue::Id(MaybeDynamicId::Static(TOMBSTONE_ID)),
|
||||
);
|
||||
|
||||
// Add changes to batch
|
||||
batch
|
||||
.update_document(document_id)
|
||||
.custom(ObjectIndexBuilder::<_, ()>::new().with_current(data))
|
||||
.caused_by(trc::location!())?
|
||||
.tag(
|
||||
Property::MailboxIds,
|
||||
TagValue::Id(MaybeDynamicId::Static(TOMBSTONE_ID)),
|
||||
);
|
||||
deleted_ids.insert(document_id);
|
||||
|
||||
document_ids.remove(document_id);
|
||||
if batch.ops.len() >= 1000 {
|
||||
batches.push(std::mem::replace(&mut batch, BatchBuilder::new()));
|
||||
batch
|
||||
.with_account_id(account_id)
|
||||
.with_collection(Collection::Email);
|
||||
}
|
||||
|
||||
if batch.ops.len() >= 1000 {
|
||||
Ok(true)
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
for batch in batches.into_iter().chain([batch]) {
|
||||
if !batch.is_empty() {
|
||||
self.core
|
||||
.storage
|
||||
.data
|
||||
.write(batch.build())
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
|
||||
batch = BatchBuilder::new();
|
||||
batch
|
||||
.with_account_id(account_id)
|
||||
.with_collection(Collection::Email);
|
||||
}
|
||||
}
|
||||
|
||||
if !batch.ops.is_empty() {
|
||||
self.core
|
||||
.storage
|
||||
.data
|
||||
.write(batch.build())
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
}
|
||||
let not_destroyed = if document_ids.len() == deleted_ids.len() {
|
||||
RoaringBitmap::new()
|
||||
} else {
|
||||
deleted_ids ^= document_ids;
|
||||
deleted_ids
|
||||
};
|
||||
|
||||
Ok((changes, document_ids))
|
||||
Ok((changes, not_destroyed))
|
||||
}
|
||||
|
||||
async fn purge_accounts(&self) {
|
||||
@@ -240,19 +244,20 @@ impl EmailDeletion for Server {
|
||||
|
||||
// Find messages to destroy
|
||||
let mut destroy_ids = RoaringBitmap::new();
|
||||
for (document_id, data) in self
|
||||
.get_properties::<Archive<AlignedBytes>, _>(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&deletion_candidates,
|
||||
Property::Value,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
if data.unarchive::<MessageData>()?.change_id < reference_cid {
|
||||
destroy_ids.insert(document_id);
|
||||
}
|
||||
}
|
||||
self.get_archives(
|
||||
account_id,
|
||||
Collection::Email,
|
||||
&deletion_candidates,
|
||||
Property::Value,
|
||||
|document_id, data| {
|
||||
if data.unarchive::<MessageData>()?.change_id < reference_cid {
|
||||
destroy_ids.insert(document_id);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
if destroy_ids.is_empty() {
|
||||
return Ok(());
|
||||
|
||||
Reference in New Issue
Block a user