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:
zjean
2026-03-09 14:34:07 +01:00
parent cf9fe82b5f
commit 18518bedaf
34 changed files with 370 additions and 336 deletions
@@ -86,7 +86,10 @@ impl ContactStorageAdapter {
.address_book_repository
.get_address_book_shares(address_book_id)
.await?;
if shares.iter().any(|(shared_user, _)| shared_user == &user_id.to_string()) {
if shares
.iter()
.any(|(shared_user, _)| shared_user == &user_id.to_string())
{
return Ok(address_book);
}
@@ -248,7 +251,11 @@ impl AddressBookUseCase for ContactStorageAdapter {
// Check write access
let user_id = Uuid::parse_str(&update.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "AddressBook", "Invalid user ID format")
DomainError::new(
ErrorKind::InvalidInput,
"AddressBook",
"Invalid user ID format",
)
})?;
let mut address_book = self.check_write_access(&uuid, user_id).await?;
@@ -364,7 +371,11 @@ impl AddressBookUseCase for ContactStorageAdapter {
}
let target_user_id = Uuid::parse_str(&dto.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "AddressBook", "Invalid target user ID format")
DomainError::new(
ErrorKind::InvalidInput,
"AddressBook",
"Invalid target user ID format",
)
})?;
self.address_book_repository
@@ -397,7 +408,11 @@ impl AddressBookUseCase for ContactStorageAdapter {
}
let target_user_id = Uuid::parse_str(&dto.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "AddressBook", "Invalid target user ID format")
DomainError::new(
ErrorKind::InvalidInput,
"AddressBook",
"Invalid target user ID format",
)
})?;
self.address_book_repository
@@ -443,8 +458,7 @@ impl ContactUseCase for ContactStorageAdapter {
let user_id = Uuid::parse_str(&dto.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "Contact", "Invalid user ID format")
})?;
self.check_write_access(&address_book_id, user_id)
.await?;
self.check_write_access(&address_book_id, user_id).await?;
let now = chrono::Utc::now();
let mut contact = Contact::from_raw(
@@ -488,8 +502,7 @@ impl ContactUseCase for ContactStorageAdapter {
let user_id = Uuid::parse_str(&dto.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "Contact", "Invalid user ID format")
})?;
self.check_write_access(&address_book_id, user_id)
.await?;
self.check_write_access(&address_book_id, user_id).await?;
// Parse vCard fields
let now = chrono::Utc::now();
@@ -742,10 +755,13 @@ impl ContactUseCase for ContactStorageAdapter {
// Check write access
let user_id = Uuid::parse_str(&dto.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "ContactGroup", "Invalid user ID format")
DomainError::new(
ErrorKind::InvalidInput,
"ContactGroup",
"Invalid user ID format",
)
})?;
self.check_write_access(&address_book_id, user_id)
.await?;
self.check_write_access(&address_book_id, user_id).await?;
let group = ContactGroup::new(address_book_id, dto.name);
@@ -770,7 +786,11 @@ impl ContactUseCase for ContactStorageAdapter {
// Check write access
let user_id = Uuid::parse_str(&update.user_id).map_err(|_| {
DomainError::new(ErrorKind::InvalidInput, "ContactGroup", "Invalid user ID format")
DomainError::new(
ErrorKind::InvalidInput,
"ContactGroup",
"Invalid user ID format",
)
})?;
self.check_write_access(group.address_book_id(), user_id)
.await?;
+2 -1
View File
@@ -283,7 +283,8 @@ fn split_sql_statements(sql: &str) -> Vec<String> {
if i >= len {
break;
}
if bytes[i] == b'$' && i + tag_bytes.len() <= len
if bytes[i] == b'$'
&& i + tag_bytes.len() <= len
&& &bytes[i..i + tag_bytes.len()] == tag_bytes
{
current.push_str(&tag);
@@ -32,8 +32,8 @@ impl AppPasswordStoragePort for AppPasswordPgRepository {
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
"#,
)
.bind(&ap.id)
.bind(&ap.user_id)
.bind(ap.id)
.bind(ap.user_id)
.bind(&ap.label)
.bind(&ap.password_hash)
.bind(&ap.prefix)
@@ -21,16 +21,7 @@ use crate::domain::services::path_service::StoragePath;
type FolderRow = (String, String, String, Option<String>, Uuid, i64, i64);
/// Type alias for paginated folder rows (includes total_count).
type FolderRowPaginated = (
String,
String,
String,
Option<String>,
Uuid,
i64,
i64,
i64,
);
type FolderRowPaginated = (String, String, String, Option<String>, Uuid, i64, i64, i64);
/// Type alias for folder rows with optional user_id.
type FolderRowOptUser = (
@@ -108,14 +99,14 @@ impl FolderRepository for FolderDbRepository {
// caller to have set up the home folder beforehand (done during user
// registration).
let user_id: Uuid = if let Some(ref pid) = parent_id {
sqlx::query_scalar::<_, Uuid>(
"SELECT user_id FROM storage.folders WHERE id = $1::uuid",
)
.bind(pid)
.fetch_optional(self.pool())
.await
.map_err(|e| DomainError::internal_error("FolderDb", format!("parent lookup: {e}")))?
.ok_or_else(|| DomainError::not_found("Folder", pid))?
sqlx::query_scalar::<_, Uuid>("SELECT user_id FROM storage.folders WHERE id = $1::uuid")
.bind(pid)
.fetch_optional(self.pool())
.await
.map_err(|e| {
DomainError::internal_error("FolderDb", format!("parent lookup: {e}"))
})?
.ok_or_else(|| DomainError::not_found("Folder", pid))?
} else {
return Err(DomainError::internal_error(
"FolderDb",
@@ -647,15 +638,9 @@ impl FolderRepository for FolderDbRepository {
.map_err(|e| DomainError::internal_error("FolderDb", format!("home folder: {e}")))?;
match row {
Some((id, path, ca, ma)) => Self::row_to_folder(
id,
name.clone(),
path,
None,
Some(user_id),
ca,
ma,
),
Some((id, path, ca, ma)) => {
Self::row_to_folder(id, name.clone(), path, None, Some(user_id), ca, ma)
}
None => {
// Already exists — fetch it
let existing = sqlx::query_as::<_, (String, String, i64, i64)>(
@@ -195,16 +195,15 @@ impl ShareStoragePort for SharePgRepository {
}
async fn delete_share_for_user(&self, id: Uuid, user_id: Uuid) -> Result<(), DomainError> {
let result =
sqlx::query("DELETE FROM storage.shares WHERE id = $1 AND created_by = $2")
.bind(id)
.bind(user_id)
.execute(&*self.db_pool)
.await
.map_err(|e| {
tracing::error!("Database error deleting share for user: {}", e);
DomainError::internal_error("Share", format!("Failed to delete share: {e}"))
})?;
let result = sqlx::query("DELETE FROM storage.shares WHERE id = $1 AND created_by = $2")
.bind(id)
.bind(user_id)
.execute(&*self.db_pool)
.await
.map_err(|e| {
tracing::error!("Database error deleting share for user: {}", e);
DomainError::internal_error("Share", format!("Failed to delete share: {e}"))
})?;
if result.rows_affected() == 0 {
// SECURITY: could be non-existent or owned by another user — same 404
@@ -64,9 +64,9 @@ impl TrashDbRepository {
// In the soft-delete model, the trash entry ID is the same as the
// original item ID since there is no separate trash table.
TrashedItem::from_raw(
id, // trash entry id (same as original)
id, // original item id
user_id, // owner
id, // trash entry id (same as original)
id, // original item id
user_id, // owner
item_type_enum,
name.clone(),
String::new(), // original_path — not stored separately in soft-delete model
+3 -2
View File
@@ -262,10 +262,11 @@ impl TokenServicePort for JwtTokenService {
mod tests {
use super::*;
use crate::domain::entities::user::{User, UserRole};
use uuid::Uuid;
fn create_test_user() -> User {
User::from_data(
"test-user-id".to_string(),
Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(),
"testuser".to_string(),
"test@example.com".to_string(),
"hashed_password".to_string(),
@@ -295,7 +296,7 @@ mod tests {
let claims = service
.validate_token(&token)
.expect("Should validate token");
assert_eq!(claims.sub, user.id());
assert_eq!(claims.sub, user.id().to_string());
assert_eq!(claims.username, user.username());
assert_eq!(claims.email, user.email());
}
@@ -1,6 +1,6 @@
use bytes::Bytes;
use image::imageops::FilterType;
use image::codecs::jpeg::JpegEncoder;
use image::imageops::FilterType;
/**
* Thumbnail Generation Service
*
@@ -236,20 +236,16 @@ impl ThumbnailService {
/// Unlike `get_thumbnail`, this does **not** generate a new thumbnail.
/// Useful for non-image file types (videos) where a client-generated
/// thumbnail may have been uploaded previously.
pub async fn get_cached_thumbnail(
&self,
file_id: &str,
size: ThumbnailSize,
) -> Option<Bytes> {
pub async fn get_cached_thumbnail(&self, file_id: &str, size: ThumbnailSize) -> Option<Bytes> {
// 1. Check in-memory cache
let cache_key = ThumbnailCacheKey {
file_id: file_id.to_string(),
size,
};
if let Some(bytes) = self.cache.get(&cache_key).await {
if !bytes.is_empty() {
return Some(bytes);
}
if let Some(bytes) = self.cache.get(&cache_key).await
&& !bytes.is_empty()
{
return Some(bytes);
}
// 2. Check disk
@@ -285,17 +281,17 @@ impl ThumbnailService {
let jpeg_bytes = tokio::task::spawn_blocking(move || -> Result<Vec<u8>, ThumbnailError> {
// ── Fast path: already a correctly-sized JPEG ─────────────
// JPEG files start with SOI marker 0xFF 0xD8.
if data.len() >= 2 && data[0] == 0xFF && data[1] == 0xD8 {
if let Ok(reader) = image::ImageReader::new(std::io::Cursor::new(&data))
.with_guessed_format()
{
if let Ok((w, h)) = reader.into_dimensions() {
if w <= max_dim && h <= max_dim {
// Already JPEG at correct size — zero-copy store
return Ok(data.to_vec());
}
}
}
if data.len() >= 2
&& data[0] == 0xFF
&& data[1] == 0xD8
&& let Ok(reader) =
image::ImageReader::new(std::io::Cursor::new(&data)).with_guessed_format()
&& let Ok((w, h)) = reader.into_dimensions()
&& w <= max_dim
&& h <= max_dim
{
// Already JPEG at correct size — zero-copy store
return Ok(data.to_vec());
}
// ── Slow path: decode, resize, re-encode to JPEG ─────────
@@ -637,11 +633,7 @@ impl ThumbnailPort for ThumbnailService {
.map_err(|e| DomainError::new(ErrorKind::InternalError, "Thumbnail", e.to_string()))
}
async fn get_cached_thumbnail(
&self,
file_id: &str,
size: PortThumbnailSize,
) -> Option<Bytes> {
async fn get_cached_thumbnail(&self, file_id: &str, size: PortThumbnailSize) -> Option<Bytes> {
self.get_cached_thumbnail(file_id, size.into()).await
}