style: apply cargo fmt to entire codebase

Standardize code formatting across all 173 Rust source files
using rustfmt. No functional changes - purely cosmetic.

This establishes a consistent code style baseline for the
project going forward.
This commit is contained in:
Dionisio
2026-02-14 01:29:34 +01:00
parent 67137a3ef2
commit 4c98c5a657
173 changed files with 23368 additions and 17590 deletions
+59 -31
View File
@@ -1,20 +1,20 @@
use async_trait::async_trait;
use crate::domain::entities::user::User;
use crate::domain::entities::session::Session;
use crate::common::errors::DomainError;
use crate::domain::entities::session::Session;
use crate::domain::entities::user::User;
use async_trait::async_trait;
// ============================================================================
// Cryptography Ports - Extracted from Domain to maintain Clean Architecture
// ============================================================================
/// Port for password hashing operations.
///
///
/// This trait abstracts cryptographic password operations, allowing the domain
/// layer to remain independent of specific hashing implementations (argon2, bcrypt, etc.)
pub trait PasswordHasherPort: Send + Sync + 'static {
/// Hash a plain text password
fn hash_password(&self, password: &str) -> Result<String, DomainError>;
/// Verify a plain text password against a hash
fn verify_password(&self, password: &str, hash: &str) -> Result<bool, DomainError>;
}
@@ -39,22 +39,22 @@ pub struct TokenClaims {
}
/// Port for JWT token operations.
///
///
/// This trait abstracts token generation and validation, allowing the domain
/// layer to remain independent of specific JWT implementations.
pub trait TokenServicePort: Send + Sync + 'static {
/// Generate an access token for a user
fn generate_access_token(&self, user: &User) -> Result<String, DomainError>;
/// Validate a token and extract its claims
fn validate_token(&self, token: &str) -> Result<TokenClaims, DomainError>;
/// Generate a refresh token
fn generate_refresh_token(&self) -> String;
/// Get refresh token expiry in seconds
fn refresh_token_expiry_secs(&self) -> i64;
/// Get refresh token expiry in days
fn refresh_token_expiry_days(&self) -> i64;
}
@@ -65,38 +65,46 @@ pub trait TokenServicePort: Send + Sync + 'static {
#[async_trait]
pub trait UserStoragePort: Send + Sync + 'static {
/// Creates a new user
/// Creates a new user
async fn create_user(&self, user: User) -> Result<User, DomainError>;
/// Gets a user by ID
async fn get_user_by_id(&self, id: &str) -> Result<User, DomainError>;
/// Gets a user by username
async fn get_user_by_username(&self, username: &str) -> Result<User, DomainError>;
/// Gets a user by email
async fn get_user_by_email(&self, email: &str) -> Result<User, DomainError>;
/// Updates an existing user
async fn update_user(&self, user: User) -> Result<User, DomainError>;
/// Updates only the storage usage of a user
async fn update_storage_usage(&self, user_id: &str, usage_bytes: i64) -> Result<(), DomainError>;
async fn update_storage_usage(
&self,
user_id: &str,
usage_bytes: i64,
) -> Result<(), DomainError>;
/// Lists users with pagination
async fn list_users(&self, limit: i64, offset: i64) -> Result<Vec<User>, DomainError>;
/// Lists users by role (e.g., "admin" or "user")
async fn list_users_by_role(&self, role: &str) -> Result<Vec<User>, DomainError>;
/// Deletes a user by their ID
async fn delete_user(&self, user_id: &str) -> Result<(), DomainError>;
/// Changes a user's password
async fn change_password(&self, user_id: &str, password_hash: &str) -> Result<(), DomainError>;
/// Finds a user by OIDC provider + subject pair
async fn get_user_by_oidc_subject(&self, provider: &str, subject: &str) -> Result<User, DomainError>;
async fn get_user_by_oidc_subject(
&self,
provider: &str,
subject: &str,
) -> Result<User, DomainError>;
/// Activates or deactivates a user
async fn set_user_active_status(&self, user_id: &str, active: bool) -> Result<(), DomainError>;
@@ -105,7 +113,11 @@ pub trait UserStoragePort: Send + Sync + 'static {
async fn change_role(&self, user_id: &str, role: &str) -> Result<(), DomainError>;
/// Updates a user's storage quota
async fn update_storage_quota(&self, user_id: &str, quota_bytes: i64) -> Result<(), DomainError>;
async fn update_storage_quota(
&self,
user_id: &str,
quota_bytes: i64,
) -> Result<(), DomainError>;
/// Counts the total number of users
async fn count_users(&self) -> Result<i64, DomainError>;
@@ -139,14 +151,27 @@ pub trait OidcServicePort: Send + Sync + 'static {
/// Get the authorization URL for redirecting the user to the IdP.
/// Includes PKCE code_challenge (S256) and nonce for ID token binding.
/// This is async because it may need to fetch the OIDC discovery document.
async fn get_authorize_url(&self, state: &str, nonce: &str, pkce_challenge: &str) -> Result<String, DomainError>;
async fn get_authorize_url(
&self,
state: &str,
nonce: &str,
pkce_challenge: &str,
) -> Result<String, DomainError>;
/// Exchange an authorization code for tokens, providing PKCE code_verifier.
async fn exchange_code(&self, code: &str, pkce_verifier: &str) -> Result<OidcTokenSet, DomainError>;
async fn exchange_code(
&self,
code: &str,
pkce_verifier: &str,
) -> Result<OidcTokenSet, DomainError>;
/// Validate an ID token and extract claims.
/// If `expected_nonce` is provided, verifies the `nonce` claim matches.
async fn validate_id_token(&self, id_token: &str, expected_nonce: Option<&str>) -> Result<OidcIdClaims, DomainError>;
async fn validate_id_token(
&self,
id_token: &str,
expected_nonce: Option<&str>,
) -> Result<OidcIdClaims, DomainError>;
/// Fetch user info from the UserInfo endpoint (fallback for missing ID token claims)
async fn fetch_user_info(&self, access_token: &str) -> Result<OidcIdClaims, DomainError>;
@@ -159,13 +184,16 @@ pub trait OidcServicePort: Send + Sync + 'static {
pub trait SessionStoragePort: Send + Sync + 'static {
/// Creates a new session
async fn create_session(&self, session: Session) -> Result<Session, DomainError>;
/// Gets a session by refresh token
async fn get_session_by_refresh_token(&self, refresh_token: &str) -> Result<Session, DomainError>;
async fn get_session_by_refresh_token(
&self,
refresh_token: &str,
) -> Result<Session, DomainError>;
/// Revokes a specific session
async fn revoke_session(&self, session_id: &str) -> Result<(), DomainError>;
/// Revokes all sessions of a user
async fn revoke_all_user_sessions(&self, user_id: &str) -> Result<u64, DomainError>;
}
}
+2 -2
View File
@@ -8,10 +8,10 @@
//! The application and interface layers remain independent of the caching
//! implementation details.
use std::path::{Path, PathBuf};
use crate::common::errors::DomainError;
use async_trait::async_trait;
use bytes::Bytes;
use crate::common::errors::DomainError;
use std::path::{Path, PathBuf};
/// Statistics for monitoring write-behind cache status.
#[derive(Debug, Clone, Default)]
+187 -54
View File
@@ -1,47 +1,108 @@
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use crate::application::dtos::calendar_dto::{
CalendarDto, CalendarEventDto, CreateCalendarDto, UpdateCalendarDto,
CreateEventDto, UpdateEventDto, CreateEventICalDto
CalendarDto, CalendarEventDto, CreateCalendarDto, CreateEventDto, CreateEventICalDto,
UpdateCalendarDto, UpdateEventDto,
};
use crate::common::errors::DomainError;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
/// Port for external calendar storage mechanisms
#[async_trait]
pub trait CalendarStoragePort: Send + Sync + 'static {
// Calendar operations
async fn create_calendar(&self, calendar: CreateCalendarDto, owner_id: &str) -> Result<CalendarDto, DomainError>;
async fn update_calendar(&self, calendar_id: &str, update: UpdateCalendarDto) -> Result<CalendarDto, DomainError>;
async fn create_calendar(
&self,
calendar: CreateCalendarDto,
owner_id: &str,
) -> Result<CalendarDto, DomainError>;
async fn update_calendar(
&self,
calendar_id: &str,
update: UpdateCalendarDto,
) -> Result<CalendarDto, DomainError>;
async fn delete_calendar(&self, calendar_id: &str) -> Result<(), DomainError>;
async fn get_calendar(&self, calendar_id: &str) -> Result<CalendarDto, DomainError>;
async fn list_calendars_by_owner(&self, owner_id: &str) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_calendars_shared_with_user(&self, user_id: &str) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_public_calendars(&self, limit: i64, offset: i64) -> Result<Vec<CalendarDto>, DomainError>;
async fn check_calendar_access(&self, calendar_id: &str, user_id: &str) -> Result<bool, DomainError>;
async fn list_calendars_by_owner(
&self,
owner_id: &str,
) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_calendars_shared_with_user(
&self,
user_id: &str,
) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_public_calendars(
&self,
limit: i64,
offset: i64,
) -> Result<Vec<CalendarDto>, DomainError>;
async fn check_calendar_access(
&self,
calendar_id: &str,
user_id: &str,
) -> Result<bool, DomainError>;
// Calendar sharing
async fn share_calendar(&self, calendar_id: &str, user_id: &str, access_level: &str) -> Result<(), DomainError>;
async fn remove_calendar_sharing(&self, calendar_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_calendar_shares(&self, calendar_id: &str) -> Result<Vec<(String, String)>, DomainError>;
async fn share_calendar(
&self,
calendar_id: &str,
user_id: &str,
access_level: &str,
) -> Result<(), DomainError>;
async fn remove_calendar_sharing(
&self,
calendar_id: &str,
user_id: &str,
) -> Result<(), DomainError>;
async fn get_calendar_shares(
&self,
calendar_id: &str,
) -> Result<Vec<(String, String)>, DomainError>;
// Calendar properties
async fn set_calendar_property(&self, calendar_id: &str, property_name: &str, property_value: &str) -> Result<(), DomainError>;
async fn get_calendar_property(&self, calendar_id: &str, property_name: &str) -> Result<Option<String>, DomainError>;
async fn get_calendar_properties(&self, calendar_id: &str) -> Result<std::collections::HashMap<String, String>, DomainError>;
async fn set_calendar_property(
&self,
calendar_id: &str,
property_name: &str,
property_value: &str,
) -> Result<(), DomainError>;
async fn get_calendar_property(
&self,
calendar_id: &str,
property_name: &str,
) -> Result<Option<String>, DomainError>;
async fn get_calendar_properties(
&self,
calendar_id: &str,
) -> Result<std::collections::HashMap<String, String>, DomainError>;
// Event operations
async fn create_event(&self, event: CreateEventDto) -> Result<CalendarEventDto, DomainError>;
async fn create_event_from_ical(&self, event: CreateEventICalDto) -> Result<CalendarEventDto, DomainError>;
async fn update_event(&self, event_id: &str, update: UpdateEventDto) -> Result<CalendarEventDto, DomainError>;
async fn create_event_from_ical(
&self,
event: CreateEventICalDto,
) -> Result<CalendarEventDto, DomainError>;
async fn update_event(
&self,
event_id: &str,
update: UpdateEventDto,
) -> Result<CalendarEventDto, DomainError>;
async fn delete_event(&self, event_id: &str) -> Result<(), DomainError>;
async fn get_event(&self, event_id: &str) -> Result<CalendarEventDto, DomainError>;
async fn list_events_by_calendar(&self, calendar_id: &str) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn list_events_by_calendar_paginated(&self, calendar_id: &str, limit: i64, offset: i64) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn list_events_by_calendar(
&self,
calendar_id: &str,
) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn list_events_by_calendar_paginated(
&self,
calendar_id: &str,
limit: i64,
offset: i64,
) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn get_events_in_time_range(
&self,
calendar_id: &str,
start: &DateTime<Utc>,
end: &DateTime<Utc>
&self,
calendar_id: &str,
start: &DateTime<Utc>,
end: &DateTime<Utc>,
) -> Result<Vec<CalendarEventDto>, DomainError>;
}
@@ -49,41 +110,113 @@ pub trait CalendarStoragePort: Send + Sync + 'static {
#[async_trait]
pub trait CalendarUseCase: Send + Sync + 'static {
// Calendar operations
async fn create_calendar(&self, calendar: CreateCalendarDto) -> Result<CalendarDto, DomainError>;
async fn update_calendar(&self, calendar_id: &str, update: UpdateCalendarDto) -> Result<CalendarDto, DomainError>;
async fn create_calendar(
&self,
calendar: CreateCalendarDto,
) -> Result<CalendarDto, DomainError>;
async fn update_calendar(
&self,
calendar_id: &str,
update: UpdateCalendarDto,
) -> Result<CalendarDto, DomainError>;
async fn delete_calendar(&self, calendar_id: &str) -> Result<(), DomainError>;
async fn get_calendar(&self, calendar_id: &str) -> Result<CalendarDto, DomainError>;
async fn list_my_calendars(&self) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_shared_calendars(&self) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_public_calendars(&self, limit: Option<i64>, offset: Option<i64>) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_public_calendars(
&self,
limit: Option<i64>,
offset: Option<i64>,
) -> Result<Vec<CalendarDto>, DomainError>;
// Calendar sharing
async fn share_calendar(&self, calendar_id: &str, user_id: &str, access_level: &str) -> Result<(), DomainError>;
async fn remove_calendar_sharing(&self, calendar_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_calendar_shares(&self, calendar_id: &str) -> Result<Vec<(String, String)>, DomainError>;
async fn share_calendar(
&self,
calendar_id: &str,
user_id: &str,
access_level: &str,
) -> Result<(), DomainError>;
async fn remove_calendar_sharing(
&self,
calendar_id: &str,
user_id: &str,
) -> Result<(), DomainError>;
async fn get_calendar_shares(
&self,
calendar_id: &str,
) -> Result<Vec<(String, String)>, DomainError>;
// Event operations
async fn create_event(&self, event: CreateEventDto) -> Result<CalendarEventDto, DomainError>;
async fn create_event_from_ical(&self, event: CreateEventICalDto) -> Result<CalendarEventDto, DomainError>;
async fn update_event(&self, event_id: &str, update: UpdateEventDto) -> Result<CalendarEventDto, DomainError>;
async fn create_event_from_ical(
&self,
event: CreateEventICalDto,
) -> Result<CalendarEventDto, DomainError>;
async fn update_event(
&self,
event_id: &str,
update: UpdateEventDto,
) -> Result<CalendarEventDto, DomainError>;
async fn delete_event(&self, event_id: &str) -> Result<(), DomainError>;
async fn get_event(&self, event_id: &str) -> Result<CalendarEventDto, DomainError>;
async fn list_events(&self, calendar_id: &str, limit: Option<i64>, offset: Option<i64>) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn get_events_in_range(
&self,
calendar_id: &str,
start: DateTime<Utc>,
end: DateTime<Utc>
async fn list_events(
&self,
calendar_id: &str,
limit: Option<i64>,
offset: Option<i64>,
) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn get_events_in_range(
&self,
calendar_id: &str,
start: DateTime<Utc>,
end: DateTime<Utc>,
) -> Result<Vec<CalendarEventDto>, DomainError>;
// ─── User-contextualized variants (for CalDAV protocol handler) ──
async fn create_calendar_for_user(&self, calendar: CreateCalendarDto, user_id: &str) -> Result<CalendarDto, DomainError>;
async fn update_calendar_for_user(&self, calendar_id: &str, update: UpdateCalendarDto, user_id: &str) -> Result<CalendarDto, DomainError>;
async fn delete_calendar_for_user(&self, calendar_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_calendar_for_user(&self, calendar_id: &str, user_id: &str) -> Result<CalendarDto, DomainError>;
async fn list_my_calendars_for_user(&self, user_id: &str) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_events_for_user(&self, calendar_id: &str, limit: Option<i64>, offset: Option<i64>, user_id: &str) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn get_events_in_range_for_user(&self, calendar_id: &str, start: DateTime<Utc>, end: DateTime<Utc>, user_id: &str) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn create_event_from_ical_for_user(&self, event: CreateEventICalDto, user_id: &str) -> Result<CalendarEventDto, DomainError>;
async fn delete_event_for_user(&self, event_id: &str, user_id: &str) -> Result<(), DomainError>;
}
async fn create_calendar_for_user(
&self,
calendar: CreateCalendarDto,
user_id: &str,
) -> Result<CalendarDto, DomainError>;
async fn update_calendar_for_user(
&self,
calendar_id: &str,
update: UpdateCalendarDto,
user_id: &str,
) -> Result<CalendarDto, DomainError>;
async fn delete_calendar_for_user(
&self,
calendar_id: &str,
user_id: &str,
) -> Result<(), DomainError>;
async fn get_calendar_for_user(
&self,
calendar_id: &str,
user_id: &str,
) -> Result<CalendarDto, DomainError>;
async fn list_my_calendars_for_user(
&self,
user_id: &str,
) -> Result<Vec<CalendarDto>, DomainError>;
async fn list_events_for_user(
&self,
calendar_id: &str,
limit: Option<i64>,
offset: Option<i64>,
user_id: &str,
) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn get_events_in_range_for_user(
&self,
calendar_id: &str,
start: DateTime<Utc>,
end: DateTime<Utc>,
user_id: &str,
) -> Result<Vec<CalendarEventDto>, DomainError>;
async fn create_event_from_ical_for_user(
&self,
event: CreateEventICalDto,
user_id: &str,
) -> Result<CalendarEventDto, DomainError>;
async fn delete_event_for_user(&self, event_id: &str, user_id: &str)
-> Result<(), DomainError>;
}
+120 -34
View File
@@ -1,57 +1,143 @@
use async_trait::async_trait;
use crate::common::errors::DomainError;
use crate::application::dtos::address_book_dto::{
AddressBookDto, CreateAddressBookDto, UpdateAddressBookDto,
ShareAddressBookDto, UnshareAddressBookDto
AddressBookDto, CreateAddressBookDto, ShareAddressBookDto, UnshareAddressBookDto,
UpdateAddressBookDto,
};
use crate::application::dtos::contact_dto::{
ContactDto, CreateContactDto, UpdateContactDto, CreateContactVCardDto,
ContactGroupDto, CreateContactGroupDto, UpdateContactGroupDto, GroupMembershipDto
ContactDto, ContactGroupDto, CreateContactDto, CreateContactGroupDto, CreateContactVCardDto,
GroupMembershipDto, UpdateContactDto, UpdateContactGroupDto,
};
use crate::common::errors::DomainError;
use async_trait::async_trait;
pub type CardDavRepositoryError = DomainError;
#[async_trait]
pub trait AddressBookUseCase: Send + Sync + 'static {
// Address Book operations
async fn create_address_book(&self, dto: CreateAddressBookDto) -> Result<AddressBookDto, DomainError>;
async fn update_address_book(&self, address_book_id: &str, update: UpdateAddressBookDto) -> Result<AddressBookDto, DomainError>;
async fn delete_address_book(&self, address_book_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_address_book(&self, address_book_id: &str, user_id: &str) -> Result<AddressBookDto, DomainError>;
async fn list_user_address_books(&self, user_id: &str) -> Result<Vec<AddressBookDto>, DomainError>;
async fn create_address_book(
&self,
dto: CreateAddressBookDto,
) -> Result<AddressBookDto, DomainError>;
async fn update_address_book(
&self,
address_book_id: &str,
update: UpdateAddressBookDto,
) -> Result<AddressBookDto, DomainError>;
async fn delete_address_book(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<(), DomainError>;
async fn get_address_book(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<AddressBookDto, DomainError>;
async fn list_user_address_books(
&self,
user_id: &str,
) -> Result<Vec<AddressBookDto>, DomainError>;
async fn list_public_address_books(&self) -> Result<Vec<AddressBookDto>, DomainError>;
// Address Book sharing
async fn share_address_book(&self, dto: ShareAddressBookDto, user_id: &str) -> Result<(), DomainError>;
async fn unshare_address_book(&self, dto: UnshareAddressBookDto, user_id: &str) -> Result<(), DomainError>;
async fn get_address_book_shares(&self, address_book_id: &str, user_id: &str) -> Result<Vec<(String, bool)>, DomainError>;
async fn share_address_book(
&self,
dto: ShareAddressBookDto,
user_id: &str,
) -> Result<(), DomainError>;
async fn unshare_address_book(
&self,
dto: UnshareAddressBookDto,
user_id: &str,
) -> Result<(), DomainError>;
async fn get_address_book_shares(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<Vec<(String, bool)>, DomainError>;
}
#[async_trait]
pub trait ContactUseCase: Send + Sync + 'static {
// Contact operations
async fn create_contact(&self, dto: CreateContactDto) -> Result<ContactDto, DomainError>;
async fn create_contact_from_vcard(&self, dto: CreateContactVCardDto) -> Result<ContactDto, DomainError>;
async fn update_contact(&self, contact_id: &str, update: UpdateContactDto) -> Result<ContactDto, DomainError>;
async fn create_contact_from_vcard(
&self,
dto: CreateContactVCardDto,
) -> Result<ContactDto, DomainError>;
async fn update_contact(
&self,
contact_id: &str,
update: UpdateContactDto,
) -> Result<ContactDto, DomainError>;
async fn delete_contact(&self, contact_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_contact(&self, contact_id: &str, user_id: &str) -> Result<ContactDto, DomainError>;
async fn list_contacts(&self, address_book_id: &str, user_id: &str) -> Result<Vec<ContactDto>, DomainError>;
async fn search_contacts(&self, address_book_id: &str, query: &str, user_id: &str) -> Result<Vec<ContactDto>, DomainError>;
async fn get_contact(&self, contact_id: &str, user_id: &str)
-> Result<ContactDto, DomainError>;
async fn list_contacts(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<Vec<ContactDto>, DomainError>;
async fn search_contacts(
&self,
address_book_id: &str,
query: &str,
user_id: &str,
) -> Result<Vec<ContactDto>, DomainError>;
// Contact Group operations
async fn create_group(&self, dto: CreateContactGroupDto) -> Result<ContactGroupDto, DomainError>;
async fn update_group(&self, group_id: &str, update: UpdateContactGroupDto) -> Result<ContactGroupDto, DomainError>;
async fn create_group(
&self,
dto: CreateContactGroupDto,
) -> Result<ContactGroupDto, DomainError>;
async fn update_group(
&self,
group_id: &str,
update: UpdateContactGroupDto,
) -> Result<ContactGroupDto, DomainError>;
async fn delete_group(&self, group_id: &str, user_id: &str) -> Result<(), DomainError>;
async fn get_group(&self, group_id: &str, user_id: &str) -> Result<ContactGroupDto, DomainError>;
async fn list_groups(&self, address_book_id: &str, user_id: &str) -> Result<Vec<ContactGroupDto>, DomainError>;
async fn get_group(
&self,
group_id: &str,
user_id: &str,
) -> Result<ContactGroupDto, DomainError>;
async fn list_groups(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<Vec<ContactGroupDto>, DomainError>;
// Group membership
async fn add_contact_to_group(&self, dto: GroupMembershipDto, user_id: &str) -> Result<(), DomainError>;
async fn remove_contact_from_group(&self, dto: GroupMembershipDto, user_id: &str) -> Result<(), DomainError>;
async fn list_contacts_in_group(&self, group_id: &str, user_id: &str) -> Result<Vec<ContactDto>, DomainError>;
async fn list_groups_for_contact(&self, contact_id: &str, user_id: &str) -> Result<Vec<ContactGroupDto>, DomainError>;
async fn add_contact_to_group(
&self,
dto: GroupMembershipDto,
user_id: &str,
) -> Result<(), DomainError>;
async fn remove_contact_from_group(
&self,
dto: GroupMembershipDto,
user_id: &str,
) -> Result<(), DomainError>;
async fn list_contacts_in_group(
&self,
group_id: &str,
user_id: &str,
) -> Result<Vec<ContactDto>, DomainError>;
async fn list_groups_for_contact(
&self,
contact_id: &str,
user_id: &str,
) -> Result<Vec<ContactGroupDto>, DomainError>;
// vCard operations
async fn get_contact_vcard(&self, contact_id: &str, user_id: &str) -> Result<String, DomainError>;
async fn get_contacts_as_vcards(&self, address_book_id: &str, user_id: &str) -> Result<Vec<(String, String)>, DomainError>;
}
async fn get_contact_vcard(
&self,
contact_id: &str,
user_id: &str,
) -> Result<String, DomainError>;
async fn get_contacts_as_vcards(
&self,
address_book_id: &str,
user_id: &str,
) -> Result<Vec<(String, String)>, DomainError>;
}
+5 -14
View File
@@ -4,11 +4,11 @@
//! operations, keeping the application and interface layers independent of
//! the specific upload implementation (TUS-like protocol, S3 multipart, etc.).
use std::path::PathBuf;
use crate::common::errors::DomainError;
use async_trait::async_trait;
use bytes::Bytes;
use serde::Serialize;
use crate::common::errors::DomainError;
use std::path::PathBuf;
/// Default chunk size (5 MB) — optimised for parallel transfers.
pub const DEFAULT_CHUNK_SIZE: usize = 5 * 1024 * 1024;
@@ -80,10 +80,7 @@ pub trait ChunkedUploadPort: Send + Sync + 'static {
) -> Result<ChunkUploadResponseDto, DomainError>;
/// Get the current status of an upload session.
async fn get_status(
&self,
upload_id: &str,
) -> Result<UploadStatusResponseDto, DomainError>;
async fn get_status(&self, upload_id: &str) -> Result<UploadStatusResponseDto, DomainError>;
/// Assemble all chunks into the final file.
///
@@ -94,16 +91,10 @@ pub trait ChunkedUploadPort: Send + Sync + 'static {
) -> Result<(PathBuf, String, Option<String>, String, u64), DomainError>;
/// Finalize upload: clean up the session and temporary files.
async fn finalize_upload(
&self,
upload_id: &str,
) -> Result<(), DomainError>;
async fn finalize_upload(&self, upload_id: &str) -> Result<(), DomainError>;
/// Cancel an upload and clean up all temporary data.
async fn cancel_upload(
&self,
upload_id: &str,
) -> Result<(), DomainError>;
async fn cancel_upload(&self, upload_id: &str) -> Result<(), DomainError>;
/// Check if a file size qualifies for chunked upload.
fn should_use_chunked(&self, size: u64) -> bool;
+6 -2
View File
@@ -4,8 +4,8 @@
//! keeping the application and interface layers independent of specific
//! compression implementations (gzip, zstd, etc.).
use async_trait::async_trait;
use crate::common::errors::DomainError;
use async_trait::async_trait;
/// Compression level settings for file compression operations.
///
@@ -30,7 +30,11 @@ pub enum CompressionLevel {
#[async_trait]
pub trait CompressionPort: Send + Sync + 'static {
/// Compress data in memory.
async fn compress_data(&self, data: &[u8], level: CompressionLevel) -> Result<Vec<u8>, DomainError>;
async fn compress_data(
&self,
data: &[u8],
level: CompressionLevel,
) -> Result<Vec<u8>, DomainError>;
/// Decompress data in memory.
async fn decompress_data(&self, compressed_data: &[u8]) -> Result<Vec<u8>, DomainError>;
+2 -2
View File
@@ -4,11 +4,11 @@
//! keeping the application and interface layers independent of the specific
//! content-addressable storage implementation.
use std::path::{Path, PathBuf};
use crate::common::errors::DomainError;
use async_trait::async_trait;
use bytes::Bytes;
use serde::Serialize;
use crate::common::errors::DomainError;
use std::path::{Path, PathBuf};
/// Metadata of a stored blob in the dedup system.
#[derive(Debug, Clone, Serialize)]
+12 -7
View File
@@ -1,19 +1,24 @@
use async_trait::async_trait;
use crate::common::errors::Result;
use crate::application::dtos::favorites_dto::FavoriteItemDto;
use crate::common::errors::Result;
use async_trait::async_trait;
/// Defines operations for managing user favorites
#[async_trait]
pub trait FavoritesUseCase: Send + Sync {
/// Get all favorites for a user
async fn get_favorites(&self, user_id: &str) -> Result<Vec<FavoriteItemDto>>;
/// Add an item to user's favorites
async fn add_to_favorites(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<()>;
/// Remove an item from user's favorites
async fn remove_from_favorites(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool>;
async fn remove_from_favorites(
&self,
user_id: &str,
item_id: &str,
item_type: &str,
) -> Result<bool>;
/// Check if an item is in user's favorites
async fn is_favorite(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool>;
}
@@ -40,4 +45,4 @@ pub trait FavoritesRepositoryPort: Send + Sync + 'static {
/// Checks if an item is in favorites.
async fn is_favorite(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool>;
}
}
+26 -17
View File
@@ -1,8 +1,8 @@
use std::sync::Arc;
use std::pin::Pin;
use async_trait::async_trait;
use bytes::Bytes;
use futures::Stream;
use std::pin::Pin;
use std::sync::Arc;
use crate::application::dtos::file_dto::FileDto;
use crate::common::errors::DomainError;
@@ -48,7 +48,13 @@ pub trait FileUploadUseCase: Send + Sync + 'static {
) -> Result<(FileDto, UploadStrategy), DomainError>;
/// Creates a new file at the specified path (for WebDAV)
async fn create_file(&self, parent_path: &str, filename: &str, content: &[u8], content_type: &str) -> Result<FileDto, DomainError>;
async fn create_file(
&self,
parent_path: &str,
filename: &str,
content: &[u8],
content_type: &str,
) -> Result<FileDto, DomainError>;
/// Updates the content of an existing file (for WebDAV)
async fn update_file(&self, path: &str, content: &[u8]) -> Result<(), DomainError>;
@@ -81,18 +87,21 @@ pub enum OptimizedFileContent {
pub trait FileRetrievalUseCase: Send + Sync + 'static {
/// Gets a file by its ID
async fn get_file(&self, id: &str) -> Result<FileDto, DomainError>;
/// Gets a file by its path (for WebDAV)
async fn get_file_by_path(&self, path: &str) -> Result<FileDto, DomainError>;
/// Lists files in a folder
async fn list_files(&self, folder_id: Option<&str>) -> Result<Vec<FileDto>, DomainError>;
/// Gets file content as bytes (for small files)
async fn get_file_content(&self, id: &str) -> Result<Vec<u8>, DomainError>;
/// Gets file content as a stream (for large files)
async fn get_file_stream(&self, id: &str) -> Result<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>, DomainError>;
async fn get_file_stream(
&self,
id: &str,
) -> Result<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>, DomainError>;
/// Optimized multi-tier download.
///
@@ -123,11 +132,15 @@ pub trait FileRetrievalUseCase: Send + Sync + 'static {
#[async_trait]
pub trait FileManagementUseCase: Send + Sync + 'static {
/// Moves a file to another folder
async fn move_file(&self, file_id: &str, folder_id: Option<String>) -> Result<FileDto, DomainError>;
async fn move_file(
&self,
file_id: &str,
folder_id: Option<String>,
) -> Result<FileDto, DomainError>;
/// Renames a file
async fn rename_file(&self, file_id: &str, new_name: &str) -> Result<FileDto, DomainError>;
/// Deletes a file
async fn delete_file(&self, id: &str) -> Result<(), DomainError>;
@@ -138,11 +151,7 @@ pub trait FileManagementUseCase: Send + Sync + 'static {
/// 3. Decrements the dedup reference count for the content hash.
///
/// Returns `Ok(true)` when trashed, `Ok(false)` when permanently deleted.
async fn delete_with_cleanup(
&self,
id: &str,
user_id: &str,
) -> Result<bool, DomainError>;
async fn delete_with_cleanup(&self, id: &str, user_id: &str) -> Result<bool, DomainError>;
}
/// Factory for creating file use case implementations
@@ -150,4 +159,4 @@ pub trait FileUseCaseFactory: Send + Sync + 'static {
fn create_file_upload_use_case(&self) -> Arc<dyn FileUploadUseCase>;
fn create_file_retrieval_use_case(&self) -> Arc<dyn FileRetrievalUseCase>;
fn create_file_management_use_case(&self) -> Arc<dyn FileManagementUseCase>;
}
}
+19 -16
View File
@@ -1,6 +1,8 @@
use async_trait::async_trait;
use crate::application::dtos::folder_dto::{CreateFolderDto, FolderDto, MoveFolderDto, RenameFolderDto};
use crate::application::dtos::folder_dto::{
CreateFolderDto, FolderDto, MoveFolderDto, RenameFolderDto,
};
use crate::application::dtos::search_dto::{SearchCriteriaDto, SearchResultsDto};
use crate::common::errors::DomainError;
@@ -9,36 +11,37 @@ use crate::common::errors::DomainError;
pub trait FolderUseCase: Send + Sync + 'static {
/// Creates a new folder
async fn create_folder(&self, dto: CreateFolderDto) -> Result<FolderDto, DomainError>;
/// Gets a folder by its ID
async fn get_folder(&self, id: &str) -> Result<FolderDto, DomainError>;
/// Gets a folder by its path
async fn get_folder_by_path(&self, path: &str) -> Result<FolderDto, DomainError>;
/// Lists folders within a parent folder
async fn list_folders(&self, parent_id: Option<&str>) -> Result<Vec<FolderDto>, DomainError>;
/// Lists folders with pagination
async fn list_folders_paginated(
&self,
&self,
parent_id: Option<&str>,
pagination: &crate::application::dtos::pagination::PaginationRequestDto
pagination: &crate::application::dtos::pagination::PaginationRequestDto,
) -> Result<crate::application::dtos::pagination::PaginatedResponseDto<FolderDto>, DomainError>;
/// Renames a folder
async fn rename_folder(&self, id: &str, dto: RenameFolderDto) -> Result<FolderDto, DomainError>;
async fn rename_folder(&self, id: &str, dto: RenameFolderDto)
-> Result<FolderDto, DomainError>;
/// Moves a folder to another parent
async fn move_folder(&self, id: &str, dto: MoveFolderDto) -> Result<FolderDto, DomainError>;
/// Deletes a folder
async fn delete_folder(&self, id: &str) -> Result<(), DomainError>;
}
/**
* Primary port for file and folder search
*
*
* Defines the operations related to advanced search of
* files and folders based on various criteria.
*/
@@ -46,16 +49,16 @@ pub trait FolderUseCase: Send + Sync + 'static {
pub trait SearchUseCase: Send + Sync + 'static {
/**
* Performs a search based on the specified criteria
*
*
* @param criteria Search criteria including text, dates, sizes, etc.
* @return Search results containing matching files and folders
*/
async fn search(&self, criteria: SearchCriteriaDto) -> Result<SearchResultsDto, DomainError>;
/**
* Clears the search results cache
*
*
* @return Result indicating success or error
*/
async fn clear_search_cache(&self) -> Result<(), DomainError>;
}
}
+1 -1
View File
@@ -15,4 +15,4 @@ pub mod storage_ports;
pub mod thumbnail_ports;
pub mod transcode_ports;
pub mod trash_ports;
pub mod zip_ports;
pub mod zip_ports;
+12 -12
View File
@@ -1,8 +1,8 @@
use std::path::PathBuf;
use async_trait::async_trait;
use std::path::PathBuf;
use crate::domain::services::path_service::StoragePath;
use crate::common::errors::DomainError;
use crate::domain::services::path_service::StoragePath;
// Re-export domain repository traits for backward compatibility
pub use crate::domain::repositories::folder_repository::FolderRepository;
@@ -14,13 +14,13 @@ use super::storage_ports::{FileReadPort, FileWritePort};
pub trait StoragePort: Send + Sync + 'static {
/// Resolves a domain path to a physical path
fn resolve_path(&self, storage_path: &StoragePath) -> PathBuf;
/// Creates directories if they don't exist
async fn ensure_directory(&self, storage_path: &StoragePath) -> Result<(), DomainError>;
/// Checks if a file exists at the given path
async fn file_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
/// Checks if a directory exists at the given path
async fn directory_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
}
@@ -54,28 +54,28 @@ impl<T: FolderRepository> FolderStoragePort for T {}
pub trait IdMappingPort: Send + Sync + 'static {
/// Gets or creates an ID for a path
async fn get_or_create_id(&self, path: &StoragePath) -> Result<String, DomainError>;
/// Gets a path by its ID
async fn get_path_by_id(&self, id: &str) -> Result<StoragePath, DomainError>;
/// Updates the path for an existing ID
async fn update_path(&self, id: &str, new_path: &StoragePath) -> Result<(), DomainError>;
/// Removes an ID from the mapping
async fn remove_id(&self, id: &str) -> Result<(), DomainError>;
/// Saves pending changes
async fn save_changes(&self) -> Result<(), DomainError>;
/// Gets the file path as a PathBuf
async fn get_file_path(&self, file_id: &str) -> Result<PathBuf, DomainError> {
let storage_path = self.get_path_by_id(file_id).await?;
Ok(PathBuf::from(storage_path.to_string()))
}
/// Updates a file's path
async fn update_file_path(&self, file_id: &str, new_path: &PathBuf) -> Result<(), DomainError> {
let storage_path = StoragePath::from_string(new_path.to_string_lossy().as_ref());
self.update_path(file_id, &storage_path).await
}
}
}
+19 -9
View File
@@ -1,19 +1,29 @@
use async_trait::async_trait;
use crate::common::errors::Result;
use crate::application::dtos::recent_dto::RecentItemDto;
use crate::common::errors::Result;
use async_trait::async_trait;
/// Defines operations for managing user recent items
#[async_trait]
pub trait RecentItemsUseCase: Send + Sync {
/// Get all recent items for a user
async fn get_recent_items(&self, user_id: &str, limit: Option<i32>) -> Result<Vec<RecentItemDto>>;
async fn get_recent_items(
&self,
user_id: &str,
limit: Option<i32>,
) -> Result<Vec<RecentItemDto>>;
/// Record access to an item
async fn record_item_access(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<()>;
async fn record_item_access(&self, user_id: &str, item_id: &str, item_type: &str)
-> Result<()>;
/// Remove an item from recents
async fn remove_from_recent(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool>;
async fn remove_from_recent(
&self,
user_id: &str,
item_id: &str,
item_type: &str,
) -> Result<bool>;
/// Clear the entire recent items list
async fn clear_recent_items(&self, user_id: &str) -> Result<()>;
}
@@ -42,4 +52,4 @@ pub trait RecentItemsRepositoryPort: Send + Sync + 'static {
/// Removes items exceeding `max_items` (the oldest ones).
async fn prune(&self, user_id: &str, max_items: i32) -> Result<()>;
}
}
+35 -21
View File
@@ -3,13 +3,12 @@ use async_trait::async_trait;
use crate::{
application::dtos::{
pagination::PaginatedResponseDto,
share_dto::{CreateShareDto, ShareDto, UpdateShareDto}
share_dto::{CreateShareDto, ShareDto, UpdateShareDto},
},
common::errors::DomainError,
domain::entities::share::ShareItemType,
};
#[async_trait]
pub trait ShareUseCase: Send + Sync + 'static {
/// Create a new shared link for a file or folder
@@ -56,30 +55,45 @@ pub trait ShareUseCase: Send + Sync + 'static {
token: &str,
password: &str,
) -> Result<bool, DomainError>;
/// Register an access to a shared link
async fn register_shared_link_access(&self, token: &str) -> Result<(), DomainError>;
}
#[async_trait]
pub trait ShareStoragePort: Send + Sync + 'static {
async fn save_share(&self, share: &crate::domain::entities::share::Share)
-> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_share_by_id(&self, id: &str)
-> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_share_by_token(&self, token: &str)
-> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_shares_by_item(&self, item_id: &str, item_type: &ShareItemType)
-> Result<Vec<crate::domain::entities::share::Share>, DomainError>;
async fn update_share(&self, share: &crate::domain::entities::share::Share)
-> Result<crate::domain::entities::share::Share, DomainError>;
async fn save_share(
&self,
share: &crate::domain::entities::share::Share,
) -> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_share_by_id(
&self,
id: &str,
) -> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_share_by_token(
&self,
token: &str,
) -> Result<crate::domain::entities::share::Share, DomainError>;
async fn find_shares_by_item(
&self,
item_id: &str,
item_type: &ShareItemType,
) -> Result<Vec<crate::domain::entities::share::Share>, DomainError>;
async fn update_share(
&self,
share: &crate::domain::entities::share::Share,
) -> Result<crate::domain::entities::share::Share, DomainError>;
async fn delete_share(&self, id: &str) -> Result<(), DomainError>;
async fn find_shares_by_user(&self, user_id: &str, offset: usize, limit: usize)
-> Result<(Vec<crate::domain::entities::share::Share>, usize), DomainError>;
async fn find_shares_by_user(
&self,
user_id: &str,
offset: usize,
limit: usize,
) -> Result<(Vec<crate::domain::entities::share::Share>, usize), DomainError>;
}
+14 -11
View File
@@ -1,16 +1,18 @@
use std::path::PathBuf;
use async_trait::async_trait;
use bytes::Bytes;
use futures::Stream;
use serde_json::Value;
use std::path::PathBuf;
use crate::common::errors::DomainError;
use crate::domain::entities::file::File;
use crate::domain::services::path_service::StoragePath;
use crate::common::errors::DomainError;
// Re-export domain repository traits for backward compatibility.
// The canonical definitions now live in domain/repositories/.
pub use crate::domain::repositories::file_repository::{FileReadRepository, FileWriteRepository, FileRepository};
pub use crate::domain::repositories::file_repository::{
FileReadRepository, FileRepository, FileWriteRepository,
};
pub use crate::domain::repositories::folder_repository::FolderRepository;
// ─────────────────────────────────────────────────────
@@ -92,17 +94,14 @@ pub trait FileWritePort: Send + Sync + 'static {
) -> Result<File, DomainError>;
/// Renames a file (same folder, different name).
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) -> Result<File, DomainError>;
/// Deletes a file.
async fn delete_file(&self, id: &str) -> Result<(), DomainError>;
/// Updates the content of an existing file.
async fn update_file_content(&self, file_id: &str, content: Vec<u8>) -> Result<(), DomainError>;
async fn update_file_content(&self, file_id: &str, content: Vec<u8>)
-> Result<(), DomainError>;
/// Registers file metadata WITHOUT writing content to disk (write-behind).
///
@@ -122,7 +121,11 @@ pub trait FileWritePort: Send + Sync + 'static {
async fn move_to_trash(&self, file_id: &str) -> Result<(), DomainError>;
/// Restores a file from the trash to its original location
async fn restore_from_trash(&self, file_id: &str, original_path: &str) -> Result<(), DomainError>;
async fn restore_from_trash(
&self,
file_id: &str,
original_path: &str,
) -> Result<(), DomainError>;
/// Permanently deletes a file (used by the trash)
async fn delete_file_permanently(&self, file_id: &str) -> Result<(), DomainError>;
@@ -174,4 +177,4 @@ pub trait StorageUsagePort: Send + Sync + 'static {
pub trait StorageUseCase: Send + Sync + 'static {
/// Handle a request with the specified action and parameters
async fn handle_request(&self, action: &str, params: Value) -> Result<Value, DomainError>;
}
}
+9 -9
View File
@@ -4,11 +4,11 @@
//! keeping the application and interface layers independent of specific
//! image processing implementations.
use std::path::{Path, PathBuf};
use std::sync::Arc;
use crate::common::errors::DomainError;
use async_trait::async_trait;
use bytes::Bytes;
use crate::common::errors::DomainError;
use std::path::{Path, PathBuf};
use std::sync::Arc;
/// Thumbnail sizes supported by the system.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -42,7 +42,11 @@ impl ThumbnailSize {
/// Get all thumbnail sizes.
pub fn all() -> &'static [ThumbnailSize] {
&[ThumbnailSize::Icon, ThumbnailSize::Preview, ThumbnailSize::Large]
&[
ThumbnailSize::Icon,
ThumbnailSize::Preview,
ThumbnailSize::Large,
]
}
}
@@ -77,11 +81,7 @@ pub trait ThumbnailPort: Send + Sync + 'static {
/// Generate all thumbnail sizes for a file in the background.
///
/// Called after file upload to pre-generate thumbnails.
fn generate_all_sizes_background(
self: Arc<Self>,
file_id: String,
original_path: PathBuf,
);
fn generate_all_sizes_background(self: Arc<Self>, file_id: String, original_path: PathBuf);
/// Delete all thumbnails for a file.
async fn delete_thumbnails(&self, file_id: &str) -> Result<(), DomainError>;
+1 -1
View File
@@ -4,9 +4,9 @@
//! (e.g., JPEG/PNG → WebP), keeping the application and interface layers
//! independent of specific image processing implementations.
use crate::common::errors::DomainError;
use async_trait::async_trait;
use bytes::Bytes;
use crate::common::errors::DomainError;
/// Supported output formats for image transcoding.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+5 -5
View File
@@ -8,16 +8,16 @@ use crate::common::errors::Result;
pub trait TrashUseCase: Send + Sync {
/// List items in the user's trash
async fn get_trash_items(&self, user_id: &str) -> Result<Vec<TrashedItemDto>>;
/// Move a file or folder to trash
async fn move_to_trash(&self, item_id: &str, item_type: &str, user_id: &str) -> Result<()>;
/// Restore an item from trash to its original location
async fn restore_item(&self, trash_id: &str, user_id: &str) -> Result<()>;
/// Permanently delete an item from trash
async fn delete_permanently(&self, trash_id: &str, user_id: &str) -> Result<()>;
/// Empty the trash for a specific user
async fn empty_trash(&self, user_id: &str) -> Result<()>;
}
}
+1 -1
View File
@@ -4,8 +4,8 @@
//! keeping the interface layer independent of specific ZIP
//! implementation details.
use async_trait::async_trait;
use crate::common::errors::DomainError;
use async_trait::async_trait;
/// Port for ZIP archive operations.
///