Initial commit
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
use std::path::PathBuf;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Represents a file entity in the domain
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct File {
|
||||
/// Unique identifier for the file
|
||||
pub id: String,
|
||||
|
||||
/// Name of the file
|
||||
pub name: String,
|
||||
|
||||
/// Path to the file (relative to user's root)
|
||||
pub path: PathBuf,
|
||||
|
||||
/// Size of the file in bytes
|
||||
pub size: u64,
|
||||
|
||||
/// MIME type of the file
|
||||
pub mime_type: String,
|
||||
|
||||
/// Parent folder ID
|
||||
pub folder_id: Option<String>,
|
||||
|
||||
/// Creation timestamp
|
||||
pub created_at: u64,
|
||||
|
||||
/// Last modification timestamp
|
||||
pub modified_at: u64,
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// Creates a new file
|
||||
pub fn new(
|
||||
id: String,
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
size: u64,
|
||||
mime_type: String,
|
||||
folder_id: Option<String>,
|
||||
) -> Self {
|
||||
let now = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
size,
|
||||
mime_type,
|
||||
folder_id,
|
||||
created_at: now,
|
||||
modified_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates file modification time
|
||||
#[allow(dead_code)]
|
||||
pub fn touch(&mut self) {
|
||||
self.modified_at = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
use std::path::PathBuf;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Represents a folder entity in the domain
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Folder {
|
||||
/// Unique identifier for the folder
|
||||
pub id: String,
|
||||
|
||||
/// Name of the folder
|
||||
pub name: String,
|
||||
|
||||
/// Path to the folder (relative to user's root)
|
||||
pub path: PathBuf,
|
||||
|
||||
/// Parent folder ID (None if it's a root folder)
|
||||
pub parent_id: Option<String>,
|
||||
|
||||
/// Creation timestamp
|
||||
pub created_at: u64,
|
||||
|
||||
/// Last modification timestamp
|
||||
pub modified_at: u64,
|
||||
}
|
||||
|
||||
impl Folder {
|
||||
/// Creates a new folder
|
||||
pub fn new(id: String, name: String, path: PathBuf, parent_id: Option<String>) -> Self {
|
||||
let now = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
parent_id,
|
||||
created_at: now,
|
||||
modified_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the absolute path of the folder
|
||||
#[allow(dead_code)]
|
||||
pub fn get_absolute_path(&self, root_path: &PathBuf) -> PathBuf {
|
||||
root_path.join(&self.path)
|
||||
}
|
||||
|
||||
/// Updates folder modification time
|
||||
pub fn touch(&mut self) {
|
||||
self.modified_at = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod file;
|
||||
pub mod folder;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod entities;
|
||||
pub mod repositories;
|
||||
pub mod services;
|
||||
@@ -0,0 +1,72 @@
|
||||
use std::path::PathBuf;
|
||||
use async_trait::async_trait;
|
||||
use crate::domain::entities::file::File;
|
||||
|
||||
/// Error types for file repository operations
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(dead_code)]
|
||||
pub enum FileRepositoryError {
|
||||
#[error("File not found: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
#[error("File already exists: {0}")]
|
||||
AlreadyExists(String),
|
||||
|
||||
#[error("Invalid file path: {0}")]
|
||||
InvalidPath(String),
|
||||
|
||||
#[error("IO Error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Result type for file repository operations
|
||||
pub type FileRepositoryResult<T> = Result<T, FileRepositoryError>;
|
||||
|
||||
/// Repository interface for file operations (primary port)
|
||||
#[async_trait]
|
||||
pub trait FileRepository: Send + Sync + 'static {
|
||||
/// Gets a folder by its ID - helper method for file repository to work with folders
|
||||
#[allow(dead_code)]
|
||||
async fn get_folder_by_id(&self, id: &str) -> FileRepositoryResult<crate::domain::entities::folder::Folder>;
|
||||
/// Saves a file from bytes
|
||||
async fn save_file_from_bytes(
|
||||
&self,
|
||||
name: String,
|
||||
folder_id: Option<String>,
|
||||
content_type: String,
|
||||
content: Vec<u8>,
|
||||
) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Saves a file with a specific ID
|
||||
#[allow(dead_code)]
|
||||
async fn save_file_with_id(
|
||||
&self,
|
||||
id: String,
|
||||
name: String,
|
||||
folder_id: Option<String>,
|
||||
content_type: String,
|
||||
content: Vec<u8>,
|
||||
) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Gets a file by its ID
|
||||
async fn get_file_by_id(&self, id: &str) -> FileRepositoryResult<File>;
|
||||
|
||||
/// Lists files in a folder
|
||||
async fn list_files(&self, folder_id: Option<&str>) -> FileRepositoryResult<Vec<File>>;
|
||||
|
||||
/// Deletes a file
|
||||
async fn delete_file(&self, id: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Deletes a file and its entry from the map
|
||||
#[allow(dead_code)]
|
||||
async fn delete_file_entry(&self, id: &str) -> FileRepositoryResult<()>;
|
||||
|
||||
/// Gets file content as bytes
|
||||
async fn get_file_content(&self, id: &str) -> FileRepositoryResult<Vec<u8>>;
|
||||
|
||||
/// Checks if a file exists at the given path
|
||||
async fn file_exists(&self, path: &PathBuf) -> FileRepositoryResult<bool>;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
use std::path::PathBuf;
|
||||
use async_trait::async_trait;
|
||||
use crate::domain::entities::folder::Folder;
|
||||
|
||||
/// Error types for folder repository operations
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(dead_code)]
|
||||
pub enum FolderRepositoryError {
|
||||
#[error("Folder not found: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
#[error("Folder already exists: {0}")]
|
||||
AlreadyExists(String),
|
||||
|
||||
#[error("Invalid folder path: {0}")]
|
||||
InvalidPath(String),
|
||||
|
||||
#[error("IO Error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Result type for folder repository operations
|
||||
pub type FolderRepositoryResult<T> = Result<T, FolderRepositoryError>;
|
||||
|
||||
/// Repository interface for folder operations (primary port)
|
||||
#[async_trait]
|
||||
pub trait FolderRepository: Send + Sync + 'static {
|
||||
/// Creates a new folder
|
||||
async fn create_folder(&self, name: String, parent_path: Option<PathBuf>) -> FolderRepositoryResult<Folder>;
|
||||
|
||||
/// Gets a folder by its ID
|
||||
async fn get_folder_by_id(&self, id: &str) -> FolderRepositoryResult<Folder>;
|
||||
|
||||
/// Gets a folder by its path
|
||||
async fn get_folder_by_path(&self, path: &PathBuf) -> FolderRepositoryResult<Folder>;
|
||||
|
||||
/// Lists folders in a parent folder
|
||||
async fn list_folders(&self, parent_id: Option<&str>) -> FolderRepositoryResult<Vec<Folder>>;
|
||||
|
||||
/// Renames a folder
|
||||
async fn rename_folder(&self, id: &str, new_name: String) -> FolderRepositoryResult<Folder>;
|
||||
|
||||
/// Moves a folder to a new parent
|
||||
async fn move_folder(&self, id: &str, new_parent_id: Option<&str>) -> FolderRepositoryResult<Folder>;
|
||||
|
||||
/// Deletes a folder
|
||||
async fn delete_folder(&self, id: &str) -> FolderRepositoryResult<()>;
|
||||
|
||||
/// Checks if a folder exists at the given path
|
||||
async fn folder_exists(&self, path: &PathBuf) -> FolderRepositoryResult<bool>;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod file_repository;
|
||||
pub mod folder_repository;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
use async_trait::async_trait;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Error types for i18n service operations
|
||||
#[derive(Debug, Error)]
|
||||
pub enum I18nError {
|
||||
#[error("Translation key not found: {0}")]
|
||||
KeyNotFound(String),
|
||||
|
||||
#[error("Invalid locale: {0}")]
|
||||
InvalidLocale(String),
|
||||
|
||||
#[error("Error loading translations: {0}")]
|
||||
LoadError(String),
|
||||
}
|
||||
|
||||
/// Result type for i18n service operations
|
||||
pub type I18nResult<T> = Result<T, I18nError>;
|
||||
|
||||
/// Supported locales
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Locale {
|
||||
English,
|
||||
Spanish,
|
||||
}
|
||||
|
||||
impl Locale {
|
||||
/// Convert locale to code string
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Locale::English => "en",
|
||||
Locale::Spanish => "es",
|
||||
}
|
||||
}
|
||||
|
||||
/// Create from locale code string
|
||||
pub fn from_str(code: &str) -> Option<Self> {
|
||||
match code.to_lowercase().as_str() {
|
||||
"en" => Some(Locale::English),
|
||||
"es" => Some(Locale::Spanish),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get default locale
|
||||
pub fn default() -> Self {
|
||||
Locale::English
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for i18n service (primary port)
|
||||
#[async_trait]
|
||||
pub trait I18nService: Send + Sync + 'static {
|
||||
/// Get a translation for a key and locale
|
||||
async fn translate(&self, key: &str, locale: Locale) -> I18nResult<String>;
|
||||
|
||||
/// Load translations for a locale
|
||||
async fn load_translations(&self, locale: Locale) -> I18nResult<()>;
|
||||
|
||||
/// Get available locales
|
||||
async fn available_locales(&self) -> Vec<Locale>;
|
||||
|
||||
/// Check if a locale is supported
|
||||
#[allow(dead_code)]
|
||||
async fn is_supported(&self, locale: Locale) -> bool;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod i18n_service;
|
||||
Reference in New Issue
Block a user