This commit is contained in:
2025-11-02 09:31:01 +01:00
commit 455e144ffb
37 changed files with 4193 additions and 0 deletions

1
libertas_core/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

13
libertas_core/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "libertas_core"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0.100"
async-trait = "0.1.89"
bytes = "1.10.1"
chrono = "0.4.42"
futures = "0.3.31"
thiserror = "2.0.17"
uuid = "1.18.1"

View File

@@ -0,0 +1,30 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CoreError {
#[error("Configuration error: {0}")]
Config(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Database error: {0}")]
Database(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("{0} not found with id: {1}")]
NotFound(String, uuid::Uuid),
#[error("Duplicate resource: {0}")]
Duplicate(String),
#[error("Authentication failed: {0}")]
Auth(String),
#[error("An unknown error occurred")]
Unknown,
}
pub type CoreResult<T> = Result<T, CoreError>;

5
libertas_core/src/lib.rs Normal file
View File

@@ -0,0 +1,5 @@
pub mod error;
pub mod models;
pub mod repositories;
pub mod schema;
pub mod services;

View File

@@ -0,0 +1,67 @@
pub struct Media {
pub id: uuid::Uuid,
pub owner_id: uuid::Uuid,
pub storage_path: String,
pub original_filename: String,
pub mime_type: String,
pub hash: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub extracted_location: Option<String>,
pub width: Option<i32>,
pub height: Option<i32>,
}
#[derive(Clone)]
pub struct User {
pub id: uuid::Uuid,
pub username: String,
pub email: String,
pub hashed_password: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
pub struct Album {
pub id: uuid::Uuid,
pub owner_id: uuid::Uuid,
pub name: String,
pub description: Option<String>,
pub is_public: bool,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
pub struct Person {
pub id: uuid::Uuid,
pub owner_id: uuid::Uuid,
pub name: String,
pub thumbnail_media_id: Option<uuid::Uuid>,
}
pub struct FaceRegion {
pub id: uuid::Uuid,
pub media_id: uuid::Uuid,
pub person_id: Option<uuid::Uuid>,
pub x_min: f32,
pub y_min: f32,
pub x_max: f32,
pub y_max: f32,
}
pub struct AlbumMedia {
pub album_id: uuid::Uuid,
pub media_id: uuid::Uuid,
}
#[derive(Clone, Copy)]
pub enum AlbumPermission {
View,
Contribute,
}
pub struct AlbumShare {
pub album_id: uuid::Uuid,
pub user_id: uuid::Uuid,
pub permission: AlbumPermission,
}

View File

@@ -0,0 +1,31 @@
use async_trait::async_trait;
use uuid::Uuid;
use crate::{
error::CoreResult,
models::{Album, Media, User},
};
#[async_trait]
pub trait MediaRepository: Send + Sync {
async fn find_by_hash(&self, hash: &str) -> CoreResult<Option<Media>>;
async fn create(&self, media: &Media) -> CoreResult<()>;
async fn find_by_id(&self, id: Uuid) -> CoreResult<Option<Media>>;
async fn list_by_user(&self, user_id: Uuid) -> CoreResult<Vec<Media>>;
}
#[async_trait]
pub trait UserRepository: Send + Sync {
async fn create(&self, user: User) -> CoreResult<()>;
async fn find_by_email(&self, email: &str) -> CoreResult<Option<User>>;
async fn find_by_username(&self, username: &str) -> CoreResult<Option<User>>;
async fn find_by_id(&self, id: Uuid) -> CoreResult<Option<User>>;
}
#[async_trait]
pub trait AlbumRepository: Send + Sync {
async fn create(&self, album: Album) -> CoreResult<()>;
async fn find_by_id(&self, id: Uuid) -> CoreResult<Option<Album>>;
async fn list_by_user(&self, user_id: Uuid) -> CoreResult<Vec<Album>>;
async fn add_media_to_album(&self, album_id: Uuid, media_ids: &[Uuid]) -> CoreResult<()>;
}

View File

@@ -0,0 +1,38 @@
use crate::models::AlbumPermission;
pub struct UploadMediaData<'a> {
pub owner_id: uuid::Uuid,
pub filename: String,
pub mime_type: String,
pub stream:
Box<dyn futures::Stream<Item = Result<bytes::Bytes, std::io::Error>> + Send + Unpin + 'a>,
}
pub struct CreateUserData<'a> {
pub username: &'a str,
pub email: &'a str,
pub password: &'a str,
}
pub struct LoginUserData<'a> {
pub username_or_email: &'a str,
pub password: &'a str,
}
pub struct CreateAlbumData<'a> {
pub owner_id: uuid::Uuid,
pub name: &'a str,
pub description: Option<&'a str>,
pub is_public: bool,
}
pub struct AddMediaToAlbumData {
pub album_id: uuid::Uuid,
pub media_ids: Vec<uuid::Uuid>,
}
pub struct ShareAlbumData {
pub album_id: uuid::Uuid,
pub target_user_id: uuid::Uuid,
pub permission: AlbumPermission,
}

View File

@@ -0,0 +1,35 @@
use async_trait::async_trait;
use uuid::Uuid;
use crate::{
error::CoreResult,
models::{Album, Media, User},
schema::{
AddMediaToAlbumData, CreateAlbumData, CreateUserData, LoginUserData, ShareAlbumData,
UploadMediaData,
},
};
#[async_trait]
pub trait MediaService: Send + Sync {
async fn upload_media(&self, data: UploadMediaData<'_>) -> CoreResult<Media>;
async fn get_media_details(&self, id: Uuid, user_id: Uuid) -> CoreResult<Media>;
async fn list_user_media(&self, user_id: Uuid) -> CoreResult<Vec<Media>>;
}
#[async_trait]
pub trait UserService: Send + Sync {
async fn register(&self, data: CreateUserData<'_>) -> CoreResult<User>;
async fn login(&self, data: LoginUserData<'_>) -> CoreResult<String>;
async fn get_user_details(&self, user_id: uuid::Uuid) -> CoreResult<User>;
}
#[async_trait]
pub trait AlbumService: Send + Sync {
async fn create_album(&self, data: CreateAlbumData<'_>) -> CoreResult<()>;
async fn get_album_details(&self, album_id: Uuid, user_id: Uuid) -> CoreResult<Album>;
async fn add_media_to_album(&self, data: AddMediaToAlbumData, user_id: Uuid) -> CoreResult<()>;
async fn list_user_albums(&self, user_id: Uuid) -> CoreResult<Vec<Album>>;
async fn share_album(&self, data: ShareAlbumData, owner_id: Uuid) -> CoreResult<()>;
}