application: auth bounded context (register, login)
This commit is contained in:
46
crates/application/src/auth/register.rs
Normal file
46
crates/application/src/auth/register.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use domain::events::DomainEvent;
|
||||
use domain::models::User;
|
||||
use domain::{DomainResult, Email, Password};
|
||||
|
||||
use super::commands::RegisterCommand;
|
||||
use super::deps::AuthDeps;
|
||||
|
||||
/// Register a new local user.
|
||||
///
|
||||
/// Flow: validate email/password -> check duplicate -> hash password ->
|
||||
/// create User (first user gets admin) -> save -> publish event -> return User.
|
||||
pub async fn execute(deps: &AuthDeps, cmd: RegisterCommand) -> DomainResult<User> {
|
||||
// Validate inputs via domain value objects
|
||||
let email = Email::new(&cmd.email)?;
|
||||
let password = Password::new(&cmd.password)?;
|
||||
|
||||
// Check for duplicate
|
||||
if deps.user_query.find_by_email(email.as_ref()).await?.is_some() {
|
||||
return Err(domain::DomainError::UserAlreadyExists(cmd.email));
|
||||
}
|
||||
|
||||
// Hash password
|
||||
let hash = deps.auth_service.hash_password(password.as_ref())?;
|
||||
|
||||
// Create user; first user gets admin
|
||||
let mut user = User::new_local(email, hash);
|
||||
if deps.user_query.count_users().await? == 0 {
|
||||
user.promote_to_admin();
|
||||
}
|
||||
|
||||
// Persist
|
||||
deps.user_command.save(&user).await?;
|
||||
|
||||
// Publish event
|
||||
deps.event_publisher
|
||||
.publish(DomainEvent::UserRegistered {
|
||||
user_id: user.id(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/register.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user