fix(quota): pre-check quota for COPY/MOVE
check qouta for a cross drive MOVE
check quota for a COPY
This commit is contained in:
@@ -31,6 +31,11 @@ pub struct FolderService {
|
||||
/// that case the cross-drive move check is skipped (the policy is
|
||||
/// silently off). Production DI wires it via `with_drive_repo`.
|
||||
drive_repo: Option<Arc<dyn crate::domain::repositories::drive_repository::DriveRepository>>,
|
||||
/// Storage-usage service — used to pre-check the destination
|
||||
/// drive's `used_bytes + subtree_bytes ≤ quota_bytes` invariant
|
||||
/// on cross-drive MOVE. Silently skipped when unwired (stubs).
|
||||
storage_usage:
|
||||
Option<Arc<crate::application::services::storage_usage_service::StorageUsageService>>,
|
||||
}
|
||||
|
||||
impl FolderService {
|
||||
@@ -45,6 +50,7 @@ impl FolderService {
|
||||
authz,
|
||||
file_lifecycle,
|
||||
drive_repo: None,
|
||||
storage_usage: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +66,19 @@ impl FolderService {
|
||||
self
|
||||
}
|
||||
|
||||
/// Wires the storage-usage service so `move_folder_with_perms`
|
||||
/// can pre-check the destination drive's quota on cross-drive
|
||||
/// folder moves.
|
||||
pub fn with_storage_usage(
|
||||
mut self,
|
||||
storage_usage: Arc<
|
||||
crate::application::services::storage_usage_service::StorageUsageService,
|
||||
>,
|
||||
) -> Self {
|
||||
self.storage_usage = Some(storage_usage);
|
||||
self
|
||||
}
|
||||
|
||||
/// Batch counterpart of `get_folder`: resolve many folder ids in ONE
|
||||
/// query instead of one per id. Like `get_folder` it performs no
|
||||
/// per-folder authorization — both current callers (ACL grant listing,
|
||||
@@ -593,6 +612,19 @@ impl FolderUseCase for FolderService {
|
||||
dst_drive_id,
|
||||
},
|
||||
)?;
|
||||
// Destination drive quota: sum the moved subtree's
|
||||
// non-trashed files and refuse if the destination
|
||||
// couldn't hold them. Same 507 shape as the file
|
||||
// path + upload path — DomainError::QuotaExceeded
|
||||
// maps at the AppError boundary.
|
||||
if let Some(storage_usage) = &self.storage_usage {
|
||||
let subtree_bytes = storage_usage.folder_subtree_bytes(src_folder_uuid).await?;
|
||||
if let Ok(subtree_u64) = u64::try_from(subtree_bytes) {
|
||||
storage_usage
|
||||
.check_drive_quota(dst_drive_id, subtree_u64)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
cross_drive = Some((src_drive_id, dst_drive_id));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user