adding features
This commit is contained in:
+16
-16
@@ -5,12 +5,12 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
## Phase 1: Basic File Functionalities
|
||||
|
||||
### Folder System
|
||||
- [ ] Implement API for creating folders
|
||||
- [ ] Add support for hierarchical paths in the backend
|
||||
- [x] Implement API for creating folders
|
||||
- [x] Add support for hierarchical paths in the backend
|
||||
- [ ] Update UI to show folder structure (tree)
|
||||
- [ ] Implement navigation between folders
|
||||
- [ ] Add functionality to rename folders
|
||||
- [ ] Add option to move files between folders
|
||||
- [x] Implement navigation between folders
|
||||
- [x] Add functionality to rename folders
|
||||
- [x] Add option to move files between folders
|
||||
|
||||
### File Preview
|
||||
- [ ] Implement integrated image viewer
|
||||
@@ -31,7 +31,7 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Improve responsive design for mobile devices
|
||||
- [ ] Implement drag & drop between folders
|
||||
- [ ] Add support for multiple file selection
|
||||
- [ ] Implement multiple file uploads
|
||||
- [x] Implement multiple file uploads
|
||||
- [ ] Add progress indicators for long operations
|
||||
- [ ] Implement UI notifications for events
|
||||
|
||||
@@ -53,9 +53,9 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
- [ ] Add storage usage monitoring
|
||||
|
||||
### Basic Security
|
||||
- [ ] Implement secure password hashing with Argon2
|
||||
- [ ] Add session management
|
||||
- [ ] Implement JWT authentication token
|
||||
- [x] Implement secure password hashing with Argon2
|
||||
- [x] Add session management
|
||||
- [x] Implement JWT authentication token
|
||||
- [ ] Add CSRF protection
|
||||
- [ ] Implement login attempt limits
|
||||
- [ ] Create activity logging system
|
||||
@@ -90,8 +90,8 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
|
||||
### Complete REST API
|
||||
- [ ] Design OpenAPI specification
|
||||
- [ ] Implement endpoints for file operations
|
||||
- [ ] Add endpoints for users and authentication
|
||||
- [x] Implement endpoints for file operations
|
||||
- [x] Add endpoints for users and authentication
|
||||
- [ ] Implement automatic documentation (Swagger)
|
||||
- [ ] Create API token system
|
||||
- [ ] Implement rate limiting
|
||||
@@ -141,8 +141,8 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
### Backend
|
||||
- [x] Implement file cache with Rust
|
||||
- [x] Enable Link Time Optimization (LTO) for better performance
|
||||
- [ ] Optimize large file transmission
|
||||
- [ ] Add adaptive compression by file type
|
||||
- [x] Optimize large file transmission
|
||||
- [x] Add adaptive compression by file type
|
||||
- [x] Implement asynchronous processing for heavy tasks
|
||||
- [ ] Optimize database queries
|
||||
- [ ] Implement scaling strategies
|
||||
@@ -158,16 +158,16 @@ This document contains the task list for the development of OxiCloud, a minimali
|
||||
### Storage
|
||||
- [ ] Research deduplication options
|
||||
- [ ] Implement block storage
|
||||
- [ ] Add transparent compression by file type
|
||||
- [x] Add transparent compression by file type
|
||||
- [ ] Implement log rotation and archiving
|
||||
- [ ] Create automated backup system
|
||||
- [ ] Add support for distributed storage
|
||||
|
||||
## Infrastructure and Deployment
|
||||
|
||||
- [ ] Create Docker configuration
|
||||
- [x] Create Docker configuration
|
||||
- [ ] Implement CI/CD with GitHub Actions
|
||||
- [ ] Add automated tests
|
||||
- [x] Add automated tests
|
||||
- [ ] Create installation documentation
|
||||
- [ ] Implement monitoring and alerts
|
||||
- [ ] Add automatic update system
|
||||
@@ -10,25 +10,41 @@ use crate::common::errors::DomainError;
|
||||
use futures::Stream;
|
||||
use bytes::Bytes;
|
||||
|
||||
/// Errores específicos del servicio de archivos
|
||||
/**
|
||||
* File service-specific error types.
|
||||
*
|
||||
* This enum represents the application-level errors that can occur during file operations,
|
||||
* providing a translation layer between domain/infrastructure errors and application errors.
|
||||
*/
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FileServiceError {
|
||||
/// Returned when a requested file cannot be found
|
||||
#[error("Archivo no encontrado: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
/// Returned when a file operation conflicts with existing files
|
||||
#[error("Archivo ya existe: {0}")]
|
||||
Conflict(String),
|
||||
|
||||
/// Returned when file access fails due to permissions or I/O issues
|
||||
#[error("Error de acceso al archivo: {0}")]
|
||||
AccessError(String),
|
||||
|
||||
/// Returned when a file path is invalid
|
||||
#[error("Ruta de archivo inválida: {0}")]
|
||||
InvalidPath(String),
|
||||
|
||||
/// Generic internal error for unexpected failures
|
||||
#[error("Error interno: {0}")]
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts repository errors to service errors.
|
||||
*
|
||||
* This implementation maps low-level repository errors to more
|
||||
* application-appropriate error types, abstracting away the implementation details.
|
||||
*/
|
||||
impl From<FileRepositoryError> for FileServiceError {
|
||||
fn from(err: FileRepositoryError) -> Self {
|
||||
match err {
|
||||
@@ -42,6 +58,12 @@ impl From<FileRepositoryError> for FileServiceError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts domain errors to service errors.
|
||||
*
|
||||
* This implementation ensures that general domain errors are properly translated
|
||||
* to file service-specific errors while preserving their semantic meaning.
|
||||
*/
|
||||
impl From<DomainError> for FileServiceError {
|
||||
fn from(err: DomainError) -> Self {
|
||||
match err.kind {
|
||||
@@ -54,6 +76,12 @@ impl From<DomainError> for FileServiceError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts service errors to domain errors.
|
||||
*
|
||||
* This implementation allows service errors to be propagated up the call stack as
|
||||
* domain errors when crossing architectural boundaries.
|
||||
*/
|
||||
impl From<FileServiceError> for DomainError {
|
||||
fn from(err: FileServiceError) -> Self {
|
||||
match err {
|
||||
@@ -66,10 +94,23 @@ impl From<FileServiceError> for DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type alias for results of file service operations.
|
||||
*
|
||||
* Provides a convenient way to return either a successful value or a FileServiceError.
|
||||
*/
|
||||
pub type FileServiceResult<T> = Result<T, FileServiceError>;
|
||||
|
||||
/// Service for file operations
|
||||
/**
|
||||
* Service component for file operations in the application layer.
|
||||
*
|
||||
* The FileService implements the application use cases related to files by orchestrating
|
||||
* domain logic and infrastructure components. It acts as an adapter between the inbound
|
||||
* ports (interfaces) and outbound ports (repositories), translating between DTOs and
|
||||
* domain entities.
|
||||
*/
|
||||
pub struct FileService {
|
||||
/// Repository responsible for file storage operations
|
||||
file_repository: Arc<dyn FileStoragePort>,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,30 @@ use crate::domain::repositories::file_repository::FileRepository;
|
||||
use crate::domain::repositories::folder_repository::FolderRepository;
|
||||
use crate::domain::repositories::trash_repository::TrashRepository;
|
||||
|
||||
/// Servicio de aplicación para operaciones de papelera
|
||||
/**
|
||||
* Application service for trash operations.
|
||||
*
|
||||
* The TrashService implements the trash management functionality in the application layer,
|
||||
* handling movement of files and folders to trash, restoration from trash, and permanent
|
||||
* deletion. It orchestrates interactions between the domain entities and infrastructure
|
||||
* repositories while enforcing business rules like retention policies.
|
||||
*
|
||||
* This service follows the Clean Architecture pattern by:
|
||||
* - Depending on domain interfaces rather than concrete implementations
|
||||
* - Orchestrating domain operations without containing domain logic
|
||||
* - Exposing its functionality through the TrashUseCase port
|
||||
*/
|
||||
pub struct TrashService {
|
||||
/// Repository for trash-specific operations like listing and retrieving trashed items
|
||||
trash_repository: Arc<dyn TrashRepository>,
|
||||
|
||||
/// Repository for file operations used when trashing, restoring, or deleting files
|
||||
file_repository: Arc<dyn FileRepository>,
|
||||
|
||||
/// Repository for folder operations used when trashing, restoring, or deleting folders
|
||||
folder_repository: Arc<dyn FolderRepository>,
|
||||
|
||||
/// Number of days items should be kept in trash before automatic cleanup
|
||||
retention_days: u32,
|
||||
}
|
||||
|
||||
|
||||
+31
-11
@@ -1,50 +1,70 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::domain::services::path_service::StoragePath;
|
||||
|
||||
/// Error en la creación o manipulación de entidades de archivo
|
||||
/**
|
||||
* Represents errors that can occur during file entity operations.
|
||||
*
|
||||
* This enum encapsulates various error conditions that may arise when creating,
|
||||
* validating, or manipulating file entities in the domain model.
|
||||
*/
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FileError {
|
||||
/// Occurs when a file name contains invalid characters or is empty.
|
||||
#[error("Nombre de archivo inválido: {0}")]
|
||||
InvalidFileName(String),
|
||||
|
||||
/// Occurs when validation fails for any file entity attribute.
|
||||
#[error("Error en la validación: {0}")]
|
||||
#[allow(dead_code)]
|
||||
ValidationError(String),
|
||||
}
|
||||
|
||||
/// Tipo de resultado para operaciones con entidades de archivo
|
||||
/**
|
||||
* Type alias for results of file entity operations.
|
||||
*
|
||||
* Provides a convenient way to return either a successful value or a FileError.
|
||||
*/
|
||||
pub type FileResult<T> = Result<T, FileError>;
|
||||
|
||||
/// Represents a file entity in the domain
|
||||
/**
|
||||
* Represents a file in the system's domain model.
|
||||
*
|
||||
* The File entity is a core domain object that encapsulates all properties and behaviors
|
||||
* of a file in the system. It implements an immutable design pattern where modification
|
||||
* operations return new instances rather than modifying the existing one.
|
||||
*
|
||||
* This entity maintains both physical storage information and logical metadata about files,
|
||||
* serving as the bridge between the storage system and the application.
|
||||
*/
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct File {
|
||||
/// Unique identifier for the file
|
||||
/// Unique identifier for the file - used throughout the system for file operations
|
||||
id: String,
|
||||
|
||||
/// Name of the file
|
||||
/// Name of the file including extension
|
||||
name: String,
|
||||
|
||||
/// Path to the file in the domain model
|
||||
/// Path to the file in the domain model - not serialized as it contains internal representation
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
storage_path: StoragePath,
|
||||
|
||||
/// String representation of the path (for serialization compatibility)
|
||||
/// String representation of the path for serialization and API compatibility
|
||||
#[serde(rename = "path")]
|
||||
path_string: String,
|
||||
|
||||
/// Size of the file in bytes
|
||||
size: u64,
|
||||
|
||||
/// MIME type of the file
|
||||
/// MIME type of the file (e.g., "text/plain", "image/jpeg")
|
||||
mime_type: String,
|
||||
|
||||
/// Parent folder ID
|
||||
/// Parent folder ID if the file is within a folder, None if in root
|
||||
folder_id: Option<String>,
|
||||
|
||||
/// Creation timestamp
|
||||
/// Creation timestamp (seconds since UNIX epoch)
|
||||
created_at: u64,
|
||||
|
||||
/// Last modification timestamp
|
||||
/// Last modification timestamp (seconds since UNIX epoch)
|
||||
modified_at: u64,
|
||||
}
|
||||
|
||||
|
||||
@@ -5,50 +5,89 @@ use crate::common::errors::DomainError;
|
||||
use futures::Stream;
|
||||
use bytes::Bytes;
|
||||
|
||||
/// Error types for file repository operations
|
||||
/**
|
||||
* Comprehensive error types for file repository operations.
|
||||
*
|
||||
* This enum represents all possible error conditions that can occur during file repository
|
||||
* operations, providing detailed context for error handling across the application.
|
||||
*/
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(dead_code)]
|
||||
pub enum FileRepositoryError {
|
||||
/// Returned when a requested file cannot be found by ID or path
|
||||
#[error("File not found: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
/// Returned when attempting to create a file at a location where one already exists
|
||||
#[error("File already exists: {0}")]
|
||||
AlreadyExists(String),
|
||||
|
||||
/// Returned when a provided file path is invalid or malformed
|
||||
#[error("Invalid file path: {0}")]
|
||||
InvalidPath(String),
|
||||
|
||||
/// Returned when an operation is not supported by the current implementation
|
||||
#[error("Operation not supported: {0}")]
|
||||
OperationNotSupported(String),
|
||||
|
||||
/// Wraps standard I/O errors from the filesystem
|
||||
#[error("IO Error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
/// Indicates errors in the path-to-ID mapping system
|
||||
#[error("Mapping error: {0}")]
|
||||
MappingError(String),
|
||||
|
||||
/// Specific errors related to ID mapping operations
|
||||
#[error("ID Mapping error: {0}")]
|
||||
IdMappingError(String),
|
||||
|
||||
/// Returned when an operation exceeds its timeout threshold
|
||||
#[error("Timeout error: {0}")]
|
||||
Timeout(String),
|
||||
|
||||
/// Propagates domain model errors to the repository layer
|
||||
#[error("Domain error: {0}")]
|
||||
DomainError(#[from] DomainError),
|
||||
|
||||
/// Catch-all for other unspecified errors
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Result type for file repository operations
|
||||
/**
|
||||
* Type alias for results of file repository operations.
|
||||
*
|
||||
* Provides a consistent return type for all repository methods, containing
|
||||
* either a successful value or a FileRepositoryError.
|
||||
*/
|
||||
pub type FileRepositoryResult<T> = Result<T, FileRepositoryError>;
|
||||
|
||||
/// Repository interface for file operations (primary port)
|
||||
/// Esta interfaz define las operaciones de negocio relacionadas con archivos
|
||||
/// sin exponer detalles de implementación como rutas o sistemas de archivos
|
||||
/**
|
||||
* Repository interface defining all file storage operations.
|
||||
*
|
||||
* This trait represents the primary port for file operations in the domain model,
|
||||
* following the hexagonal architecture pattern. It defines the contract that any
|
||||
* file storage implementation must fulfill, abstracting away implementation details
|
||||
* like filesystem specifics, cloud storage, or database operations.
|
||||
*
|
||||
* All implementations must be thread-safe (Send + Sync) and have a 'static lifetime
|
||||
* to support the async operations in the system.
|
||||
*/
|
||||
#[async_trait]
|
||||
pub trait FileRepository: Send + Sync + 'static {
|
||||
/// Saves a file from bytes
|
||||
/**
|
||||
* Creates and saves a new file from binary content.
|
||||
*
|
||||
* This method handles new file creation with automatic ID generation,
|
||||
* content storage, and metadata registration.
|
||||
*
|
||||
* @param name The filename with extension
|
||||
* @param folder_id Optional ID of parent folder, None for root
|
||||
* @param content_type MIME type of the file
|
||||
* @param content Binary data of the file
|
||||
* @return A File entity with generated metadata on success, error otherwise
|
||||
*/
|
||||
async fn save_file_from_bytes(
|
||||
&self,
|
||||
name: String,
|
||||
@@ -57,7 +96,19 @@ pub trait FileRepository: Send + Sync + 'static {
|
||||
content: Vec<u8>,
|
||||
) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Saves a file with a specific ID
|
||||
/**
|
||||
* Saves a file with a predetermined ID.
|
||||
*
|
||||
* Similar to save_file_from_bytes but allows specifying the ID,
|
||||
* useful for restoring files or migrations.
|
||||
*
|
||||
* @param id Predefined unique ID for the file
|
||||
* @param name The filename with extension
|
||||
* @param folder_id Optional ID of parent folder, None for root
|
||||
* @param content_type MIME type of the file
|
||||
* @param content Binary data of the file
|
||||
* @return The created File entity on success, error otherwise
|
||||
*/
|
||||
#[allow(dead_code)]
|
||||
async fn save_file_with_id(
|
||||
&self,
|
||||
@@ -68,38 +119,109 @@ pub trait FileRepository: Send + Sync + 'static {
|
||||
content: Vec<u8>,
|
||||
) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Gets a file by its ID
|
||||
/**
|
||||
* Retrieves a file entity by its unique ID.
|
||||
*
|
||||
* @param id The unique identifier of the file
|
||||
* @return The File entity if found, NotFound error otherwise
|
||||
*/
|
||||
async fn get_file_by_id(&self, id: &str) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Lists files in a folder
|
||||
/**
|
||||
* Lists all files within a specified folder.
|
||||
*
|
||||
* @param folder_id Optional folder ID to list files from, None for root
|
||||
* @return Vector of File entities in the folder
|
||||
*/
|
||||
async fn list_files(&self, folder_id: Option<&str>) -> FileRepositoryResult<Vec<File>>;
|
||||
|
||||
/// Deletes a file
|
||||
/**
|
||||
* Deletes a file by ID.
|
||||
*
|
||||
* @param id The unique identifier of the file to delete
|
||||
* @return Success or error
|
||||
*/
|
||||
async fn delete_file(&self, id: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Deletes a file and its entry from mapping systems
|
||||
/**
|
||||
* Deletes a file and removes its mapping entries.
|
||||
*
|
||||
* More thorough than delete_file as it also purges ID mappings,
|
||||
* useful for permanent deletions.
|
||||
*
|
||||
* @param id The unique identifier of the file to delete
|
||||
* @return Success or error
|
||||
*/
|
||||
#[allow(dead_code)]
|
||||
async fn delete_file_entry(&self, id: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Gets file content as bytes - use only for small files
|
||||
/**
|
||||
* Retrieves the complete file content as a byte vector.
|
||||
*
|
||||
* This method loads the entire file into memory, so it should
|
||||
* only be used for reasonably sized files.
|
||||
*
|
||||
* @param id The unique identifier of the file
|
||||
* @return The file's binary content
|
||||
*/
|
||||
async fn get_file_content(&self, id: &str) -> FileRepositoryResult<Vec<u8>>;
|
||||
|
||||
/// Gets file content as a stream - better for large files
|
||||
/**
|
||||
* Retrieves file content as an asynchronous stream of bytes.
|
||||
*
|
||||
* Preferred for large files as it avoids loading everything into memory at once.
|
||||
*
|
||||
* @param id The unique identifier of the file
|
||||
* @return A stream that yields chunks of file data
|
||||
*/
|
||||
#[allow(clippy::type_complexity)]
|
||||
async fn get_file_stream(&self, id: &str) -> FileRepositoryResult<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>>;
|
||||
|
||||
/// Moves a file to a different folder
|
||||
/**
|
||||
* Moves a file to a different folder.
|
||||
*
|
||||
* @param id The unique identifier of the file to move
|
||||
* @param target_folder_id The destination folder ID, None for root
|
||||
* @return The updated File entity after the move
|
||||
*/
|
||||
async fn move_file(&self, id: &str, target_folder_id: Option<String>) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Gets the storage path for a file
|
||||
/**
|
||||
* Retrieves the storage path for a file.
|
||||
*
|
||||
* @param id The unique identifier of the file
|
||||
* @return The StoragePath object representing the file's location
|
||||
*/
|
||||
async fn get_file_path(&self, id: &str) -> FileRepositoryResult<StoragePath>;
|
||||
|
||||
/// Moves a file to trash
|
||||
/**
|
||||
* Moves a file to the trash system.
|
||||
*
|
||||
* Instead of permanent deletion, this marks the file as trashed
|
||||
* and relocates it to the trash storage area.
|
||||
*
|
||||
* @param file_id The unique identifier of the file to trash
|
||||
* @return Success or error
|
||||
*/
|
||||
async fn move_to_trash(&self, file_id: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Restores a file from trash
|
||||
/**
|
||||
* Restores a file from the trash to its original location.
|
||||
*
|
||||
* @param file_id The unique identifier of the file to restore
|
||||
* @param original_path The original path where the file was located before trashing
|
||||
* @return Success or error
|
||||
*/
|
||||
async fn restore_from_trash(&self, file_id: &str, original_path: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Permanently deletes a file (used for trash cleanup)
|
||||
/**
|
||||
* Permanently deletes a file from the trash system.
|
||||
*
|
||||
* This operation is not reversible and removes the file completely.
|
||||
* Used primarily by the trash cleanup service.
|
||||
*
|
||||
* @param file_id The unique identifier of the file to permanently delete
|
||||
* @return Success or error
|
||||
*/
|
||||
async fn delete_file_permanently(&self, file_id: &str) -> FileRepositoryResult<()>;
|
||||
}
|
||||
@@ -6,39 +6,78 @@ use chrono::Utc;
|
||||
use crate::domain::entities::user::User;
|
||||
use crate::common::errors::{DomainError, ErrorKind};
|
||||
|
||||
// Reclamaciones JWT
|
||||
/**
|
||||
* JWT claims structure for authentication tokens.
|
||||
*
|
||||
* This structure represents the payload of JWT tokens used for authentication
|
||||
* in the system. It contains all the necessary claims to identify users and
|
||||
* manage token lifecycle.
|
||||
*/
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct TokenClaims {
|
||||
pub sub: String, // user ID
|
||||
pub exp: i64, // expiration timestamp
|
||||
pub iat: i64, // issued at timestamp
|
||||
pub jti: String, // JWT ID
|
||||
pub username: String, // username
|
||||
pub email: String, // email
|
||||
pub role: String, // role as string
|
||||
/// Subject identifier - contains the user ID
|
||||
pub sub: String,
|
||||
|
||||
/// Expiration timestamp (seconds since Unix epoch)
|
||||
pub exp: i64,
|
||||
|
||||
/// Issued at timestamp (seconds since Unix epoch)
|
||||
pub iat: i64,
|
||||
|
||||
/// JWT unique ID for token tracking and revocation
|
||||
pub jti: String,
|
||||
|
||||
/// Username for display and identification purposes
|
||||
pub username: String,
|
||||
|
||||
/// User email for communication and identification
|
||||
pub email: String,
|
||||
|
||||
/// User role for authorization checks
|
||||
pub role: String,
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication-specific error types.
|
||||
*
|
||||
* This enum encapsulates all error scenarios that can occur during
|
||||
* authentication and authorization processes, providing clear error messages
|
||||
* and categorization for proper handling.
|
||||
*/
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AuthError {
|
||||
/// Returned when username/password authentication fails
|
||||
#[error("Credenciales inválidas")]
|
||||
InvalidCredentials,
|
||||
|
||||
/// Returned when a JWT token has passed its expiration time
|
||||
#[error("Token expirado")]
|
||||
TokenExpired,
|
||||
|
||||
/// Returned when a JWT token is malformed or has invalid signature
|
||||
#[error("Token inválido: {0}")]
|
||||
InvalidToken(String),
|
||||
|
||||
/// Returned when a user attempts to access a resource they don't have permission for
|
||||
#[error("Acceso denegado: {0}")]
|
||||
AccessDenied(String),
|
||||
|
||||
/// Returned when a requested operation is not allowed for the user
|
||||
#[error("Operación no permitida: {0}")]
|
||||
OperationNotAllowed(String),
|
||||
|
||||
/// Returned for unexpected errors in the authentication system
|
||||
#[error("Error interno: {0}")]
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion from AuthError to DomainError.
|
||||
*
|
||||
* This implementation allows authentication errors to be seamlessly
|
||||
* transformed into domain errors, making error handling more consistent
|
||||
* throughout the application.
|
||||
*/
|
||||
impl From<AuthError> for DomainError {
|
||||
fn from(err: AuthError) -> Self {
|
||||
match err {
|
||||
@@ -64,10 +103,22 @@ impl From<AuthError> for DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication service for managing user sessions and authorization.
|
||||
*
|
||||
* This service provides the core authentication functionality for the system,
|
||||
* including JWT token generation and validation, refresh token management,
|
||||
* and session duration control.
|
||||
*/
|
||||
pub struct AuthService {
|
||||
/// Secret key used for signing JWT tokens
|
||||
jwt_secret: String,
|
||||
access_token_expiry: i64, // segundos
|
||||
refresh_token_expiry: i64, // segundos
|
||||
|
||||
/// Expiration time for access tokens in seconds
|
||||
access_token_expiry: i64,
|
||||
|
||||
/// Expiration time for refresh tokens in seconds
|
||||
refresh_token_expiry: i64,
|
||||
}
|
||||
|
||||
impl AuthService {
|
||||
|
||||
@@ -26,6 +26,25 @@ use crate::common::config::AppConfig;
|
||||
use crate::application::ports::outbound::FileStoragePort;
|
||||
use crate::infrastructure::repositories::parallel_file_processor::ParallelFileProcessor;
|
||||
|
||||
/**
|
||||
* Filesystem implementation of the File Repository interface.
|
||||
*
|
||||
* This repository provides a concrete implementation of the FileRepository domain interface
|
||||
* that interacts with a filesystem-based storage backend. It implements:
|
||||
*
|
||||
* 1. File creation, retrieval, and deletion operations
|
||||
* 2. File content reading (both in-memory and streaming)
|
||||
* 3. Folder organization for files
|
||||
* 4. ID-to-path mapping persistence
|
||||
* 5. Optimized handling of large files using parallel I/O
|
||||
* 6. Metadata caching to reduce filesystem operations
|
||||
* 7. Trash operations for file lifecycle management
|
||||
*
|
||||
* The implementation follows the hexagonal architecture pattern as a secondary adapter,
|
||||
* implementing domain interfaces and ports while isolating the application core from
|
||||
* filesystem-specific details.
|
||||
*/
|
||||
|
||||
// Usar constantes de la configuración centralizada en lugar de valores fijos
|
||||
// Esto se reemplaza con self.config.concurrency.max_concurrent_files más adelante
|
||||
|
||||
|
||||
@@ -18,10 +18,32 @@ use crate::infrastructure::services::compression_service::{
|
||||
};
|
||||
use crate::common::di::AppState;
|
||||
|
||||
/**
|
||||
* Type aliases for dependency injection state.
|
||||
* These aliases improve code readability when working with service dependencies.
|
||||
*/
|
||||
/// State containing the file service for dependency injection
|
||||
type FileServiceState = Arc<FileService>;
|
||||
/// Global application state for dependency injection
|
||||
type GlobalState = AppState;
|
||||
|
||||
/// Handler for file-related API endpoints
|
||||
/**
|
||||
* API handler for file-related operations.
|
||||
*
|
||||
* The FileHandler is responsible for processing HTTP requests related to file operations.
|
||||
* It handles:
|
||||
*
|
||||
* 1. File uploads through multipart form data
|
||||
* 2. File downloads with optional compression
|
||||
* 3. Listing files in folders
|
||||
* 4. Moving files between folders
|
||||
* 5. Deleting files (with trash integration)
|
||||
*
|
||||
* This component acts as an adapter in the hexagonal architecture, translating
|
||||
* between HTTP requests/responses and application service calls. It handles
|
||||
* HTTP-specific concerns like status codes, headers, and request parsing while
|
||||
* delegating business logic to the application services.
|
||||
*/
|
||||
pub struct FileHandler;
|
||||
|
||||
// Simpler approach to make streams Unpin - use Pin<Box<dyn Stream>> directly
|
||||
|
||||
+31
@@ -6,10 +6,41 @@ use axum::Router;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
/**
|
||||
* OxiCloud - Cloud Storage Platform
|
||||
*
|
||||
* OxiCloud is a NextCloud-like file storage system built in Rust with a focus on
|
||||
* performance, security, and clean architecture. The system provides:
|
||||
*
|
||||
* - File and folder management with rich metadata
|
||||
* - User authentication and authorization
|
||||
* - File trash system with automatic cleanup
|
||||
* - Efficient handling of large files through parallel processing
|
||||
* - Compression capabilities for bandwidth optimization
|
||||
* - RESTful API and web interface
|
||||
*
|
||||
* The architecture follows the Clean/Hexagonal Architecture pattern with:
|
||||
*
|
||||
* - Domain Layer: Core business entities and repository interfaces (domain/*)
|
||||
* - Application Layer: Use cases and service orchestration (application/*)
|
||||
* - Infrastructure Layer: Technical implementations of repositories (infrastructure/*)
|
||||
* - Interface Layer: API endpoints and web controllers (interfaces/*)
|
||||
*
|
||||
* Dependencies are managed through dependency inversion, with high-level modules
|
||||
* defining interfaces (ports) that low-level modules implement (adapters).
|
||||
*
|
||||
* @author OxiCloud Development Team
|
||||
*/
|
||||
|
||||
/// Common utilities, configuration, and error handling
|
||||
mod common;
|
||||
/// Core domain model, entities, and business rules
|
||||
mod domain;
|
||||
/// Application services, use cases, and DTOs
|
||||
mod application;
|
||||
/// Technical implementations of repositories and services
|
||||
mod infrastructure;
|
||||
/// External interfaces like API endpoints and web controllers
|
||||
mod interfaces;
|
||||
|
||||
use application::services::folder_service::FolderService;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# OxiCloud Tests
|
||||
|
||||
This directory contains test scripts, utilities and troubleshooting tools for the OxiCloud project.
|
||||
|
||||
## API Tests
|
||||
|
||||
* `test-all-routes.py` - Tests all API routes to verify which ones are implemented
|
||||
* `test-api.sh` - Bash script to test basic API functionality (list, upload, download)
|
||||
* `test-api-integration.py` - Python-based integration tests for the API
|
||||
* `test-upload.py` - Dedicated upload testing script with more options
|
||||
* `test-upload.sh` - Simple shell script for testing file uploads
|
||||
* `test-delete-file.py` - Tests the file deletion functionality
|
||||
|
||||
## Folder Tests
|
||||
|
||||
* `test-folder.sh` - Tests folder API operations
|
||||
* `test-folder-simple.sh` - Simplified folder creation/listing tests
|
||||
* `test-create-folder.sh` - Specific test for folder creation
|
||||
* `test-folder.js` - JavaScript based folder tests
|
||||
|
||||
## Trash Tests
|
||||
|
||||
* `test-trash.sh` - Tests trash functionality
|
||||
* `test-trash-simple.sh` - Basic trash functionality test
|
||||
* `test-trash-api.py` - Python script for testing trash API
|
||||
* `test-trash-api-simple.py` - Simplified version of trash API tests
|
||||
* `test-trash-api.sh` - Bash scripts for trash API testing
|
||||
* `test-compile-trash.sh` - Tests compilation with trash feature enabled
|
||||
* `fix-trash-index.sh` - Utility to fix trash indexing issues
|
||||
* `check-trash-dirs.sh` - Checks trash directories structure
|
||||
* `debug-trash.py` - Debug tool for trash functionality
|
||||
* `run-trash-test.sh` - Runner for trash tests
|
||||
|
||||
## Authentication Tests
|
||||
|
||||
* `test-auth-api.sh` - Tests the authentication API endpoints
|
||||
* `test-auth-env.sh` - Tests authentication with environment variables
|
||||
|
||||
## Utilities
|
||||
|
||||
* `check-db.sh` - Database check utility
|
||||
* `simulate-id-mapping.py` - Simulates ID mapping for testing
|
||||
* `direct-upload-test.py` - Tests direct uploads bypassing certain layers
|
||||
|
||||
## Test Files
|
||||
|
||||
* `test-upload.txt` - Sample file for upload testing
|
||||
* `test-api-file.txt` - Sample file for API testing
|
||||
|
||||
## Running Tests
|
||||
|
||||
Most test scripts can be run directly from this directory. Many accept command-line arguments
|
||||
to customize their behavior. Check the script headers or run with `--help` for more information.
|
||||
|
||||
Basic usage examples:
|
||||
|
||||
```bash
|
||||
# Test API endpoints
|
||||
python test-all-routes.py
|
||||
|
||||
# Test file upload
|
||||
./test-upload.sh --file sample.txt
|
||||
|
||||
# Test trash API
|
||||
python test-trash-api.py
|
||||
|
||||
# Run folder tests
|
||||
./test-folder.sh
|
||||
```
|
||||
|
||||
Note that these tests expect a running OxiCloud server, typically on localhost:8086.
|
||||
Regular → Executable
@@ -72,7 +72,7 @@ for route in routes:
|
||||
|
||||
# Test POST upload
|
||||
print("\nTesting file upload...")
|
||||
with open("test-all-routes.py", "rb") as f:
|
||||
with open(__file__, "rb") as f: # Use __file__ to reference the current script regardless of location
|
||||
files = {"file": f}
|
||||
data = {"folder_id": "folder-storage:1"}
|
||||
test_route(f"{SERVER_URL}/api/files/upload", method="POST", data=data, files=files)
|
||||
Regular → Executable
Reference in New Issue
Block a user