fix: resolve all clippy warnings and enforce cargo fmt

- display_helpers: convert module doc-comments to regular comments,
  merge identical text/markdown + text/ branches
- search_service: replace needless range loops with slice-based pagination
- folder_repository, folder_db_repository: collapse nested if statements
- favorites_pg_repository: remove unnecessary borrow on generic arg
- file_blob_read_repository: collapse 6 nested if-let blocks
- file_blob_write_repository: collapse nested if for dedup ref decrement
- chunked_upload_service: use div_ceil(), collapse 2 nested if blocks
- folder_handler: collapse nested if-let for owner check
- webdav_handler: replace 7x io::Error::new(ErrorKind::Other, ..) with
  io::Error::other(..)
- cargo fmt applied to all files

Passes: cargo clippy --all-targets --all-features -- -D warnings
This commit is contained in:
Dionisio
2026-02-25 10:28:34 +01:00
parent 093400ce72
commit 97cf6402e2
34 changed files with 769 additions and 761 deletions
+9 -11
View File
@@ -1,12 +1,12 @@
/// Shared display helpers for DTOs.
///
/// These functions centralise the mime→icon / mime→category / size→human-string
/// logic so that every API response carries pre-computed display fields and the
/// frontend does **not** need to duplicate these mappings.
///
/// The approach is: try MIME first (specific matches beat prefix matches),
/// then fall back to the file extension when the MIME is generic
/// (`application/octet-stream` or empty).
// Shared display helpers for DTOs.
//
// These functions centralise the mime→icon / mime→category / size→human-string
// logic so that every API response carries pre-computed display fields and the
// frontend does **not** need to duplicate these mappings.
//
// The approach is: try MIME first (specific matches beat prefix matches),
// then fall back to the file extension when the MIME is generic
// (`application/octet-stream` or empty).
// ─── Private: extract lowercase extension from a filename ────────────
@@ -100,8 +100,6 @@ pub fn icon_class_for(name: &str, mime: &str) -> &'static str {
|| mime.contains("typescript")
{
return "fas fa-file-code";
} else if mime.starts_with("text/markdown") {
return "fas fa-file-alt";
} else if mime.starts_with("text/") {
return "fas fa-file-alt";
}
+6 -5
View File
@@ -165,10 +165,7 @@ pub trait FileRetrievalUseCase: Send + Sync + 'static {
/// Lists every file in the subtree rooted at `folder_id`.
///
/// Default: falls back to `list_files(Some(folder_id))` (one level).
async fn list_files_in_subtree(
&self,
folder_id: &str,
) -> Result<Vec<FileDto>, DomainError> {
async fn list_files_in_subtree(&self, folder_id: &str) -> Result<Vec<FileDto>, DomainError> {
self.list_files(Some(folder_id)).await
}
@@ -183,7 +180,11 @@ pub trait FileRetrievalUseCase: Send + Sync + 'static {
limit: i64,
) -> Result<Vec<FileDto>, DomainError> {
let all = self.list_files(folder_id).await?;
Ok(all.into_iter().skip(offset as usize).take(limit as usize).collect())
Ok(all
.into_iter()
.skip(offset as usize)
.take(limit as usize)
.collect())
}
}
+6 -5
View File
@@ -76,10 +76,7 @@ pub trait FolderUseCase: Send + Sync + 'static {
/// ordered by path. Uses ltree `<@` — single GiST-indexed query.
///
/// Default: returns an empty vec (stubs / mocks).
async fn list_subtree_folders(
&self,
folder_id: &str,
) -> Result<Vec<FolderDto>, DomainError> {
async fn list_subtree_folders(&self, folder_id: &str) -> Result<Vec<FolderDto>, DomainError> {
let _ = folder_id;
Ok(Vec::new())
}
@@ -97,7 +94,11 @@ pub trait SearchUseCase: Send + Sync + 'static {
///
/// `user_id` identifies the authenticated user so that SQL queries filter
/// by owner and the result cache is isolated per tenant.
async fn search(&self, criteria: SearchCriteriaDto, user_id: &str) -> Result<SearchResultsDto, DomainError>;
async fn search(
&self,
criteria: SearchCriteriaDto,
user_id: &str,
) -> Result<SearchResultsDto, DomainError>;
/// Returns quick suggestions for autocomplete (lightweight, fast).
async fn suggest(
+1 -4
View File
@@ -100,10 +100,7 @@ pub trait FileReadPort: Send + Sync + 'static {
/// subtree is fetched in a single GiST-indexed query.
///
/// Default: falls back to `list_files(Some(folder_id))` (one level).
async fn list_files_in_subtree(
&self,
folder_id: &str,
) -> Result<Vec<File>, DomainError> {
async fn list_files_in_subtree(&self, folder_id: &str) -> Result<Vec<File>, DomainError> {
self.list_files(Some(folder_id)).await
}
@@ -526,7 +526,10 @@ impl AuthApplicationService {
}
// Hash new password and update user
let new_hash = self.password_hasher.hash_password(&dto.new_password).await?;
let new_hash = self
.password_hasher
.hash_password(&dto.new_password)
.await?;
user.update_password_hash(new_hash);
// Save updated user
@@ -642,10 +645,7 @@ impl AuthApplicationService {
let admin_quota = self.capped_quota(&admin_role);
// Hash the password (same as register / admin_create_user)
let password_hash = self
.password_hasher
.hash_password(&dto.password)
.await?;
let password_hash = self.password_hasher.hash_password(&dto.password).await?;
// Create the new admin user
let user = User::new(
@@ -1156,10 +1156,8 @@ impl AuthApplicationService {
let exchange_code = hex::encode(code_bytes);
// Store auth response (auto-expires after 60 s via moka TTL)
self.pending_oidc_tokens.insert(
exchange_code.clone(),
PendingOidcToken { auth_response },
);
self.pending_oidc_tokens
.insert(exchange_code.clone(), PendingOidcToken { auth_response });
tracing::info!("OIDC login successful, one-time exchange code generated");
@@ -1169,13 +1167,16 @@ impl AuthApplicationService {
/// Exchange a one-time code for the authentication tokens.
/// The code is single-use and expires after 60 seconds (moka TTL).
pub fn exchange_oidc_token(&self, one_time_code: &str) -> Result<AuthResponseDto, DomainError> {
let pending = self.pending_oidc_tokens.remove(one_time_code).ok_or_else(|| {
DomainError::new(
ErrorKind::AccessDenied,
"OIDC",
"Invalid or expired exchange code. Please try logging in again.",
)
})?;
let pending = self
.pending_oidc_tokens
.remove(one_time_code)
.ok_or_else(|| {
DomainError::new(
ErrorKind::AccessDenied,
"OIDC",
"Invalid or expired exchange code. Please try logging in again.",
)
})?;
Ok(pending.auth_response)
}
+4 -1
View File
@@ -713,7 +713,10 @@ impl BatchOperationService {
match chunk {
Ok(bytes) => {
if let Err(e) = zip.write_all(&bytes) {
info!("Could not write zip chunk for {}: {}", file_dto.name, e);
info!(
"Could not write zip chunk for {}: {}",
file_dto.name, e
);
break;
}
}
@@ -177,7 +177,10 @@ impl FileManagementUseCase for FileManagementService {
.copy_folder_tree(source_folder_id, target_parent_id, dest_name)
.await
.map_err(|e| {
error!("Error copying folder tree (source: {}): {}", source_folder_id, e);
error!(
"Error copying folder tree (source: {}): {}",
source_folder_id, e
);
e
})?;
@@ -88,7 +88,10 @@ impl FileRetrievalService {
return None;
}
let format = OutputFormat::WebP;
match transcode.get_transcoded(id, content.clone(), mime, format).await {
match transcode
.get_transcoded(id, content.clone(), mime, format)
.await
{
Ok((transcoded, webp_mime, true)) => {
debug!(
"🖼️ WebP transcode: {} -> {} bytes ({:.0}% smaller)",
@@ -200,12 +203,7 @@ impl FileRetrievalService {
let etag: Arc<str> = format!("\"{}-{}\"", id, modified_at).into();
let ct: Arc<str> = Arc::from(&*mime_type);
cache
.put(
id.to_string(),
content_bytes.clone(),
etag,
ct,
)
.put(id.to_string(), content_bytes.clone(), etag, ct)
.await;
}
@@ -310,10 +308,7 @@ impl FileRetrievalUseCase for FileRetrievalService {
self.file_read.get_file_range_stream(id, start, end).await
}
async fn list_files_in_subtree(
&self,
folder_id: &str,
) -> Result<Vec<FileDto>, DomainError> {
async fn list_files_in_subtree(&self, folder_id: &str) -> Result<Vec<FileDto>, DomainError> {
let files = self.file_read.list_files_in_subtree(folder_id).await?;
Ok(files.into_iter().map(FileDto::from).collect())
}
@@ -324,7 +319,10 @@ impl FileRetrievalUseCase for FileRetrievalService {
offset: i64,
limit: i64,
) -> Result<Vec<FileDto>, DomainError> {
let files = self.file_read.list_files_batch(folder_id, offset, limit).await?;
let files = self
.file_read
.list_files_batch(folder_id, offset, limit)
.await?;
Ok(files.into_iter().map(FileDto::from).collect())
}
}
+1 -4
View File
@@ -182,10 +182,7 @@ impl FolderUseCase for FolderService {
Ok(FolderDto::from(folder))
}
async fn list_subtree_folders(
&self,
folder_id: &str,
) -> Result<Vec<FolderDto>, DomainError> {
async fn list_subtree_folders(&self, folder_id: &str) -> Result<Vec<FolderDto>, DomainError> {
let folders = self.folder_storage.list_subtree_folders(folder_id).await?;
Ok(folders.into_iter().map(FolderDto::from).collect())
}
+23 -29
View File
@@ -347,19 +347,15 @@ impl SearchUseCase for SearchService {
let start_idx = criteria.offset.min(total_count);
let end_idx = (criteria.offset + criteria.limit).min(total_count);
let mut paginated_folders = Vec::new();
let mut paginated_files = Vec::new();
let folder_start = start_idx.min(folder_count);
let folder_end = end_idx.min(folder_count);
let paginated_folders = enriched_folders[folder_start..folder_end].to_vec();
for i in start_idx..end_idx {
if i < folder_count {
paginated_folders.push(enriched_folders[i].clone());
} else {
let file_idx = i - folder_count;
if file_idx < enriched_files.len() {
paginated_files.push(enriched_files[file_idx].clone());
}
}
}
let file_start = start_idx.saturating_sub(folder_count);
let file_end = end_idx
.saturating_sub(folder_count)
.min(enriched_files.len());
let paginated_files = enriched_files[file_start..file_end].to_vec();
let elapsed_ms = start.elapsed().as_millis() as u64;
@@ -413,12 +409,10 @@ impl SearchUseCase for SearchService {
// ── Sort folders (files already sorted by SQL ORDER BY) ──
match criteria.sort_by.as_str() {
"name" => {
enriched_folders
.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
enriched_folders.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
}
"name_desc" => {
enriched_folders
.sort_by(|a, b| b.name.to_lowercase().cmp(&a.name.to_lowercase()));
enriched_folders.sort_by(|a, b| b.name.to_lowercase().cmp(&a.name.to_lowercase()));
}
"date" => {
enriched_folders.sort_by(|a, b| a.modified_at.cmp(&b.modified_at));
@@ -437,19 +431,15 @@ impl SearchUseCase for SearchService {
let start_idx = criteria.offset.min(total_count);
let end_idx = (criteria.offset + criteria.limit).min(total_count);
let mut paginated_folders = Vec::new();
let mut paginated_files = Vec::new();
let folder_start = start_idx.min(folder_count);
let folder_end = end_idx.min(folder_count);
let paginated_folders = enriched_folders[folder_start..folder_end].to_vec();
for i in start_idx..end_idx {
if i < folder_count {
paginated_folders.push(enriched_folders[i].clone());
} else {
let file_idx = i - folder_count;
if file_idx < enriched_files.len() {
paginated_files.push(enriched_files[file_idx].clone());
}
}
}
let file_start = start_idx.saturating_sub(folder_count);
let file_end = end_idx
.saturating_sub(folder_count)
.min(enriched_files.len());
let paginated_files = enriched_files[file_start..file_end].to_vec();
let elapsed_ms = start.elapsed().as_millis() as u64;
@@ -496,7 +486,11 @@ impl SearchService {
#[async_trait]
impl SearchUseCase for SearchServiceStub {
async fn search(&self, _criteria: SearchCriteriaDto, _user_id: &str) -> Result<SearchResultsDto> {
async fn search(
&self,
_criteria: SearchCriteriaDto,
_user_id: &str,
) -> Result<SearchResultsDto> {
Ok(SearchResultsDto::empty())
}
+3 -2
View File
@@ -132,8 +132,9 @@ impl ShareService {
/// concurrently. This keeps RAM usage predictable (~19 MB × 2 = ~38 MB max)
/// and avoids starving the Tokio blocking thread pool.
async fn hash_password_async(&self, password: &str) -> Result<String, DomainError> {
let _permit = self.hash_semaphore.acquire().await
.map_err(|_| DomainError::internal_error("ShareService", "Hash semaphore closed".to_string()))?;
let _permit = self.hash_semaphore.acquire().await.map_err(|_| {
DomainError::internal_error("ShareService", "Hash semaphore closed".to_string())
})?;
self.password_hasher.hash_password(password).await
}
}