Files
libertas/libertas_api/src/services/user_service.rs

93 lines
2.7 KiB
Rust

use std::sync::Arc;
use async_trait::async_trait;
use libertas_core::{
error::{CoreError, CoreResult},
models::{Role, User},
repositories::UserRepository,
schema::{CreateUserData, LoginUserData},
services::UserService,
};
use uuid::Uuid;
use crate::security::{PasswordHasher, TokenGenerator};
pub struct UserServiceImpl {
repo: Arc<dyn UserRepository>,
hasher: Arc<dyn PasswordHasher>,
tokenizer: Arc<dyn TokenGenerator>,
}
impl UserServiceImpl {
pub fn new(
repo: Arc<dyn UserRepository>,
hasher: Arc<dyn PasswordHasher>,
tokenizer: Arc<dyn TokenGenerator>,
) -> Self {
Self {
repo,
hasher,
tokenizer,
}
}
}
#[async_trait]
impl UserService for UserServiceImpl {
async fn register(&self, data: CreateUserData<'_>) -> CoreResult<User> {
if data.username.is_empty() || data.email.is_empty() || data.password.is_empty() {
return Err(CoreError::Validation(
"Username, email, and password cannot be empty".to_string(),
));
}
if self.repo.find_by_email(data.email).await?.is_some() {
return Err(CoreError::Duplicate("Email already exists".to_string()));
}
if self.repo.find_by_username(data.username).await?.is_some() {
return Err(CoreError::Duplicate("Username already exists".to_string()));
}
let hashed_password = self.hasher.hash_password(data.password).await?;
let user = User {
id: Uuid::new_v4(),
username: data.username.to_string(),
email: data.email.to_string(),
hashed_password,
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
role: Role::User,
storage_quota: 10 * 1024 * 1024 * 1024, // 10 GB
storage_used: 0,
};
self.repo.create(user.clone()).await?;
Ok(user)
}
async fn login(&self, data: LoginUserData<'_>) -> CoreResult<String> {
let user = self
.repo
.find_by_email(data.username_or_email) // Allow login with email
.await?
.or(self.repo.find_by_username(data.username_or_email).await?) // Or username
.ok_or(CoreError::Auth("Invalid credentials".to_string()))?;
self.hasher
.verify_password(data.password, &user.hashed_password)
.await?;
// 3. Generate JWT token
self.tokenizer.generate_token(user.id)
}
async fn get_user_details(&self, user_id: Uuid) -> CoreResult<User> {
self.repo
.find_by_id(user_id)
.await?
.ok_or(CoreError::NotFound("User".to_string(), user_id))
}
}