feat(folders): implement copy_folders taking care of ownership

This commit is contained in:
Edouard Vanbelle
2026-05-11 22:58:33 +02:00
parent 85c8c086ac
commit 2f49daa4ee
7 changed files with 233 additions and 12 deletions
@@ -12,6 +12,7 @@ use tracing::info;
use crate::application::dtos::file_dto::FileDto;
use crate::application::dtos::folder_dto::{FolderDto, MoveFolderDto};
use crate::application::ports::file_ports::{FileManagementUseCase, FileRetrievalUseCase};
use crate::application::ports::storage_ports::CopyFolderTreeResult;
use crate::application::ports::inbound::FolderUseCase;
use crate::application::ports::trash_ports::TrashUseCase;
use crate::application::services::file_management_service::FileManagementService;
@@ -616,6 +617,73 @@ impl BatchOperationService {
Ok(result)
}
/// Copies multiple folder trees to a target parent in parallel
pub async fn copy_folders(
&self,
folder_ids: Vec<String>,
target_folder_id: Option<String>,
user_id: Uuid,
) -> Result<BatchResult<CopyFolderTreeResult>, BatchOperationError> {
info!("Starting batch copy of {} folders", folder_ids.len());
let start_time = std::time::Instant::now();
let mut result = BatchResult {
successful: Vec::new(),
failed: Vec::new(),
stats: BatchStats {
total: folder_ids.len(),
..Default::default()
},
};
let target: Option<Arc<str>> = target_folder_id.map(|s| Arc::from(s.as_str()));
let mut operation_stream = stream::iter(folder_ids.into_iter().map(|folder_id| {
let file_management = self.file_management.clone();
let target = target.clone();
async move {
let copy_result = file_management
.copy_folder_tree_owned(
&folder_id,
user_id,
target.map(|s| s.to_string()),
None,
)
.await;
(folder_id, copy_result)
}
}))
.buffer_unordered(self.config.concurrency.max_concurrent_files);
while let Some((folder_id, operation_result)) = operation_stream.next().await {
match operation_result {
Ok(copy_result) => {
result.successful.push(copy_result);
result.stats.successful += 1;
}
Err(e) => {
result.failed.push((folder_id, e.to_string()));
result.stats.failed += 1;
}
}
}
result.stats.execution_time_ms = start_time.elapsed().as_millis();
result.stats.max_concurrency = self
.config
.concurrency
.max_concurrent_files
.min(result.stats.total);
info!(
"Batch folder copy completed: {}/{} successful in {}ms",
result.stats.successful, result.stats.total, result.stats.execution_time_ms
);
Ok(result)
}
/// Downloads multiple files/folders as a single ZIP archive.
///
/// Writes the archive to a temporary file so RAM usage is O(buffer_size)