Legal holds, step 3: deleted items in a held account are kept
Every way of deleting mail (JMAP, IMAP EXPUNGE, POP3, mailbox removal, Trash emptying) and Sieve scripts, events, contacts and files now asks how the account's deletions are kept: a hold keeps them with no expiry (archivedUntil 9999-12-31), even with undelete off; otherwise undelete's period applies as before (LH-4). A hold's date range decides by the item's own date (LH-3). Mail is noted as held at deletion and settled when it's archived, once its received date is known; outside the range it gets undelete's deadline or isn't kept. Events go by their start, with a day's slack for time zones; recurring events, contacts, files and scripts are held whole. A groupware item's note now stays until its archive succeeds, and a failure retries the task instead of being logged and lost (LH-5).
This commit is contained in:
@@ -97,6 +97,39 @@ pub async fn take(
|
||||
Ok(Some(note))
|
||||
}
|
||||
|
||||
/// A note, left in place: for a held account it's cleared only once its item
|
||||
/// is archived, so a failure leaves it for the retry (LH-5).
|
||||
pub async fn peek(
|
||||
data: &Store,
|
||||
kind: Kind,
|
||||
account_id: u32,
|
||||
document_id: u32,
|
||||
) -> trc::Result<Option<Note>> {
|
||||
Ok(data
|
||||
.get_value::<Json<Note>>(ValueKey::from(note_class(kind, account_id, document_id)))
|
||||
.await?
|
||||
.map(|Json(note)| note))
|
||||
}
|
||||
|
||||
/// Removes a note once its item is archived or needn't be.
|
||||
pub async fn clear(data: &Store, kind: Kind, account_id: u32, document_id: u32) -> trc::Result<()> {
|
||||
let mut batch = BatchBuilder::new();
|
||||
batch.clear(note_class(kind, account_id, document_id));
|
||||
data.write(batch.build_all()).await.map(|_| ())
|
||||
}
|
||||
|
||||
/// An event's start, for a hold's range (LH-3). None for a recurring event,
|
||||
/// which may have an occurrence anywhere, so a hold keeps it whole.
|
||||
pub fn event_start(note: &Note) -> Option<u64> {
|
||||
let text = note.content.as_deref()?;
|
||||
if property(text, "RRULE").is_some() || property(text, "RDATE").is_some() {
|
||||
return None;
|
||||
}
|
||||
property(text, "DTSTART")
|
||||
.and_then(|v| ical_time(&v))
|
||||
.map(|t| t.max(0) as u64)
|
||||
}
|
||||
|
||||
/// The value of the first line starting with `name` (as `NAME:` or
|
||||
/// `NAME;params:`) in iCalendar or vCard text, unfolded.
|
||||
fn property(text: &str, name: &str) -> Option<String> {
|
||||
|
||||
Reference in New Issue
Block a user