chore: translate all Spanish comments and log messages to English
This commit is contained in:
@@ -14,7 +14,7 @@ use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::common::errors::{Result, DomainError, ErrorKind};
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::CalendarError;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ use chrono::{DateTime, Utc, Duration, TimeZone};
|
||||
|
||||
use crate::common::errors::{Result, DomainError, ErrorKind};
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::CalendarEventError;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
//! Errores puros de entidades de dominio
|
||||
//! Pure domain entity errors
|
||||
//!
|
||||
//! Este módulo define los errores específicos de las entidades de dominio
|
||||
//! sin dependencias de frameworks externos, siguiendo los principios de
|
||||
//! Clean Architecture.
|
||||
//! This module defines domain entity-specific errors
|
||||
//! without external framework dependencies, following
|
||||
//! Clean Architecture principles.
|
||||
//!
|
||||
//! Los errores implementan manualmente `std::error::Error` y `std::fmt::Display`
|
||||
//! para mantener el dominio libre de dependencias externas.
|
||||
//! Errors manually implement `std::error::Error` and `std::fmt::Display`
|
||||
//! to keep the domain free of external dependencies.
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
@@ -14,12 +14,12 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
// FILE ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades File
|
||||
/// Errors that can occur during File entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum FileError {
|
||||
/// Ocurre cuando el nombre de archivo contiene caracteres inválidos o está vacío
|
||||
/// Occurs when the file name contains invalid characters or is empty
|
||||
InvalidFileName(String),
|
||||
/// Ocurre cuando falla la validación de cualquier atributo de la entidad
|
||||
/// Occurs when validation of any entity attribute fails
|
||||
ValidationError(String),
|
||||
}
|
||||
|
||||
@@ -34,19 +34,19 @@ impl Display for FileError {
|
||||
|
||||
impl Error for FileError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades File
|
||||
/// Type alias for File entity operation results
|
||||
pub type FileResult<T> = Result<T, FileError>;
|
||||
|
||||
// ============================================================================
|
||||
// FOLDER ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades Folder
|
||||
/// Errors that can occur during Folder entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum FolderError {
|
||||
/// Ocurre cuando el nombre de carpeta contiene caracteres inválidos o está vacío
|
||||
/// Occurs when the folder name contains invalid characters or is empty
|
||||
InvalidFolderName(String),
|
||||
/// Ocurre cuando falla la validación de cualquier atributo de la entidad
|
||||
/// Occurs when validation of any entity attribute fails
|
||||
ValidationError(String),
|
||||
}
|
||||
|
||||
@@ -61,54 +61,54 @@ impl Display for FolderError {
|
||||
|
||||
impl Error for FolderError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades Folder
|
||||
/// Type alias for Folder entity operation results
|
||||
pub type FolderResult<T> = Result<T, FolderError>;
|
||||
|
||||
// ============================================================================
|
||||
// USER ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades User
|
||||
/// Errors that can occur during User entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum UserError {
|
||||
/// Nombre de usuario inválido
|
||||
/// Invalid username
|
||||
InvalidUsername(String),
|
||||
/// Contraseña inválida
|
||||
/// Invalid password
|
||||
InvalidPassword(String),
|
||||
/// Error de validación general
|
||||
/// General validation error
|
||||
ValidationError(String),
|
||||
/// Error de autenticación
|
||||
/// Authentication error
|
||||
AuthenticationError(String),
|
||||
}
|
||||
|
||||
impl Display for UserError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
match self {
|
||||
UserError::InvalidUsername(msg) => write!(f, "Username inválido: {}", msg),
|
||||
UserError::InvalidPassword(msg) => write!(f, "Password inválido: {}", msg),
|
||||
UserError::ValidationError(msg) => write!(f, "Error en la validación: {}", msg),
|
||||
UserError::AuthenticationError(msg) => write!(f, "Error en la autenticación: {}", msg),
|
||||
UserError::InvalidUsername(msg) => write!(f, "Invalid username: {}", msg),
|
||||
UserError::InvalidPassword(msg) => write!(f, "Invalid password: {}", msg),
|
||||
UserError::ValidationError(msg) => write!(f, "Validation error: {}", msg),
|
||||
UserError::AuthenticationError(msg) => write!(f, "Authentication error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for UserError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades User
|
||||
/// Type alias for User entity operation results
|
||||
pub type UserResult<T> = Result<T, UserError>;
|
||||
|
||||
// ============================================================================
|
||||
// SHARE ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades Share
|
||||
/// Errors that can occur during Share entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ShareError {
|
||||
/// Token de compartición inválido
|
||||
/// Invalid share token
|
||||
InvalidToken(String),
|
||||
/// Fecha de expiración inválida
|
||||
/// Invalid expiration date
|
||||
InvalidExpiration(String),
|
||||
/// Error de validación general
|
||||
/// General validation error
|
||||
ValidationError(String),
|
||||
}
|
||||
|
||||
@@ -124,21 +124,21 @@ impl Display for ShareError {
|
||||
|
||||
impl Error for ShareError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades Share
|
||||
/// Type alias for Share entity operation results
|
||||
pub type ShareResult<T> = Result<T, ShareError>;
|
||||
|
||||
// ============================================================================
|
||||
// CALENDAR ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades Calendar
|
||||
/// Errors that can occur during Calendar entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CalendarError {
|
||||
/// Nombre de calendario inválido
|
||||
/// Invalid calendar name
|
||||
InvalidName(String),
|
||||
/// Código de color inválido
|
||||
/// Invalid color code
|
||||
InvalidColor(String),
|
||||
/// ID de propietario inválido
|
||||
/// Invalid owner ID
|
||||
InvalidOwnerId(String),
|
||||
}
|
||||
|
||||
@@ -154,23 +154,23 @@ impl Display for CalendarError {
|
||||
|
||||
impl Error for CalendarError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades Calendar
|
||||
/// Type alias for Calendar entity operation results
|
||||
pub type CalendarResult<T> = Result<T, CalendarError>;
|
||||
|
||||
// ============================================================================
|
||||
// CALENDAR EVENT ERRORS
|
||||
// ============================================================================
|
||||
|
||||
/// Errores que pueden ocurrir durante operaciones con entidades CalendarEvent
|
||||
/// Errors that can occur during CalendarEvent entity operations
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CalendarEventError {
|
||||
/// Resumen/título de evento inválido
|
||||
/// Invalid event summary/title
|
||||
InvalidSummary(String),
|
||||
/// Fechas de evento inválidas
|
||||
/// Invalid event dates
|
||||
InvalidDates(String),
|
||||
/// Regla de recurrencia inválida
|
||||
/// Invalid recurrence rule
|
||||
InvalidRecurrence(String),
|
||||
/// Datos iCalendar inválidos
|
||||
/// Invalid iCalendar data
|
||||
InvalidICalData(String),
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ impl Display for CalendarEventError {
|
||||
|
||||
impl Error for CalendarEventError {}
|
||||
|
||||
/// Alias de tipo para resultados de operaciones con entidades CalendarEvent
|
||||
/// Type alias for CalendarEvent entity operation results
|
||||
pub type CalendarEventResult<T> = Result<T, CalendarEventError>;
|
||||
|
||||
// ============================================================================
|
||||
@@ -216,10 +216,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_user_error_display() {
|
||||
let err = UserError::InvalidUsername("".to_string());
|
||||
assert_eq!(err.to_string(), "Username inválido: ");
|
||||
assert_eq!(err.to_string(), "Invalid username: ");
|
||||
|
||||
let err = UserError::AuthenticationError("invalid credentials".to_string());
|
||||
assert_eq!(err.to_string(), "Error en la autenticación: invalid credentials");
|
||||
assert_eq!(err.to_string(), "Authentication error: invalid credentials");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::domain::services::path_service::StoragePath;
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::{FileError, FileResult};
|
||||
|
||||
/**
|
||||
@@ -366,6 +366,6 @@ mod tests {
|
||||
assert!(renamed.is_ok());
|
||||
let renamed = renamed.unwrap();
|
||||
assert_eq!(renamed.name(), "newname.txt");
|
||||
assert_eq!(renamed.id(), "123"); // El ID no cambia
|
||||
assert_eq!(renamed.id(), "123"); // The ID does not change
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::domain::services::path_service::StoragePath;
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::{FolderError, FolderResult};
|
||||
|
||||
/// Represents a folder entity in the domain
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use uuid::Uuid;
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::ShareError;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
||||
+12
-12
@@ -1,7 +1,7 @@
|
||||
use uuid::Uuid;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
// Re-exportar errores de entidad desde el módulo centralizado
|
||||
// Re-export entity errors from the centralized module
|
||||
pub use super::entity_errors::{UserError, UserResult};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -57,22 +57,22 @@ impl User {
|
||||
role: UserRole,
|
||||
storage_quota_bytes: i64,
|
||||
) -> UserResult<Self> {
|
||||
// Validaciones
|
||||
// Validations
|
||||
if username.is_empty() || username.len() < 3 || username.len() > 32 {
|
||||
return Err(UserError::InvalidUsername(format!(
|
||||
"Username debe tener entre 3 y 32 caracteres"
|
||||
"Username must be between 3 and 32 characters"
|
||||
)));
|
||||
}
|
||||
|
||||
if !email.contains('@') || email.len() < 5 {
|
||||
return Err(UserError::ValidationError(format!(
|
||||
"Email inválido"
|
||||
"Invalid email"
|
||||
)));
|
||||
}
|
||||
|
||||
if password_hash.is_empty() {
|
||||
return Err(UserError::InvalidPassword(format!(
|
||||
"Password hash no puede estar vacío"
|
||||
"Password hash cannot be empty"
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -106,12 +106,12 @@ impl User {
|
||||
) -> UserResult<Self> {
|
||||
if username.is_empty() || username.len() < 3 || username.len() > 32 {
|
||||
return Err(UserError::InvalidUsername(
|
||||
"Username debe tener entre 3 y 32 caracteres".to_string(),
|
||||
"Username must be between 3 and 32 characters".to_string(),
|
||||
));
|
||||
}
|
||||
if !email.contains('@') || email.len() < 5 {
|
||||
return Err(UserError::ValidationError(
|
||||
"Email inválido".to_string(),
|
||||
"Invalid email".to_string(),
|
||||
));
|
||||
}
|
||||
let now = Utc::now();
|
||||
@@ -132,7 +132,7 @@ impl User {
|
||||
})
|
||||
}
|
||||
|
||||
// Crear desde valores existentes (para reconstrucción desde BD)
|
||||
// Create from existing values (for reconstruction from DB)
|
||||
pub fn from_data(
|
||||
id: String,
|
||||
username: String,
|
||||
@@ -263,26 +263,26 @@ impl User {
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
// Actualizar uso de almacenamiento
|
||||
// Update storage usage
|
||||
pub fn update_storage_used(&mut self, storage_used_bytes: i64) {
|
||||
self.storage_used_bytes = storage_used_bytes;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
// Registrar login
|
||||
// Register login
|
||||
pub fn register_login(&mut self) {
|
||||
let now = Utc::now();
|
||||
self.last_login_at = Some(now);
|
||||
self.updated_at = now;
|
||||
}
|
||||
|
||||
// Desactivar usuario
|
||||
// Deactivate user
|
||||
pub fn deactivate(&mut self) {
|
||||
self.active = false;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
// Activar usuario
|
||||
// Activate user
|
||||
pub fn activate(&mut self) {
|
||||
self.active = true;
|
||||
self.updated_at = Utc::now();
|
||||
|
||||
+34
-34
@@ -1,35 +1,35 @@
|
||||
//! Errores del dominio
|
||||
//! Domain errors
|
||||
//!
|
||||
//! Este módulo contiene los tipos de error propios del dominio.
|
||||
//! DomainError es el error base que se usa en toda la capa de dominio.
|
||||
//! This module contains domain-specific error types.
|
||||
//! DomainError is the base error used throughout the domain layer.
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use std::error::Error as StdError;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Tipo Result común para el dominio con DomainError como error estándar
|
||||
/// Common Result type for the domain with DomainError as the standard error
|
||||
pub type Result<T> = std::result::Result<T, DomainError>;
|
||||
|
||||
/// Tipos de errores del dominio
|
||||
/// Domain error types
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ErrorKind {
|
||||
/// Entidad no encontrada
|
||||
/// Entity not found
|
||||
NotFound,
|
||||
/// Entidad ya existe
|
||||
/// Entity already exists
|
||||
AlreadyExists,
|
||||
/// Entrada inválida o validación fallida
|
||||
/// Invalid input or failed validation
|
||||
InvalidInput,
|
||||
/// Error de acceso o permisos
|
||||
/// Access or permissions error
|
||||
AccessDenied,
|
||||
/// Tiempo de espera agotado
|
||||
/// Timeout expired
|
||||
Timeout,
|
||||
/// Error interno del sistema
|
||||
/// Internal system error
|
||||
InternalError,
|
||||
/// Funcionalidad no implementada
|
||||
/// Functionality not implemented
|
||||
NotImplemented,
|
||||
/// Operación no soportada
|
||||
/// Unsupported operation
|
||||
UnsupportedOperation,
|
||||
/// Error de base de datos
|
||||
/// Database error
|
||||
DatabaseError,
|
||||
}
|
||||
|
||||
@@ -49,25 +49,25 @@ impl Display for ErrorKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error base de dominio que proporciona contexto detallado
|
||||
/// Base domain error that provides detailed context
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{kind}: {message}")]
|
||||
pub struct DomainError {
|
||||
/// Tipo de error
|
||||
/// Error type
|
||||
pub kind: ErrorKind,
|
||||
/// Tipo de entidad afectada (ej: "File", "Folder")
|
||||
/// Affected entity type (e.g.: "File", "Folder")
|
||||
pub entity_type: &'static str,
|
||||
/// Identificador de la entidad si está disponible
|
||||
/// Entity identifier if available
|
||||
pub entity_id: Option<String>,
|
||||
/// Mensaje descriptivo del error
|
||||
/// Descriptive error message
|
||||
pub message: String,
|
||||
/// Error fuente (opcional)
|
||||
/// Source error (optional)
|
||||
#[source]
|
||||
pub source: Option<Box<dyn StdError + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl DomainError {
|
||||
/// Crea un nuevo error de dominio
|
||||
/// Creates a new domain error
|
||||
pub fn new<S: Into<String>>(
|
||||
kind: ErrorKind,
|
||||
entity_type: &'static str,
|
||||
@@ -82,7 +82,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de entidad no encontrada
|
||||
/// Creates an entity not found error
|
||||
pub fn not_found<S: Into<String>>(entity_type: &'static str, entity_id: S) -> Self {
|
||||
let id = entity_id.into();
|
||||
Self {
|
||||
@@ -94,7 +94,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de entidad ya existente
|
||||
/// Creates an entity already exists error
|
||||
pub fn already_exists<S: Into<String>>(entity_type: &'static str, entity_id: S) -> Self {
|
||||
let id = entity_id.into();
|
||||
Self {
|
||||
@@ -106,7 +106,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error para operaciones no soportadas
|
||||
/// Creates an error for unsupported operations
|
||||
pub fn operation_not_supported<S: Into<String>>(entity_type: &'static str, message: S) -> Self {
|
||||
Self::new(
|
||||
ErrorKind::UnsupportedOperation,
|
||||
@@ -115,7 +115,7 @@ impl DomainError {
|
||||
)
|
||||
}
|
||||
|
||||
/// Crea un error de tiempo agotado
|
||||
/// Creates a timeout error
|
||||
pub fn timeout<S: Into<String>>(entity_type: &'static str, message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::Timeout,
|
||||
@@ -126,7 +126,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error interno
|
||||
/// Creates an internal error
|
||||
pub fn internal_error<S: Into<String>>(entity_type: &'static str, message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::InternalError,
|
||||
@@ -137,7 +137,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de acceso denegado
|
||||
/// Creates an access denied error
|
||||
pub fn access_denied<S: Into<String>>(entity_type: &'static str, message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::AccessDenied,
|
||||
@@ -159,7 +159,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de base de datos
|
||||
/// Creates a database error
|
||||
pub fn database_error<S: Into<String>>(message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::DatabaseError,
|
||||
@@ -170,7 +170,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de validación
|
||||
/// Creates a validation error
|
||||
pub fn validation_error<S: Into<String>>(message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::InvalidInput,
|
||||
@@ -181,7 +181,7 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Crea un error de funcionalidad no implementada
|
||||
/// Creates a not implemented error
|
||||
pub fn not_implemented<S: Into<String>>(entity_type: &'static str, message: S) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::NotImplemented,
|
||||
@@ -192,20 +192,20 @@ impl DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Establece el ID de la entidad
|
||||
/// Sets the entity ID
|
||||
pub fn with_id<S: Into<String>>(mut self, entity_id: S) -> Self {
|
||||
self.entity_id = Some(entity_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el error fuente
|
||||
/// Sets the source error
|
||||
pub fn with_source<E: StdError + Send + Sync + 'static>(mut self, source: E) -> Self {
|
||||
self.source = Some(Box::new(source));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait para añadir contexto a los errores
|
||||
/// Trait for adding context to errors
|
||||
pub trait ErrorContext<T, E> {
|
||||
fn with_context<C, F>(self, context: F) -> std::result::Result<T, DomainError>
|
||||
where
|
||||
@@ -245,7 +245,7 @@ impl<T, E: StdError + Send + Sync + 'static> ErrorContext<T, E> for std::result:
|
||||
}
|
||||
}
|
||||
|
||||
// Implementaciones From para errores estándar (sin dependencias externas de infra)
|
||||
// From implementations for standard errors (without external infrastructure dependencies)
|
||||
impl From<std::io::Error> for DomainError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
DomainError {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//! Puerto de persistencia del dominio para la entidad File.
|
||||
//! Domain persistence port for the File entity.
|
||||
//!
|
||||
//! Define el contrato que cualquier implementación de almacenamiento de archivos
|
||||
//! debe cumplir. Este trait vive en el dominio porque File es una entidad core
|
||||
//! del sistema y sus contratos de persistencia pertenecen a la capa de dominio,
|
||||
//! siguiendo los principios de Clean/Hexagonal Architecture.
|
||||
//! Defines the contract that any file storage implementation must fulfill.
|
||||
//! This trait lives in the domain because File is a core entity of the system
|
||||
//! and its persistence contracts belong to the domain layer, following
|
||||
//! Clean/Hexagonal Architecture principles.
|
||||
//!
|
||||
//! Las implementaciones concretas (filesystem, PostgreSQL, S3, etc.) viven en
|
||||
//! la capa de infraestructura.
|
||||
//! Concrete implementations (filesystem, PostgreSQL, S3, etc.) live in
|
||||
//! the infrastructure layer.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
@@ -20,31 +20,31 @@ use crate::domain::services::path_service::StoragePath;
|
||||
use crate::common::errors::DomainError;
|
||||
|
||||
// ─────────────────────────────────────────────────────
|
||||
// FileReadRepository — operaciones de lectura/consulta
|
||||
// FileReadRepository — read/query operations
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Puerto del dominio para **lectura** de archivos.
|
||||
/// Domain port for file **reading**.
|
||||
///
|
||||
/// Encapsula toda operación que consulta estado sin modificarlo:
|
||||
/// obtener, listar, contenido, stream, mmap, rango, resolución de rutas.
|
||||
/// Encapsulates every operation that queries state without modifying it:
|
||||
/// get, list, content, stream, mmap, range, path resolution.
|
||||
#[async_trait]
|
||||
pub trait FileReadRepository: Send + Sync + 'static {
|
||||
/// Obtiene un archivo por su ID.
|
||||
/// Gets a file by its ID.
|
||||
async fn get_file(&self, id: &str) -> Result<File, DomainError>;
|
||||
|
||||
/// Lista archivos en una carpeta.
|
||||
/// Lists files in a folder.
|
||||
async fn list_files(&self, folder_id: Option<&str>) -> Result<Vec<File>, DomainError>;
|
||||
|
||||
/// Obtiene contenido completo como bytes (solo archivos pequeños/medianos).
|
||||
/// Gets full content as bytes (only for small/medium files).
|
||||
async fn get_file_content(&self, id: &str) -> Result<Vec<u8>, DomainError>;
|
||||
|
||||
/// Obtiene contenido como stream (ideal para archivos grandes).
|
||||
/// Gets content as a stream (ideal for large files).
|
||||
async fn get_file_stream(
|
||||
&self,
|
||||
id: &str,
|
||||
) -> Result<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>, DomainError>;
|
||||
|
||||
/// Stream de un rango de bytes (HTTP Range Requests, video seek).
|
||||
/// Stream of a byte range (HTTP Range Requests, video seek).
|
||||
async fn get_file_range_stream(
|
||||
&self,
|
||||
id: &str,
|
||||
@@ -52,27 +52,27 @@ pub trait FileReadRepository: Send + Sync + 'static {
|
||||
end: Option<u64>,
|
||||
) -> Result<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>, DomainError>;
|
||||
|
||||
/// Memory-map de archivo para acceso zero-copy (10–100 MB).
|
||||
/// Memory-mapped file for zero-copy access (10–100 MB).
|
||||
async fn get_file_mmap(&self, id: &str) -> Result<Bytes, DomainError>;
|
||||
|
||||
/// Obtiene la ruta de almacenamiento lógica de un archivo.
|
||||
/// Gets the logical storage path of a file.
|
||||
async fn get_file_path(&self, id: &str) -> Result<StoragePath, DomainError>;
|
||||
|
||||
/// Obtiene el ID de la carpeta padre a partir de una ruta (WebDAV).
|
||||
/// Gets the parent folder ID from a path (WebDAV).
|
||||
async fn get_parent_folder_id(&self, path: &str) -> Result<String, DomainError>;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────
|
||||
// FileWriteRepository — operaciones de escritura/mutación
|
||||
// FileWriteRepository — write/mutation operations
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Puerto del dominio para **escritura** de archivos.
|
||||
/// Domain port for file **writing**.
|
||||
///
|
||||
/// Cubre: upload (buffered + streaming), move, delete, update,
|
||||
/// y el registro diferido para write-behind cache.
|
||||
/// Covers: upload (buffered + streaming), move, delete, update,
|
||||
/// and deferred registration for write-behind cache.
|
||||
#[async_trait]
|
||||
pub trait FileWriteRepository: Send + Sync + 'static {
|
||||
/// Guarda un nuevo archivo desde bytes.
|
||||
/// Saves a new file from bytes.
|
||||
async fn save_file(
|
||||
&self,
|
||||
name: String,
|
||||
@@ -81,7 +81,7 @@ pub trait FileWriteRepository: Send + Sync + 'static {
|
||||
content: Vec<u8>,
|
||||
) -> Result<File, DomainError>;
|
||||
|
||||
/// Upload en streaming — escribe chunks a disco sin acumular en RAM.
|
||||
/// Streaming upload — writes chunks to disk without accumulating in RAM.
|
||||
async fn save_file_from_stream(
|
||||
&self,
|
||||
name: String,
|
||||
@@ -90,30 +90,30 @@ pub trait FileWriteRepository: Send + Sync + 'static {
|
||||
stream: Pin<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>>,
|
||||
) -> Result<File, DomainError>;
|
||||
|
||||
/// Mueve un archivo a otra carpeta.
|
||||
/// Moves a file to another folder.
|
||||
async fn move_file(
|
||||
&self,
|
||||
file_id: &str,
|
||||
target_folder_id: Option<String>,
|
||||
) -> Result<File, DomainError>;
|
||||
|
||||
/// Renombra un archivo (same folder, different name).
|
||||
/// Renames a file (same folder, different name).
|
||||
async fn rename_file(
|
||||
&self,
|
||||
file_id: &str,
|
||||
new_name: &str,
|
||||
) -> Result<File, DomainError>;
|
||||
|
||||
/// Elimina un archivo.
|
||||
/// Deletes a file.
|
||||
async fn delete_file(&self, id: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Actualiza el contenido de un archivo existente.
|
||||
/// Updates the content of an existing file.
|
||||
async fn update_file_content(&self, file_id: &str, content: Vec<u8>) -> Result<(), DomainError>;
|
||||
|
||||
/// Registra metadatos de archivo SIN escribir contenido a disco (write-behind).
|
||||
/// Registers file metadata WITHOUT writing content to disk (write-behind).
|
||||
///
|
||||
/// Devuelve `(File, PathBuf)` donde `PathBuf` es la ruta destino para la
|
||||
/// escritura diferida que realizará el `WriteBehindCache`.
|
||||
/// Returns `(File, PathBuf)` where `PathBuf` is the destination path for
|
||||
/// the deferred write that the `WriteBehindCache` will perform.
|
||||
async fn register_file_deferred(
|
||||
&self,
|
||||
name: String,
|
||||
@@ -124,27 +124,27 @@ pub trait FileWriteRepository: Send + Sync + 'static {
|
||||
|
||||
// ── Trash operations ──
|
||||
|
||||
/// Mueve un archivo a la papelera
|
||||
/// Moves a file to the trash
|
||||
async fn move_to_trash(&self, file_id: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Restaura un archivo desde la papelera a su ubicación original
|
||||
/// Restores a file from the trash to its original location
|
||||
async fn restore_from_trash(&self, file_id: &str, original_path: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Elimina un archivo permanentemente (usado por la papelera)
|
||||
/// Permanently deletes a file (used by the trash)
|
||||
async fn delete_file_permanently(&self, file_id: &str) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────
|
||||
// FileRepository — supertrait unificado
|
||||
// FileRepository — unified supertrait
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Puerto unificado para persistencia de archivos.
|
||||
/// Unified port for file persistence.
|
||||
///
|
||||
/// Es un supertrait de `FileReadRepository + FileWriteRepository`.
|
||||
/// Cualquier tipo que implemente ambos ports obtiene `FileRepository`
|
||||
/// automáticamente vía blanket impl.
|
||||
/// It is a supertrait of `FileReadRepository + FileWriteRepository`.
|
||||
/// Any type that implements both ports gets `FileRepository`
|
||||
/// automatically via blanket impl.
|
||||
pub trait FileRepository: FileReadRepository + FileWriteRepository {}
|
||||
|
||||
/// Blanket implementation: cualquier tipo que implemente ambos ports
|
||||
/// es automáticamente un FileRepository.
|
||||
/// Blanket implementation: any type that implements both ports
|
||||
/// is automatically a FileRepository.
|
||||
impl<T: FileReadRepository + FileWriteRepository> FileRepository for T {}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//! Puerto de persistencia del dominio para la entidad Folder.
|
||||
//! Domain persistence port for the Folder entity.
|
||||
//!
|
||||
//! Define el contrato que cualquier implementación de almacenamiento de carpetas
|
||||
//! debe cumplir. Este trait vive en el dominio porque Folder es una entidad core
|
||||
//! del sistema y sus contratos de persistencia pertenecen a la capa de dominio,
|
||||
//! siguiendo los principios de Clean/Hexagonal Architecture.
|
||||
//! Defines the contract that any folder storage implementation
|
||||
//! must fulfill. This trait lives in the domain because Folder is a core entity
|
||||
//! of the system and its persistence contracts belong to the domain layer,
|
||||
//! following the principles of Clean/Hexagonal Architecture.
|
||||
//!
|
||||
//! Las implementaciones concretas (filesystem, PostgreSQL, S3, etc.) viven en
|
||||
//! la capa de infraestructura.
|
||||
//! Concrete implementations (filesystem, PostgreSQL, S3, etc.) live in
|
||||
//! the infrastructure layer.
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
@@ -14,25 +14,25 @@ use crate::domain::entities::folder::Folder;
|
||||
use crate::domain::services::path_service::StoragePath;
|
||||
use crate::common::errors::DomainError;
|
||||
|
||||
/// Puerto del dominio para persistencia de carpetas.
|
||||
/// Domain port for folder persistence.
|
||||
///
|
||||
/// Define las operaciones CRUD y de gestión necesarias para
|
||||
/// la entidad Folder en el sistema de almacenamiento.
|
||||
/// Defines the CRUD and management operations required for
|
||||
/// the Folder entity in the storage system.
|
||||
#[async_trait]
|
||||
pub trait FolderRepository: Send + Sync + 'static {
|
||||
/// Crea una nueva carpeta
|
||||
/// Creates a new folder
|
||||
async fn create_folder(&self, name: String, parent_id: Option<String>) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Obtiene una carpeta por su ID
|
||||
/// Gets a folder by its ID
|
||||
async fn get_folder(&self, id: &str) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Obtiene una carpeta por su ruta de almacenamiento
|
||||
/// Gets a folder by its storage path
|
||||
async fn get_folder_by_path(&self, storage_path: &StoragePath) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Lista carpetas dentro de una carpeta padre
|
||||
/// Lists folders within a parent folder
|
||||
async fn list_folders(&self, parent_id: Option<&str>) -> Result<Vec<Folder>, DomainError>;
|
||||
|
||||
/// Lista carpetas con paginación
|
||||
/// Lists folders with pagination
|
||||
async fn list_folders_paginated(
|
||||
&self,
|
||||
parent_id: Option<&str>,
|
||||
@@ -41,29 +41,29 @@ pub trait FolderRepository: Send + Sync + 'static {
|
||||
include_total: bool
|
||||
) -> Result<(Vec<Folder>, Option<usize>), DomainError>;
|
||||
|
||||
/// Renombra una carpeta
|
||||
/// Renames a folder
|
||||
async fn rename_folder(&self, id: &str, new_name: String) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Mueve una carpeta a otro padre
|
||||
/// Moves a folder to another parent
|
||||
async fn move_folder(&self, id: &str, new_parent_id: Option<&str>) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Elimina una carpeta
|
||||
/// Deletes a folder
|
||||
async fn delete_folder(&self, id: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Verifica si existe una carpeta en la ruta dada
|
||||
/// Checks if a folder exists at the given path
|
||||
async fn folder_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
|
||||
|
||||
/// Obtiene la ruta de una carpeta
|
||||
/// Gets the path of a folder
|
||||
async fn get_folder_path(&self, id: &str) -> Result<StoragePath, DomainError>;
|
||||
|
||||
// ── Trash operations ──
|
||||
|
||||
/// Mueve una carpeta a la papelera
|
||||
/// Moves a folder to the trash
|
||||
async fn move_to_trash(&self, folder_id: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Restaura una carpeta desde la papelera a su ubicación original
|
||||
/// Restores a folder from the trash to its original location
|
||||
async fn restore_from_trash(&self, folder_id: &str, original_path: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Elimina una carpeta permanentemente (usado por la papelera)
|
||||
/// Permanently deletes a folder (used by the trash)
|
||||
async fn delete_folder_permanently(&self, folder_id: &str) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ use crate::common::errors::DomainError;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SessionRepositoryError {
|
||||
#[error("Sesión no encontrada: {0}")]
|
||||
#[error("Session not found: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
#[error("Error de base de datos: {0}")]
|
||||
#[error("Database error: {0}")]
|
||||
DatabaseError(String),
|
||||
|
||||
#[error("Error de tiempo de espera: {0}")]
|
||||
#[error("Timeout error: {0}")]
|
||||
Timeout(String),
|
||||
}
|
||||
|
||||
pub type SessionRepositoryResult<T> = Result<T, SessionRepositoryError>;
|
||||
|
||||
// Conversión de SessionRepositoryError a DomainError
|
||||
// Conversion from SessionRepositoryError to DomainError
|
||||
impl From<SessionRepositoryError> for DomainError {
|
||||
fn from(err: SessionRepositoryError) -> Self {
|
||||
match err {
|
||||
@@ -35,24 +35,24 @@ impl From<SessionRepositoryError> for DomainError {
|
||||
|
||||
#[async_trait]
|
||||
pub trait SessionRepository: Send + Sync + 'static {
|
||||
/// Crea una nueva sesión
|
||||
/// Creates a new session
|
||||
async fn create_session(&self, session: Session) -> SessionRepositoryResult<Session>;
|
||||
|
||||
/// Obtiene una sesión por ID
|
||||
/// Gets a session by ID
|
||||
async fn get_session_by_id(&self, id: &str) -> SessionRepositoryResult<Session>;
|
||||
|
||||
/// Obtiene una sesión por token de actualización
|
||||
/// Gets a session by refresh token
|
||||
async fn get_session_by_refresh_token(&self, refresh_token: &str) -> SessionRepositoryResult<Session>;
|
||||
|
||||
/// Obtiene todas las sesiones de un usuario
|
||||
/// Gets all sessions for a user
|
||||
async fn get_sessions_by_user_id(&self, user_id: &str) -> SessionRepositoryResult<Vec<Session>>;
|
||||
|
||||
/// Revoca una sesión específica
|
||||
/// Revokes a specific session
|
||||
async fn revoke_session(&self, session_id: &str) -> SessionRepositoryResult<()>;
|
||||
|
||||
/// Revoca todas las sesiones de un usuario
|
||||
/// Revokes all sessions for a user
|
||||
async fn revoke_all_user_sessions(&self, user_id: &str) -> SessionRepositoryResult<u64>;
|
||||
|
||||
/// Elimina sesiones expiradas
|
||||
/// Deletes expired sessions
|
||||
async fn delete_expired_sessions(&self) -> SessionRepositoryResult<u64>;
|
||||
}
|
||||
@@ -4,28 +4,28 @@ use crate::common::errors::DomainError;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum UserRepositoryError {
|
||||
#[error("Usuario no encontrado: {0}")]
|
||||
#[error("User not found: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
#[error("Usuario ya existe: {0}")]
|
||||
#[error("User already exists: {0}")]
|
||||
AlreadyExists(String),
|
||||
|
||||
#[error("Error de base de datos: {0}")]
|
||||
#[error("Database error: {0}")]
|
||||
DatabaseError(String),
|
||||
|
||||
#[error("Error de validación: {0}")]
|
||||
#[error("Validation error: {0}")]
|
||||
ValidationError(String),
|
||||
|
||||
#[error("Error de tiempo de espera: {0}")]
|
||||
#[error("Timeout error: {0}")]
|
||||
Timeout(String),
|
||||
|
||||
#[error("Operación no permitida: {0}")]
|
||||
#[error("Operation not allowed: {0}")]
|
||||
OperationNotAllowed(String),
|
||||
}
|
||||
|
||||
pub type UserRepositoryResult<T> = Result<T, UserRepositoryError>;
|
||||
|
||||
// Conversión de UserRepositoryError a DomainError
|
||||
// Conversion from UserRepositoryError to DomainError
|
||||
impl From<UserRepositoryError> for DomainError {
|
||||
fn from(err: UserRepositoryError) -> Self {
|
||||
match err {
|
||||
@@ -53,59 +53,59 @@ impl From<UserRepositoryError> for DomainError {
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserRepository: Send + Sync + 'static {
|
||||
/// Crea un nuevo usuario
|
||||
/// Creates a new user
|
||||
async fn create_user(&self, user: User) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Obtiene un usuario por ID
|
||||
/// Gets a user by ID
|
||||
async fn get_user_by_id(&self, id: &str) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Obtiene un usuario por nombre de usuario
|
||||
/// Gets a user by username
|
||||
async fn get_user_by_username(&self, username: &str) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Obtiene un usuario por correo electrónico
|
||||
/// Gets a user by email
|
||||
async fn get_user_by_email(&self, email: &str) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Actualiza un usuario existente
|
||||
/// Updates an existing user
|
||||
async fn update_user(&self, user: User) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Actualiza solo el uso de almacenamiento de un usuario
|
||||
/// Updates only a user's storage usage
|
||||
async fn update_storage_usage(&self, user_id: &str, usage_bytes: i64) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Actualiza la fecha de último inicio de sesión
|
||||
/// Updates the last login date
|
||||
async fn update_last_login(&self, user_id: &str) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Lista usuarios con paginación
|
||||
/// Lists users with pagination
|
||||
async fn list_users(&self, limit: i64, offset: i64) -> UserRepositoryResult<Vec<User>>;
|
||||
|
||||
/// Activa o desactiva un usuario
|
||||
/// Activates or deactivates a user
|
||||
async fn set_user_active_status(&self, user_id: &str, active: bool) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Cambia la contraseña de un usuario
|
||||
/// Changes a user's password
|
||||
async fn change_password(&self, user_id: &str, password_hash: &str) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Cambia el rol de un usuario
|
||||
/// Changes a user's role
|
||||
async fn change_role(&self, user_id: &str, role: UserRole) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Lista usuarios por rol (admin o user)
|
||||
/// Lists users by role (admin or user)
|
||||
async fn list_users_by_role(&self, role: &str) -> UserRepositoryResult<Vec<User>>;
|
||||
|
||||
/// Elimina un usuario
|
||||
/// Deletes a user
|
||||
async fn delete_user(&self, user_id: &str) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Finds a user by OIDC provider + subject pair
|
||||
async fn get_user_by_oidc_subject(&self, provider: &str, subject: &str) -> UserRepositoryResult<User>;
|
||||
|
||||
/// Actualiza la cuota de almacenamiento de un usuario
|
||||
/// Updates a user's storage quota
|
||||
async fn update_storage_quota(&self, user_id: &str, quota_bytes: i64) -> UserRepositoryResult<()>;
|
||||
|
||||
/// Cuenta el número total de usuarios
|
||||
/// Counts the total number of users
|
||||
async fn count_users(&self) -> UserRepositoryResult<i64>;
|
||||
|
||||
/// Obtiene estadísticas de almacenamiento agregadas
|
||||
/// Gets aggregated storage statistics
|
||||
async fn get_storage_stats(&self) -> UserRepositoryResult<StorageStats>;
|
||||
}
|
||||
|
||||
/// Estadísticas de almacenamiento agregadas
|
||||
/// Aggregated storage statistics
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StorageStats {
|
||||
pub total_users: i64,
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
//! StoragePath - Value Object del dominio para representar rutas de almacenamiento
|
||||
//! StoragePath - Domain Value Object for representing storage paths
|
||||
//!
|
||||
//! Este módulo contiene solo el Value Object StoragePath que es parte del dominio puro.
|
||||
//! PathService (que implementa StoragePort y StorageMediator) fue movido a
|
||||
//! infrastructure/services/path_service.rs porque tiene dependencias de sistema de archivos.
|
||||
//! This module contains only the StoragePath Value Object which is part of the pure domain.
|
||||
//! PathService (which implements StoragePort and StorageMediator) was moved to
|
||||
//! infrastructure/services/path_service.rs because it has file system dependencies.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Representa una ruta de almacenamiento en el dominio (Value Object)
|
||||
/// Represents a storage path in the domain (Value Object)
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct StoragePath {
|
||||
segments: Vec<String>,
|
||||
}
|
||||
|
||||
impl StoragePath {
|
||||
/// Crea una nueva ruta de almacenamiento
|
||||
/// Creates a new storage path
|
||||
pub fn new(segments: Vec<String>) -> Self {
|
||||
Self { segments }
|
||||
}
|
||||
|
||||
/// Crea una ruta vacía (raíz)
|
||||
/// Creates an empty path (root)
|
||||
pub fn root() -> Self {
|
||||
Self { segments: Vec::new() }
|
||||
}
|
||||
|
||||
/// Crea una ruta a partir de una cadena con segmentos separados por /
|
||||
/// Creates a path from a string with segments separated by /
|
||||
pub fn from_string(path: &str) -> Self {
|
||||
let segments = path
|
||||
.split('/')
|
||||
@@ -33,7 +33,7 @@ impl StoragePath {
|
||||
Self { segments }
|
||||
}
|
||||
|
||||
/// Crea una ruta a partir de un PathBuf
|
||||
/// Creates a path from a PathBuf
|
||||
pub fn from(path_buf: PathBuf) -> Self {
|
||||
let segments = path_buf
|
||||
.components()
|
||||
@@ -45,19 +45,19 @@ impl StoragePath {
|
||||
Self { segments }
|
||||
}
|
||||
|
||||
/// Añade un segmento a la ruta
|
||||
/// Appends a segment to the path
|
||||
pub fn join(&self, segment: &str) -> Self {
|
||||
let mut new_segments = self.segments.clone();
|
||||
new_segments.push(segment.to_string());
|
||||
Self { segments: new_segments }
|
||||
}
|
||||
|
||||
/// Obtiene el nombre del archivo (último segmento)
|
||||
/// Gets the file name (last segment)
|
||||
pub fn file_name(&self) -> Option<String> {
|
||||
self.segments.last().cloned()
|
||||
}
|
||||
|
||||
/// Obtiene la ruta del directorio padre
|
||||
/// Gets the parent directory path
|
||||
pub fn parent(&self) -> Option<Self> {
|
||||
if self.segments.is_empty() {
|
||||
None
|
||||
@@ -67,12 +67,12 @@ impl StoragePath {
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifica si la ruta está vacía (es la raíz)
|
||||
/// Checks if the path is empty (is the root)
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.segments.is_empty()
|
||||
}
|
||||
|
||||
/// Convierte la ruta a una cadena con formato "/segment1/segment2/..."
|
||||
/// Converts the path to a string with format "/segment1/segment2/..."
|
||||
pub fn to_string(&self) -> String {
|
||||
if self.segments.is_empty() {
|
||||
"/".to_string()
|
||||
@@ -81,15 +81,15 @@ impl StoragePath {
|
||||
}
|
||||
}
|
||||
|
||||
/// Devuelve la representación de la ruta como cadena
|
||||
/// Returns the path representation as a string
|
||||
pub fn as_str(&self) -> &str {
|
||||
// Nota: La implementación realmente debería almacenar la cadena,
|
||||
// pero aquí hacemos una implementación temporal que siempre devuelve "/"
|
||||
// Esto se usa solo para la implementación de get_folder_path_str
|
||||
// Note: The implementation should really store the string,
|
||||
// but here we do a temporary implementation that always returns "/"
|
||||
// This is only used for the get_folder_path_str implementation
|
||||
"/"
|
||||
}
|
||||
|
||||
/// Obtiene los segmentos de la ruta
|
||||
/// Gets the path segments
|
||||
pub fn segments(&self) -> &[String] {
|
||||
&self.segments
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user