feat(drive): complete updated_by created_by
This commit is contained in:
@@ -623,6 +623,7 @@ impl DeltaUploadService {
|
||||
Some(folder_id.clone()),
|
||||
content_type,
|
||||
blob,
|
||||
caller_id,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ impl FileManagementService {
|
||||
&self,
|
||||
file_id: &str,
|
||||
folder_id: Option<String>,
|
||||
caller_id: Uuid,
|
||||
) -> Result<FileDto, DomainError> {
|
||||
info!(
|
||||
"Moving file with ID: {} to folder: {:?}",
|
||||
@@ -106,7 +107,7 @@ impl FileManagementService {
|
||||
|
||||
let moved_file = self
|
||||
.file_repository
|
||||
.move_file(file_id, folder_id)
|
||||
.move_file(file_id, folder_id, caller_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Error moving file (ID: {}): {}", file_id, e);
|
||||
@@ -128,6 +129,7 @@ impl FileManagementService {
|
||||
file_id: &str,
|
||||
target_folder_id: Option<String>,
|
||||
new_name: Option<&str>,
|
||||
caller_id: Uuid,
|
||||
) -> Result<FileDto, DomainError> {
|
||||
info!(
|
||||
"Copying file with ID: {} to folder: {:?} as {:?}",
|
||||
@@ -136,7 +138,7 @@ impl FileManagementService {
|
||||
|
||||
let copied_file = self
|
||||
.file_repository
|
||||
.copy_file(file_id, target_folder_id, new_name)
|
||||
.copy_file(file_id, target_folder_id, new_name, caller_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Error copying file (ID: {}): {}", file_id, e);
|
||||
@@ -157,7 +159,12 @@ impl FileManagementService {
|
||||
Ok(dto)
|
||||
}
|
||||
|
||||
async fn rename_file(&self, file_id: &str, new_name: &str) -> Result<FileDto, DomainError> {
|
||||
async fn rename_file(
|
||||
&self,
|
||||
file_id: &str,
|
||||
new_name: &str,
|
||||
caller_id: Uuid,
|
||||
) -> Result<FileDto, DomainError> {
|
||||
if let Err(reason) = validate_storage_name(new_name) {
|
||||
return Err(DomainError::validation_error(format!(
|
||||
"Invalid file name '{new_name}': {reason}"
|
||||
@@ -168,7 +175,7 @@ impl FileManagementService {
|
||||
|
||||
let renamed_file = self
|
||||
.file_repository
|
||||
.rename_file(file_id, new_name)
|
||||
.rename_file(file_id, new_name, caller_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Error renaming file (ID: {}): {}", file_id, e);
|
||||
@@ -253,7 +260,7 @@ impl FileManagementUseCase for FileManagementService {
|
||||
.await?;
|
||||
self.require_target_folder_perm(folder_id.as_deref(), Permission::Create, caller_id)
|
||||
.await?;
|
||||
self.move_file(file_id, folder_id).await
|
||||
self.move_file(file_id, folder_id, caller_id).await
|
||||
}
|
||||
|
||||
async fn copy_file_with_perms(
|
||||
@@ -268,7 +275,7 @@ impl FileManagementUseCase for FileManagementService {
|
||||
.await?;
|
||||
self.require_target_folder_perm(target_folder_id.as_deref(), Permission::Create, caller_id)
|
||||
.await?;
|
||||
self.copy_file(file_id, target_folder_id, new_name.as_deref())
|
||||
self.copy_file(file_id, target_folder_id, new_name.as_deref(), caller_id)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -280,7 +287,7 @@ impl FileManagementUseCase for FileManagementService {
|
||||
) -> Result<FileDto, DomainError> {
|
||||
self.require_file_perm(file_id, Permission::Update, caller_id)
|
||||
.await?;
|
||||
self.rename_file(file_id, new_name).await
|
||||
self.rename_file(file_id, new_name, caller_id).await
|
||||
}
|
||||
|
||||
async fn delete_file_with_perms(&self, id: &str, caller_id: Uuid) -> Result<(), DomainError> {
|
||||
|
||||
@@ -209,6 +209,7 @@ impl FileUploadService {
|
||||
size: metadata.size,
|
||||
is_new_blob: false,
|
||||
},
|
||||
caller_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -255,7 +256,7 @@ impl FileUploadService {
|
||||
let file = file_read.get_file(file_id).await?;
|
||||
let (new_hash, updated_at) = self
|
||||
.file_write
|
||||
.update_file_content_with_blob(file_id, &blob.hash, blob.size, None)
|
||||
.update_file_content_with_blob(file_id, &blob.hash, blob.size, None, caller_id)
|
||||
.await?;
|
||||
// The file maps to a different blob now — stale cached content must
|
||||
// never be served for the rest of its TTI window.
|
||||
@@ -326,10 +327,18 @@ impl FileUploadUseCase for FileUploadService {
|
||||
folder_id: Option<String>,
|
||||
content_type: String,
|
||||
blob: StoredBlob,
|
||||
caller_id: Uuid,
|
||||
) -> Result<FileDto, DomainError> {
|
||||
let file = self
|
||||
.file_write
|
||||
.save_file_with_blob(name.clone(), folder_id, content_type, &blob.hash, blob.size)
|
||||
.save_file_with_blob(
|
||||
name.clone(),
|
||||
folder_id,
|
||||
content_type,
|
||||
&blob.hash,
|
||||
blob.size,
|
||||
caller_id,
|
||||
)
|
||||
.await?;
|
||||
let dto = FileDto::from(file);
|
||||
info!(
|
||||
@@ -352,6 +361,7 @@ impl FileUploadUseCase for FileUploadService {
|
||||
blob: StoredBlob,
|
||||
content_type: &str,
|
||||
modified_at: Option<i64>,
|
||||
caller_id: Uuid,
|
||||
) -> Result<FileDto, DomainError> {
|
||||
// Try to find the existing file first
|
||||
if let Some(file_read) = &self.file_read
|
||||
@@ -360,7 +370,13 @@ impl FileUploadUseCase for FileUploadService {
|
||||
let file_id = file.id().to_string();
|
||||
let (new_hash, updated_at) = self
|
||||
.file_write
|
||||
.update_file_content_with_blob(&file_id, &blob.hash, blob.size, modified_at)
|
||||
.update_file_content_with_blob(
|
||||
&file_id,
|
||||
&blob.hash,
|
||||
blob.size,
|
||||
modified_at,
|
||||
caller_id,
|
||||
)
|
||||
.await?;
|
||||
// Invalidate content cache — file content has changed.
|
||||
if let Some(cc) = &self.content_cache {
|
||||
@@ -428,6 +444,7 @@ impl FileUploadUseCase for FileUploadService {
|
||||
content_type.to_string(),
|
||||
&blob.hash,
|
||||
blob.size,
|
||||
caller_id,
|
||||
)
|
||||
.await?;
|
||||
let dto = FileDto::from(created);
|
||||
|
||||
@@ -234,7 +234,7 @@ impl FolderUseCase for FolderService {
|
||||
|
||||
let folder = self
|
||||
.folder_storage
|
||||
.create_folder(dto.name, dto.parent_id)
|
||||
.create_folder(dto.name, dto.parent_id, caller_id)
|
||||
.await?;
|
||||
Ok(FolderDto::from(folder))
|
||||
}
|
||||
@@ -489,7 +489,7 @@ impl FolderUseCase for FolderService {
|
||||
|
||||
let folder = self
|
||||
.folder_storage
|
||||
.rename_folder(id, dto.name)
|
||||
.rename_folder(id, dto.name, caller_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::internal_error(
|
||||
@@ -541,7 +541,7 @@ impl FolderUseCase for FolderService {
|
||||
let parent_ref = dto.parent_id.as_deref();
|
||||
let folder = self
|
||||
.folder_storage
|
||||
.move_folder(id, parent_ref)
|
||||
.move_folder(id, parent_ref, caller_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::internal_error(
|
||||
|
||||
@@ -184,6 +184,7 @@ impl FileWritePort for MockFileWritePort {
|
||||
_content_type: String,
|
||||
_blob_hash: &str,
|
||||
_size: u64,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -192,6 +193,7 @@ impl FileWritePort for MockFileWritePort {
|
||||
&self,
|
||||
file_id: &str,
|
||||
_target_folder_id: Option<String>,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<File, DomainError> {
|
||||
let files = self.files.lock().unwrap();
|
||||
files
|
||||
@@ -200,7 +202,12 @@ impl FileWritePort for MockFileWritePort {
|
||||
.ok_or_else(|| DomainError::not_found("File", file_id.to_string()))
|
||||
}
|
||||
|
||||
async fn rename_file(&self, file_id: &str, _new_name: &str) -> Result<File, DomainError> {
|
||||
async fn rename_file(
|
||||
&self,
|
||||
file_id: &str,
|
||||
_new_name: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<File, DomainError> {
|
||||
let files = self.files.lock().unwrap();
|
||||
files
|
||||
.get(file_id)
|
||||
@@ -218,6 +225,7 @@ impl FileWritePort for MockFileWritePort {
|
||||
_blob_hash: &str,
|
||||
_size: u64,
|
||||
_modified_at: Option<i64>,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<(String, i64), DomainError> {
|
||||
Ok((String::new(), 0))
|
||||
}
|
||||
@@ -228,6 +236,7 @@ impl FileWritePort for MockFileWritePort {
|
||||
_folder_id: Option<String>,
|
||||
_content_type: String,
|
||||
_size: u64,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<(File, PathBuf), DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -237,11 +246,12 @@ impl FileWritePort for MockFileWritePort {
|
||||
_file_id: &str,
|
||||
_target_folder_id: Option<String>,
|
||||
_new_name: Option<&str>,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn move_to_trash(&self, _file_id: &str) -> Result<(), DomainError> {
|
||||
async fn move_to_trash(&self, _file_id: &str, _caller_id: Uuid) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -249,6 +259,7 @@ impl FileWritePort for MockFileWritePort {
|
||||
&self,
|
||||
_file_id: &str,
|
||||
_original_path: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -906,6 +906,7 @@ mod tests {
|
||||
&self,
|
||||
_name: String,
|
||||
_parent_id: Option<String>,
|
||||
_caller_id: uuid::Uuid,
|
||||
) -> Result<crate::domain::entities::folder::Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -980,6 +981,7 @@ mod tests {
|
||||
&self,
|
||||
_id: &str,
|
||||
_new_name: String,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<crate::domain::entities::folder::Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -988,6 +990,7 @@ mod tests {
|
||||
&self,
|
||||
_id: &str,
|
||||
_new_parent_id: Option<&str>,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<crate::domain::entities::folder::Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -1011,7 +1014,11 @@ mod tests {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn move_to_trash(&self, _folder_id: &str) -> Result<(), DomainError> {
|
||||
async fn move_to_trash(
|
||||
&self,
|
||||
_folder_id: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<(), DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -1019,6 +1026,7 @@ mod tests {
|
||||
&self,
|
||||
_folder_id: &str,
|
||||
_original_path: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> Result<(), DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -253,9 +253,10 @@ impl TrashUseCase for TrashService {
|
||||
}
|
||||
};
|
||||
|
||||
// Then physically move the file to trash
|
||||
// Then physically move the file to trash.
|
||||
// §14: caller_id stamps `updated_by` on the trashed row.
|
||||
info!("Physically moving file to trash: {}", item_id);
|
||||
match self.file_write_port.move_to_trash(item_id).await {
|
||||
match self.file_write_port.move_to_trash(item_id, user_id).await {
|
||||
Ok(_) => {
|
||||
debug!("File physically moved to trash successfully: {}", item_id);
|
||||
}
|
||||
@@ -320,9 +321,10 @@ impl TrashUseCase for TrashService {
|
||||
}
|
||||
};
|
||||
|
||||
// Then physically move the folder to trash
|
||||
// Then physically move the folder to trash.
|
||||
// §14: caller_id stamps `updated_by` on every cascade-trashed row.
|
||||
self.folder_storage_port
|
||||
.move_to_trash(item_id)
|
||||
.move_to_trash(item_id, user_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::new(
|
||||
@@ -391,7 +393,7 @@ impl TrashUseCase for TrashService {
|
||||
);
|
||||
match self
|
||||
.file_write_port
|
||||
.restore_from_trash(&file_id, &original_path)
|
||||
.restore_from_trash(&file_id, &original_path, user_id)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
@@ -431,7 +433,7 @@ impl TrashUseCase for TrashService {
|
||||
);
|
||||
match self
|
||||
.folder_storage_port
|
||||
.restore_from_trash(&folder_id, &original_path)
|
||||
.restore_from_trash(&folder_id, &original_path, user_id)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
@@ -831,6 +833,9 @@ fn row_to_item_dto(row: TrashResourceRow) -> TrashResourceItemDto {
|
||||
icon_class: std::sync::Arc::from("fas fa-folder"),
|
||||
icon_special_class: std::sync::Arc::from("folder-icon"),
|
||||
category: std::sync::Arc::from("Folder"),
|
||||
// §14 provenance not selected by the trash listing query.
|
||||
created_by: None,
|
||||
updated_by: None,
|
||||
};
|
||||
TrashResourceItemDto {
|
||||
resource_type: ResourceTypeDto::Folder,
|
||||
@@ -871,6 +876,9 @@ fn row_to_item_dto(row: TrashResourceRow) -> TrashResourceItemDto {
|
||||
sort_date: None,
|
||||
content_hash,
|
||||
etag,
|
||||
// §14 provenance not selected by the trash listing query.
|
||||
created_by: None,
|
||||
updated_by: None,
|
||||
};
|
||||
TrashResourceItemDto {
|
||||
resource_type: ResourceTypeDto::File,
|
||||
|
||||
@@ -139,7 +139,7 @@ where
|
||||
)
|
||||
})?;
|
||||
self.file_write_port
|
||||
.move_to_trash(item_id)
|
||||
.move_to_trash(item_id, user_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::new(
|
||||
@@ -181,7 +181,7 @@ where
|
||||
)
|
||||
})?;
|
||||
self.folder_storage_port
|
||||
.move_to_trash(item_id)
|
||||
.move_to_trash(item_id, user_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::new(
|
||||
@@ -215,7 +215,7 @@ where
|
||||
let original_path = item.original_path().to_string();
|
||||
let result = self
|
||||
.file_write_port
|
||||
.restore_from_trash(&file_id, &original_path)
|
||||
.restore_from_trash(&file_id, &original_path, user_id)
|
||||
.await;
|
||||
if let Err(e) = result
|
||||
&& !format!("{}", e).contains("not found")
|
||||
@@ -232,7 +232,7 @@ where
|
||||
let original_path = item.original_path().to_string();
|
||||
let result = self
|
||||
.folder_storage_port
|
||||
.restore_from_trash(&folder_id, &original_path)
|
||||
.restore_from_trash(&folder_id, &original_path, user_id)
|
||||
.await;
|
||||
if let Err(e) = result
|
||||
&& !format!("{}", e).contains("not found")
|
||||
@@ -566,6 +566,7 @@ impl FileWritePort for MockFileRepository {
|
||||
_content_type: String,
|
||||
_blob_hash: &str,
|
||||
_size: u64,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -574,6 +575,7 @@ impl FileWritePort for MockFileRepository {
|
||||
&self,
|
||||
_file_id: &str,
|
||||
_target_folder_id: Option<String>,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -582,6 +584,7 @@ impl FileWritePort for MockFileRepository {
|
||||
&self,
|
||||
_file_id: &str,
|
||||
_new_name: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -596,6 +599,7 @@ impl FileWritePort for MockFileRepository {
|
||||
_blob_hash: &str,
|
||||
_size: u64,
|
||||
_modified_at: Option<i64>,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(String, i64), DomainError> {
|
||||
Ok((String::new(), 0))
|
||||
}
|
||||
@@ -606,6 +610,7 @@ impl FileWritePort for MockFileRepository {
|
||||
_folder_id: Option<String>,
|
||||
_content_type: String,
|
||||
_size: u64,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(File, PathBuf), DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -615,11 +620,16 @@ impl FileWritePort for MockFileRepository {
|
||||
_file_id: &str,
|
||||
_target_folder_id: Option<String>,
|
||||
_new_name: Option<&str>,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<File, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn move_to_trash(&self, id: &str) -> std::result::Result<(), DomainError> {
|
||||
async fn move_to_trash(
|
||||
&self,
|
||||
id: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(), DomainError> {
|
||||
let mut files = self.files.lock().unwrap();
|
||||
let mut trashed = self.trashed_files.lock().unwrap();
|
||||
|
||||
@@ -635,6 +645,7 @@ impl FileWritePort for MockFileRepository {
|
||||
&self,
|
||||
id: &str,
|
||||
_original_path: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(), DomainError> {
|
||||
let mut files = self.files.lock().unwrap();
|
||||
let mut trashed = self.trashed_files.lock().unwrap();
|
||||
@@ -698,6 +709,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
&self,
|
||||
_name: String,
|
||||
_parent_id: Option<String>,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -759,6 +771,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
&self,
|
||||
_id: &str,
|
||||
_new_name: String,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -767,6 +780,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
&self,
|
||||
_id: &str,
|
||||
_new_parent_id: Option<&str>,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<Folder, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -787,7 +801,11 @@ impl FolderRepository for MockFolderRepository {
|
||||
Ok(StoragePath::from_string("/"))
|
||||
}
|
||||
|
||||
async fn move_to_trash(&self, id: &str) -> std::result::Result<(), DomainError> {
|
||||
async fn move_to_trash(
|
||||
&self,
|
||||
id: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(), DomainError> {
|
||||
let mut folders = self.folders.lock().unwrap();
|
||||
let mut trashed = self.trashed_folders.lock().unwrap();
|
||||
|
||||
@@ -803,6 +821,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
&self,
|
||||
id: &str,
|
||||
_original_path: &str,
|
||||
_caller_id: Uuid,
|
||||
) -> std::result::Result<(), DomainError> {
|
||||
let mut folders = self.folders.lock().unwrap();
|
||||
let mut trashed = self.trashed_folders.lock().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user