fix: resolve clippy warnings and rustfmt issues for CI compliance
Fix all clippy lints (collapsible if, clone on Copy, needless borrow, redundant bindings, unused params) and apply rustfmt across the codebase. Update test mocks to match Uuid-based trait signatures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,11 +89,7 @@ pub trait ThumbnailPort: Send + Sync + 'static {
|
||||
/// Returns `None` if no cached thumbnail exists on disk or in memory.
|
||||
/// Used for non-image file types (videos) where thumbnails are
|
||||
/// generated client-side and uploaded.
|
||||
async fn get_cached_thumbnail(
|
||||
&self,
|
||||
file_id: &str,
|
||||
size: ThumbnailSize,
|
||||
) -> Option<Bytes>;
|
||||
async fn get_cached_thumbnail(&self, file_id: &str, size: ThumbnailSize) -> Option<Bytes>;
|
||||
|
||||
/// Store an externally-generated thumbnail (e.g. client-side video frame).
|
||||
///
|
||||
|
||||
@@ -17,11 +17,11 @@ use crate::infrastructure::services::jwt_service::JwtTokenService;
|
||||
use crate::infrastructure::services::oidc_service::OidcService;
|
||||
use crate::infrastructure::services::password_hasher::Argon2PasswordHasher;
|
||||
use moka::sync::Cache;
|
||||
use uuid::Uuid;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Result of a successful OIDC callback. The handler layer inspects this to
|
||||
/// decide whether to redirect to the regular frontend or complete a Nextcloud
|
||||
|
||||
@@ -448,11 +448,9 @@ impl BatchOperationService {
|
||||
},
|
||||
};
|
||||
|
||||
let uid = user_id;
|
||||
|
||||
let mut operation_stream = stream::iter(file_ids.into_iter().map(|file_id| {
|
||||
let trash = trash_service.clone();
|
||||
let uid = uid;
|
||||
let uid = user_id;
|
||||
|
||||
async move {
|
||||
let trash_result = trash.move_to_trash(&file_id, "file", uid).await;
|
||||
@@ -513,11 +511,9 @@ impl BatchOperationService {
|
||||
},
|
||||
};
|
||||
|
||||
let uid = user_id;
|
||||
|
||||
let mut operation_stream = stream::iter(folder_ids.into_iter().map(|folder_id| {
|
||||
let trash = trash_service.clone();
|
||||
let uid = uid;
|
||||
let uid = user_id;
|
||||
|
||||
async move {
|
||||
let trash_result = trash.move_to_trash(&folder_id, "folder", uid).await;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use chrono::Utc;
|
||||
use uuid::Uuid;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::application::dtos::address_book_dto::{
|
||||
AddressBookDto, CreateAddressBookDto, ShareAddressBookDto, UnshareAddressBookDto,
|
||||
@@ -296,8 +296,11 @@ impl AddressBookUseCase for ContactService {
|
||||
|
||||
// Check if user has write access to the address book
|
||||
let address_book = self
|
||||
.check_address_book_write_access(&id, &Uuid::parse_str(&update.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?)
|
||||
.check_address_book_write_access(
|
||||
&id,
|
||||
&Uuid::parse_str(&update.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Apply updates
|
||||
@@ -526,9 +529,12 @@ impl ContactUseCase for ContactService {
|
||||
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
|
||||
|
||||
// Check if user has write access to the address book
|
||||
self.check_address_book_write_access(&address_book_id, &Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?)
|
||||
.await?;
|
||||
self.check_address_book_write_access(
|
||||
&address_book_id,
|
||||
&Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Convert DTOs to domain entities
|
||||
let email: Vec<Email> = dto
|
||||
@@ -604,9 +610,12 @@ impl ContactUseCase for ContactService {
|
||||
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
|
||||
|
||||
// Check if user has write access to the address book
|
||||
self.check_address_book_write_access(&address_book_id, &Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?)
|
||||
.await?;
|
||||
self.check_address_book_write_access(
|
||||
&address_book_id,
|
||||
&Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Parse vCard data
|
||||
let mut contact = self.parse_vcard(&dto.vcard)?;
|
||||
@@ -819,9 +828,12 @@ impl ContactUseCase for ContactService {
|
||||
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
|
||||
|
||||
// Check if user has write access to the address book
|
||||
self.check_address_book_write_access(&address_book_id, &Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?)
|
||||
.await?;
|
||||
self.check_address_book_write_access(
|
||||
&address_book_id,
|
||||
&Uuid::parse_str(&dto.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let group = ContactGroup::new(address_book_id, dto.name);
|
||||
|
||||
@@ -845,9 +857,12 @@ impl ContactUseCase for ContactService {
|
||||
.ok_or_else(|| DomainError::not_found("Contact group", "not found"))?;
|
||||
|
||||
// Check if user has write access to the address book
|
||||
self.check_address_book_write_access(group.address_book_id(), &Uuid::parse_str(&update.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?)
|
||||
.await?;
|
||||
self.check_address_book_write_access(
|
||||
group.address_book_id(),
|
||||
&Uuid::parse_str(&update.user_id)
|
||||
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Update the group
|
||||
let updated_group = ContactGroup::from_raw(
|
||||
|
||||
@@ -178,10 +178,10 @@ impl FileManagementUseCase for FileManagementService {
|
||||
async fn delete_file(&self, id: &str) -> Result<(), DomainError> {
|
||||
self.file_repository.delete_file(id).await?;
|
||||
// Best-effort thumbnail cleanup
|
||||
if let Some(thumb) = &self.thumbnail_service {
|
||||
if let Err(e) = thumb.delete_thumbnails(id).await {
|
||||
warn!("Failed to delete thumbnails for file {}: {}", id, e);
|
||||
}
|
||||
if let Some(thumb) = &self.thumbnail_service
|
||||
&& let Err(e) = thumb.delete_thumbnails(id).await
|
||||
{
|
||||
warn!("Failed to delete thumbnails for file {}: {}", id, e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -223,10 +223,10 @@ impl FileManagementUseCase for FileManagementService {
|
||||
warn!("Permanently deleting file: {}", id);
|
||||
self.file_repository.delete_file(id).await?;
|
||||
// Best-effort thumbnail cleanup
|
||||
if let Some(thumb) = &self.thumbnail_service {
|
||||
if let Err(e) = thumb.delete_thumbnails(id).await {
|
||||
warn!("Failed to delete thumbnails for file {}: {}", id, e);
|
||||
}
|
||||
if let Some(thumb) = &self.thumbnail_service
|
||||
&& let Err(e) = thumb.delete_thumbnails(id).await
|
||||
{
|
||||
warn!("Failed to delete thumbnails for file {}: {}", id, e);
|
||||
}
|
||||
info!("File permanently deleted: {}", id);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::application::ports::storage_ports::{FileReadPort, FileWritePort};
|
||||
use crate::common::errors::DomainError;
|
||||
@@ -22,7 +23,7 @@ use crate::domain::services::path_service::StoragePath;
|
||||
/// A simple in-memory mock that maps (file_id → (File, owner_id)).
|
||||
struct MockFileReadPort {
|
||||
/// file_id → (File, owner_id)
|
||||
files: Mutex<HashMap<String, (File, String)>>,
|
||||
files: Mutex<HashMap<String, (File, Uuid)>>,
|
||||
}
|
||||
|
||||
impl MockFileReadPort {
|
||||
@@ -33,7 +34,7 @@ impl MockFileReadPort {
|
||||
}
|
||||
|
||||
/// Insert a test file owned by `owner_id`.
|
||||
fn insert(&self, id: &str, name: &str, owner_id: &str) {
|
||||
fn insert(&self, id: &str, name: &str, owner_id: Uuid) {
|
||||
let file = File::new(
|
||||
id.to_string(),
|
||||
name.to_string(),
|
||||
@@ -46,7 +47,7 @@ impl MockFileReadPort {
|
||||
self.files
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id.to_string(), (file, owner_id.to_string()));
|
||||
.insert(id.to_string(), (file, owner_id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +60,10 @@ impl FileReadPort for MockFileReadPort {
|
||||
.ok_or_else(|| DomainError::not_found("File", id.to_string()))
|
||||
}
|
||||
|
||||
async fn get_file_for_owner(&self, id: &str, owner_id: &str) -> Result<File, DomainError> {
|
||||
async fn get_file_for_owner(&self, id: &str, owner_id: Uuid) -> Result<File, DomainError> {
|
||||
let files = self.files.lock().unwrap();
|
||||
match files.get(id) {
|
||||
Some((file, actual_owner)) if actual_owner == owner_id => Ok(file.clone()),
|
||||
Some((file, actual_owner)) if *actual_owner == owner_id => Ok(file.clone()),
|
||||
// Return NotFound regardless — do not leak existence
|
||||
_ => Err(DomainError::not_found("File", id.to_string())),
|
||||
}
|
||||
@@ -104,7 +105,7 @@ impl FileReadPort for MockFileReadPort {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> Result<(Vec<File>, usize), DomainError> {
|
||||
Ok((Vec::new(), 0))
|
||||
}
|
||||
@@ -113,7 +114,7 @@ impl FileReadPort for MockFileReadPort {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
@@ -248,20 +249,23 @@ impl FileWritePort for MockFileWritePort {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_file_for_owner_returns_file_for_correct_owner() {
|
||||
let alice_id = Uuid::new_v4();
|
||||
let repo = MockFileReadPort::new();
|
||||
repo.insert("file-1", "secret.txt", "alice");
|
||||
repo.insert("file-1", "secret.txt", alice_id);
|
||||
|
||||
let result = repo.get_file_for_owner("file-1", "alice").await;
|
||||
let result = repo.get_file_for_owner("file-1", alice_id).await;
|
||||
assert!(result.is_ok(), "owner should be able to read own file");
|
||||
assert_eq!(result.unwrap().id(), "file-1");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_file_for_owner_rejects_wrong_owner() {
|
||||
let alice_id = Uuid::new_v4();
|
||||
let bob_id = Uuid::new_v4();
|
||||
let repo = MockFileReadPort::new();
|
||||
repo.insert("file-1", "secret.txt", "alice");
|
||||
repo.insert("file-1", "secret.txt", alice_id);
|
||||
|
||||
let result = repo.get_file_for_owner("file-1", "bob").await;
|
||||
let result = repo.get_file_for_owner("file-1", bob_id).await;
|
||||
assert!(result.is_err(), "non-owner should be rejected");
|
||||
|
||||
// Must be NotFound, NOT Forbidden — avoids leaking existence
|
||||
@@ -276,20 +280,23 @@ async fn get_file_for_owner_rejects_wrong_owner() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_file_for_owner_returns_not_found_for_missing_file() {
|
||||
let alice_id = Uuid::new_v4();
|
||||
let repo = MockFileReadPort::new();
|
||||
|
||||
let result = repo.get_file_for_owner("nonexistent", "alice").await;
|
||||
let result = repo.get_file_for_owner("nonexistent", alice_id).await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn verify_file_owner_uses_default_impl() {
|
||||
let alice_id = Uuid::new_v4();
|
||||
let bob_id = Uuid::new_v4();
|
||||
let repo = MockFileReadPort::new();
|
||||
repo.insert("file-1", "secret.txt", "alice");
|
||||
repo.insert("file-1", "secret.txt", alice_id);
|
||||
|
||||
// Default impl delegates to get_file_for_owner and maps to ()
|
||||
assert!(repo.verify_file_owner("file-1", "alice").await.is_ok());
|
||||
assert!(repo.verify_file_owner("file-1", "bob").await.is_err());
|
||||
assert!(repo.verify_file_owner("file-1", alice_id).await.is_ok());
|
||||
assert!(repo.verify_file_owner("file-1", bob_id).await.is_err());
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -310,15 +317,17 @@ async fn verify_file_owner_uses_default_impl() {
|
||||
async fn verify_file_owner_delegates_to_read_port() {
|
||||
// This test verifies the FileReadPort contract that verify_file_owner
|
||||
// returns Ok for the correct owner and Err for others.
|
||||
let user_id = Uuid::new_v4();
|
||||
let attacker_id = Uuid::new_v4();
|
||||
let read = MockFileReadPort::new();
|
||||
read.insert("abc-123", "report.pdf", "user-42");
|
||||
read.insert("abc-123", "report.pdf", user_id);
|
||||
|
||||
// Same user → Ok
|
||||
let ok = read.verify_file_owner("abc-123", "user-42").await;
|
||||
let ok = read.verify_file_owner("abc-123", user_id).await;
|
||||
assert!(ok.is_ok(), "correct owner should pass verify_file_owner");
|
||||
|
||||
// Different user → Err
|
||||
let err = read.verify_file_owner("abc-123", "attacker-99").await;
|
||||
let err = read.verify_file_owner("abc-123", attacker_id).await;
|
||||
assert!(err.is_err(), "wrong owner should fail verify_file_owner");
|
||||
}
|
||||
|
||||
@@ -326,15 +335,17 @@ async fn verify_file_owner_delegates_to_read_port() {
|
||||
async fn owned_methods_require_ownership_check_first() {
|
||||
// Simulate what the _owned methods do: verify_owner then delegate.
|
||||
// We test with the mock read port to prove the sequence.
|
||||
let owner_id = Uuid::new_v4();
|
||||
let attacker_id = Uuid::new_v4();
|
||||
let read = MockFileReadPort::new();
|
||||
read.insert("file-1", "data.csv", "owner-a");
|
||||
read.insert("file-1", "data.csv", owner_id);
|
||||
|
||||
// Step 1: verify_owner for correct owner → Ok
|
||||
let step1 = read.verify_file_owner("file-1", "owner-a").await;
|
||||
let step1 = read.verify_file_owner("file-1", owner_id).await;
|
||||
assert!(step1.is_ok());
|
||||
|
||||
// Step 2: verify_owner for attacker → Err, so the move/rename never executes
|
||||
let step2 = read.verify_file_owner("file-1", "attacker").await;
|
||||
let step2 = read.verify_file_owner("file-1", attacker_id).await;
|
||||
assert!(step2.is_err());
|
||||
}
|
||||
|
||||
@@ -347,18 +358,20 @@ use crate::common::stubs::StubFileManagementUseCase;
|
||||
|
||||
#[tokio::test]
|
||||
async fn stub_move_file_owned_returns_ok() {
|
||||
let user_id = Uuid::new_v4();
|
||||
let stub = StubFileManagementUseCase;
|
||||
let result = stub
|
||||
.move_file_owned("file-1", "user-1", Some("folder-2".to_string()))
|
||||
.move_file_owned("file-1", user_id, Some("folder-2".to_string()))
|
||||
.await;
|
||||
assert!(result.is_ok(), "stub should return Ok for move_file_owned");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stub_rename_file_owned_returns_ok() {
|
||||
let user_id = Uuid::new_v4();
|
||||
let stub = StubFileManagementUseCase;
|
||||
let result = stub
|
||||
.rename_file_owned("file-1", "user-1", "new-name.txt")
|
||||
.rename_file_owned("file-1", user_id, "new-name.txt")
|
||||
.await;
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
@@ -371,16 +384,18 @@ use crate::common::stubs::StubFileRetrievalUseCase;
|
||||
|
||||
#[tokio::test]
|
||||
async fn stub_get_file_owned_returns_ok() {
|
||||
let user_id = Uuid::new_v4();
|
||||
let stub = StubFileRetrievalUseCase;
|
||||
let result = stub.get_file_owned("file-1", "user-1").await;
|
||||
let result = stub.get_file_owned("file-1", user_id).await;
|
||||
assert!(result.is_ok(), "stub should return Ok for get_file_owned");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stub_get_file_optimized_owned_returns_ok() {
|
||||
let user_id = Uuid::new_v4();
|
||||
let stub = StubFileRetrievalUseCase;
|
||||
let result = stub
|
||||
.get_file_optimized_owned("file-1", "user-1", true, false)
|
||||
.get_file_optimized_owned("file-1", user_id, true, false)
|
||||
.await;
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
|
||||
@@ -806,7 +806,7 @@ mod tests {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> Result<(Vec<crate::domain::entities::file::File>, usize), DomainError> {
|
||||
Ok((Vec::new(), 0))
|
||||
}
|
||||
@@ -815,7 +815,7 @@ mod tests {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
@@ -839,7 +839,7 @@ mod tests {
|
||||
async fn get_file_for_owner(
|
||||
&self,
|
||||
id: &str,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
) -> Result<crate::domain::entities::file::File, DomainError> {
|
||||
self.get_file(id).await
|
||||
}
|
||||
@@ -891,7 +891,7 @@ mod tests {
|
||||
async fn list_folders_by_owner(
|
||||
&self,
|
||||
_parent_id: Option<&str>,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
) -> Result<Vec<crate::domain::entities::folder::Folder>, DomainError> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -910,7 +910,7 @@ mod tests {
|
||||
async fn list_folders_by_owner_paginated(
|
||||
&self,
|
||||
_parent_id: Option<&str>,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
_offset: usize,
|
||||
_limit: usize,
|
||||
_include_total: bool,
|
||||
@@ -971,7 +971,7 @@ mod tests {
|
||||
|
||||
async fn create_home_folder(
|
||||
&self,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
_name: String,
|
||||
) -> Result<crate::domain::entities::folder::Folder, DomainError> {
|
||||
unimplemented!()
|
||||
|
||||
@@ -566,10 +566,10 @@ impl TrashUseCase for TrashService {
|
||||
|
||||
// Best-effort thumbnail cleanup — thumbnails are cache
|
||||
// artifacts, so failure must not block file deletion.
|
||||
if let Some(thumb) = &self.thumbnail_service {
|
||||
if let Err(e) = thumb.delete_thumbnails(&file_id).await {
|
||||
warn!("Failed to delete thumbnails for file {}: {}", file_id, e);
|
||||
}
|
||||
if let Some(thumb) = &self.thumbnail_service
|
||||
&& let Err(e) = thumb.delete_thumbnails(&file_id).await
|
||||
{
|
||||
warn!("Failed to delete thumbnails for file {}: {}", file_id, e);
|
||||
}
|
||||
}
|
||||
TrashedItemType::Folder => {
|
||||
|
||||
@@ -61,10 +61,8 @@ where
|
||||
FW: FileWritePort,
|
||||
FoR: FolderRepository,
|
||||
{
|
||||
async fn get_trash_items(&self, user_id: &str) -> Result<Vec<TrashedItemDto>> {
|
||||
let user_uuid = Uuid::parse_str(user_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid user ID: {}", e)))?;
|
||||
let items = self.trash_repository.get_trash_items(&user_uuid).await?;
|
||||
async fn get_trash_items(&self, user_id: Uuid) -> Result<Vec<TrashedItemDto>> {
|
||||
let items = self.trash_repository.get_trash_items(&user_id).await?;
|
||||
Ok(items
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
@@ -85,11 +83,9 @@ where
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn move_to_trash(&self, item_id: &str, item_type: &str, user_id: &str) -> Result<()> {
|
||||
async fn move_to_trash(&self, item_id: &str, item_type: &str, user_id: Uuid) -> Result<()> {
|
||||
let item_uuid = Uuid::parse_str(item_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid item ID: {}", e)))?;
|
||||
let user_uuid = Uuid::parse_str(user_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid user ID: {}", e)))?;
|
||||
|
||||
match item_type {
|
||||
"file" => {
|
||||
@@ -103,7 +99,7 @@ where
|
||||
let original_path = file.storage_path().to_string();
|
||||
let trashed_item = TrashedItem::new(
|
||||
item_uuid,
|
||||
user_uuid,
|
||||
user_id,
|
||||
TrashedItemType::File,
|
||||
file.name().to_string(),
|
||||
original_path,
|
||||
@@ -145,7 +141,7 @@ where
|
||||
let original_path = folder.storage_path().to_string();
|
||||
let trashed_item = TrashedItem::new(
|
||||
item_uuid,
|
||||
user_uuid,
|
||||
user_id,
|
||||
TrashedItemType::Folder,
|
||||
folder.name().to_string(),
|
||||
original_path,
|
||||
@@ -179,15 +175,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
async fn restore_item(&self, trash_id: &str, user_id: &str) -> Result<()> {
|
||||
async fn restore_item(&self, trash_id: &str, user_id: Uuid) -> Result<()> {
|
||||
let trash_uuid = Uuid::parse_str(trash_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid trash ID: {}", e)))?;
|
||||
let user_uuid = Uuid::parse_str(user_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid user ID: {}", e)))?;
|
||||
|
||||
let item = self
|
||||
.trash_repository
|
||||
.get_trash_item(&trash_uuid, &user_uuid)
|
||||
.get_trash_item(&trash_uuid, &user_id)
|
||||
.await?;
|
||||
match item {
|
||||
Some(item) => {
|
||||
@@ -228,7 +222,7 @@ where
|
||||
}
|
||||
}
|
||||
self.trash_repository
|
||||
.restore_from_trash(&trash_uuid, &user_uuid)
|
||||
.restore_from_trash(&trash_uuid, &user_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::new(
|
||||
@@ -243,15 +237,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_permanently(&self, trash_id: &str, user_id: &str) -> Result<()> {
|
||||
async fn delete_permanently(&self, trash_id: &str, user_id: Uuid) -> Result<()> {
|
||||
let trash_uuid = Uuid::parse_str(trash_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid trash ID: {}", e)))?;
|
||||
let user_uuid = Uuid::parse_str(user_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid user ID: {}", e)))?;
|
||||
|
||||
let item = self
|
||||
.trash_repository
|
||||
.get_trash_item(&trash_uuid, &user_uuid)
|
||||
.get_trash_item(&trash_uuid, &user_id)
|
||||
.await?;
|
||||
match item {
|
||||
Some(item) => {
|
||||
@@ -287,7 +279,7 @@ where
|
||||
}
|
||||
}
|
||||
self.trash_repository
|
||||
.delete_permanently(&trash_uuid, &user_uuid)
|
||||
.delete_permanently(&trash_uuid, &user_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::new(
|
||||
@@ -302,10 +294,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
async fn empty_trash(&self, user_id: &str) -> Result<()> {
|
||||
let user_uuid = Uuid::parse_str(user_id)
|
||||
.map_err(|e| DomainError::validation_error(format!("Invalid user ID: {}", e)))?;
|
||||
self.trash_repository.clear_trash(&user_uuid).await
|
||||
async fn empty_trash(&self, user_id: Uuid) -> Result<()> {
|
||||
self.trash_repository.clear_trash(&user_id).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +482,7 @@ impl FileReadPort for MockFileRepository {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> std::result::Result<(Vec<File>, usize), DomainError> {
|
||||
Ok((Vec::new(), 0))
|
||||
}
|
||||
@@ -501,7 +491,7 @@ impl FileReadPort for MockFileRepository {
|
||||
&self,
|
||||
_folder_id: Option<&str>,
|
||||
_criteria: &crate::application::dtos::search_dto::SearchCriteriaDto,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
) -> std::result::Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
@@ -519,7 +509,7 @@ impl FileReadPort for MockFileRepository {
|
||||
async fn get_file_for_owner(
|
||||
&self,
|
||||
id: &str,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
) -> std::result::Result<File, DomainError> {
|
||||
// In this mock, ignore ownership — trash tests don't focus on ownership
|
||||
self.get_file(id).await
|
||||
@@ -697,7 +687,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
async fn list_folders_by_owner(
|
||||
&self,
|
||||
_parent_id: Option<&str>,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
) -> std::result::Result<Vec<Folder>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
@@ -715,7 +705,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
async fn list_folders_by_owner_paginated(
|
||||
&self,
|
||||
_parent_id: Option<&str>,
|
||||
_owner_id: &str,
|
||||
_owner_id: Uuid,
|
||||
_offset: usize,
|
||||
_limit: usize,
|
||||
_include_total: bool,
|
||||
@@ -799,7 +789,7 @@ impl FolderRepository for MockFolderRepository {
|
||||
|
||||
async fn create_home_folder(
|
||||
&self,
|
||||
_user_id: &str,
|
||||
_user_id: Uuid,
|
||||
_name: String,
|
||||
) -> std::result::Result<Folder, DomainError> {
|
||||
Ok(Folder::default())
|
||||
@@ -839,18 +829,18 @@ mod tests {
|
||||
|
||||
let file_id = "550e8400-e29b-41d4-a716-446655440000";
|
||||
let user_id = "550e8400-e29b-41d4-a716-446655440001";
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
|
||||
// Add a test file to the repository
|
||||
file_repo.add_test_file(file_id, "test.txt", "/test/path/test.txt");
|
||||
|
||||
// Act
|
||||
let result = service.move_to_trash(file_id, "file", user_id).await;
|
||||
let result = service.move_to_trash(file_id, "file", user_uuid).await;
|
||||
|
||||
// Assert
|
||||
assert!(result.is_ok(), "Moving file to trash failed: {:?}", result);
|
||||
|
||||
// Verify the file is in trash
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let trash_items = trash_repo.get_trash_items(&user_uuid).await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -913,12 +903,13 @@ mod tests {
|
||||
|
||||
let folder_id = "550e8400-e29b-41d4-a716-446655440002";
|
||||
let user_id = "550e8400-e29b-41d4-a716-446655440001";
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
|
||||
// Add a test folder to the repository
|
||||
folder_repo.add_test_folder(folder_id, "test_folder", "/test/path/test_folder");
|
||||
|
||||
// Act
|
||||
let result = service.move_to_trash(folder_id, "folder", user_id).await;
|
||||
let result = service.move_to_trash(folder_id, "folder", user_uuid).await;
|
||||
|
||||
// Assert
|
||||
assert!(
|
||||
@@ -928,7 +919,6 @@ mod tests {
|
||||
);
|
||||
|
||||
// Verify the folder is in trash
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let trash_items = trash_repo.get_trash_items(&user_uuid).await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -978,22 +968,22 @@ mod tests {
|
||||
|
||||
let file_id = "550e8400-e29b-41d4-a716-446655440000";
|
||||
let user_id = "550e8400-e29b-41d4-a716-446655440001";
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let file_path = "/test/path/test.txt";
|
||||
|
||||
// Add a test file and move it to trash
|
||||
file_repo.add_test_file(file_id, "test.txt", file_path);
|
||||
service
|
||||
.move_to_trash(file_id, "file", user_id)
|
||||
.move_to_trash(file_id, "file", user_uuid)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Get the trash item ID
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let trash_items = trash_repo.get_trash_items(&user_uuid).await.unwrap();
|
||||
let trash_id = trash_items[0].id().to_string();
|
||||
|
||||
// Act
|
||||
let result = service.restore_item(&trash_id, user_id).await;
|
||||
let result = service.restore_item(&trash_id, user_uuid).await;
|
||||
|
||||
// Assert
|
||||
assert!(
|
||||
@@ -1048,21 +1038,21 @@ mod tests {
|
||||
|
||||
let file_id = "550e8400-e29b-41d4-a716-446655440000";
|
||||
let user_id = "550e8400-e29b-41d4-a716-446655440001";
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
|
||||
// Add a test file and move it to trash
|
||||
file_repo.add_test_file(file_id, "test.txt", "/test/path/test.txt");
|
||||
service
|
||||
.move_to_trash(file_id, "file", user_id)
|
||||
.move_to_trash(file_id, "file", user_uuid)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Get the trash item ID
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let trash_items = trash_repo.get_trash_items(&user_uuid).await.unwrap();
|
||||
let trash_id = trash_items[0].id().to_string();
|
||||
|
||||
// Act
|
||||
let result = service.delete_permanently(&trash_id, user_id).await;
|
||||
let result = service.delete_permanently(&trash_id, user_uuid).await;
|
||||
|
||||
// Assert
|
||||
assert!(
|
||||
@@ -1116,6 +1106,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let user_id = "550e8400-e29b-41d4-a716-446655440001";
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
|
||||
// Add multiple files and folders to trash
|
||||
let file_ids = [
|
||||
@@ -1136,7 +1127,7 @@ mod tests {
|
||||
&format!("/test/path/test{}.txt", i),
|
||||
);
|
||||
service
|
||||
.move_to_trash(file_id, "file", user_id)
|
||||
.move_to_trash(file_id, "file", user_uuid)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
@@ -1148,18 +1139,17 @@ mod tests {
|
||||
&format!("/test/path/folder{}", i),
|
||||
);
|
||||
service
|
||||
.move_to_trash(folder_id, "folder", user_id)
|
||||
.move_to_trash(folder_id, "folder", user_uuid)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Verify items are in trash
|
||||
let user_uuid = Uuid::parse_str(user_id).unwrap();
|
||||
let trash_items = trash_repo.get_trash_items(&user_uuid).await.unwrap();
|
||||
assert_eq!(trash_items.len(), 4, "Should have 4 items in trash");
|
||||
|
||||
// Act
|
||||
let result = service.empty_trash(user_id).await;
|
||||
let result = service.empty_trash(user_uuid).await;
|
||||
|
||||
// Assert
|
||||
assert!(result.is_ok(), "Emptying trash failed: {:?}", result);
|
||||
|
||||
Reference in New Issue
Block a user