Legal holds, step 4: freezing, release, and the audit log
Placing or widening a hold freezes what's already archived in its scope and range, its old deadline noted; releasing one gives each item no other hold covers that deadline back, or release plus 30 days if later. One pass over the archive does both and changes nothing twice (LH-6, LH-10, LH-11). A held archived item can't be destroyed; restoring still can, and the hold is named only to callers who may see holds (LH-7). Audit records about a held account survive the purge (AU-7). Fixes the daily clean-up of expired archived items (UD-13), which never found any: the registry's unfiltered query reads an all-ids index that archived items aren't in. Items are now walked account by account, kept deleted accounts included. Expired items were still removed whenever their account's archive was read.
This commit is contained in:
@@ -405,6 +405,11 @@ pub async fn set(
|
||||
response.updated.append(id, None);
|
||||
}
|
||||
|
||||
// LH-6, LH-10, LH-11: the archive follows what's now held
|
||||
if !response.created.is_empty() || !response.updated.is_empty() {
|
||||
server.settle_archive().await?;
|
||||
}
|
||||
|
||||
for id in request.unwrap_destroy().into_valid() {
|
||||
response.not_destroyed.append(
|
||||
id,
|
||||
|
||||
@@ -298,6 +298,33 @@ pub(crate) async fn set(mut set: RegistrySetResponse<'_>) -> trc::Result<Registr
|
||||
|
||||
for id in std::mem::take(&mut set.destroy) {
|
||||
match undelete::records::get(data, registry, account_id, id).await? {
|
||||
// inbuxa: LH-7: a held item can't be destroyed; restoring it
|
||||
// still can. The hold is named only to those who may see holds.
|
||||
Some(item)
|
||||
if inbuxa_features::hold::is_held_until(
|
||||
item.archived_until().timestamp().max(0) as u64,
|
||||
) =>
|
||||
{
|
||||
let mut why = "A legal hold applies to this item, so it can't be deleted.".to_string();
|
||||
if set
|
||||
.access_token
|
||||
.has_permission(registry::schema::enums::Permission::SysLegalHoldGet)
|
||||
{
|
||||
let names = set
|
||||
.server
|
||||
.holds_on(account_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|hold| hold.name)
|
||||
.collect::<Vec<_>>();
|
||||
if !names.is_empty() {
|
||||
why = format!("Held by {}, so it can't be deleted.", names.join(", "));
|
||||
}
|
||||
}
|
||||
set.response
|
||||
.not_destroyed
|
||||
.append(id, SetError::forbidden().with_description(why));
|
||||
}
|
||||
Some(item) => {
|
||||
undelete::records::remove(data, registry, id, &item).await?;
|
||||
set.response.destroyed.push(id);
|
||||
|
||||
Reference in New Issue
Block a user