get complete session from login request instead of fetching again

This commit is contained in:
2025-07-18 14:05:19 +02:00
parent fe6cf2fb53
commit 4c3e54daca
9 changed files with 102 additions and 76 deletions

View File

@@ -1,8 +1,8 @@
use thiserror::Error;
use crate::domain::warren::models::auth_session::requests::CreateAuthSessionError;
use crate::domain::warren::models::auth_session::{AuthSession, requests::CreateAuthSessionError};
use super::{UserEmail, UserName};
use super::{User, UserEmail, UserName};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RegisterUserRequest {
@@ -125,6 +125,26 @@ pub struct LoginUserRequest {
password: UserPassword,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LoginUserResponse {
session: AuthSession,
user: User,
}
impl LoginUserResponse {
pub fn new(session: AuthSession, user: User) -> Self {
Self { session, user }
}
pub fn session(&self) -> &AuthSession {
&self.session
}
pub fn user(&self) -> &User {
&self.user
}
}
impl LoginUserRequest {
pub fn new(email: UserEmail, password: UserPassword) -> Self {
Self { email, password }

View File

@@ -19,7 +19,10 @@ use super::models::{
DeleteDirectoryError, DeleteDirectoryRequest, DeleteFileError, DeleteFileRequest, File,
FilePath, ListFilesError, ListFilesRequest, RenameEntryError, RenameEntryRequest,
},
user::{LoginUserError, LoginUserRequest, RegisterUserError, RegisterUserRequest, User},
user::{
LoginUserError, LoginUserRequest, LoginUserResponse, RegisterUserError,
RegisterUserRequest, User,
},
warren::{
CreateWarrenDirectoryError, CreateWarrenDirectoryRequest, DeleteWarrenDirectoryError,
DeleteWarrenDirectoryRequest, DeleteWarrenFileError, DeleteWarrenFileRequest,
@@ -108,7 +111,7 @@ pub trait AuthService: Clone + Send + Sync + 'static {
fn login_user(
&self,
request: LoginUserRequest,
) -> impl Future<Output = Result<AuthSession, LoginUserError>> + Send;
) -> impl Future<Output = Result<LoginUserResponse, LoginUserError>> + Send;
fn create_auth_session(
&self,
request: CreateAuthSessionRequest,

View File

@@ -3,7 +3,7 @@ use uuid::Uuid;
use crate::domain::warren::models::{
auth_session::requests::FetchAuthSessionResponse,
file::{AbsoluteFilePath, File, FilePath},
user::User,
user::{LoginUserResponse, User},
warren::Warren,
};
@@ -75,7 +75,7 @@ pub trait FileSystemNotifier: Clone + Send + Sync + 'static {
pub trait AuthNotifier: Clone + Send + Sync + 'static {
fn user_registered(&self, user: &User) -> impl Future<Output = ()> + Send;
fn user_logged_in(&self, user: &User) -> impl Future<Output = ()> + Send;
fn user_logged_in(&self, response: &LoginUserResponse) -> impl Future<Output = ()> + Send;
fn auth_session_created(&self, user_id: &Uuid) -> impl Future<Output = ()> + Send;
fn auth_session_fetched(
&self,

View File

@@ -10,7 +10,8 @@ use crate::{
},
},
user::{
LoginUserError, LoginUserRequest, RegisterUserError, RegisterUserRequest, User,
LoginUserError, LoginUserRequest, LoginUserResponse, RegisterUserError,
RegisterUserRequest, User,
},
},
ports::{AuthMetrics, AuthNotifier, AuthRepository, AuthService},
@@ -93,7 +94,10 @@ where
result
}
async fn login_user(&self, request: LoginUserRequest) -> Result<AuthSession, LoginUserError> {
async fn login_user(
&self,
request: LoginUserRequest,
) -> Result<LoginUserResponse, LoginUserError> {
let user = self
.repository
.verify_user_password(request.into())
@@ -105,11 +109,12 @@ where
user.clone(),
self.config.session_lifetime(),
))
.await;
.await
.map(|session| LoginUserResponse::new(session, user));
if result.as_ref().is_ok() {
if let Ok(response) = result.as_ref() {
self.metrics.record_user_login_success().await;
self.notifier.user_logged_in(&user).await;
self.notifier.user_logged_in(response).await;
} else {
self.metrics.record_user_login_failure().await;
}

View File

@@ -3,45 +3,22 @@ use axum::{
http::{HeaderMap, StatusCode},
};
use serde::Serialize;
use uuid::Uuid;
use crate::{
domain::warren::{
models::{
auth_session::{
AuthSessionId,
requests::{FetchAuthSessionRequest, FetchAuthSessionResponse},
},
user::User,
models::auth_session::{
AuthSessionId,
requests::{FetchAuthSessionRequest, FetchAuthSessionResponse},
},
ports::{AuthService, WarrenService},
},
inbound::http::{
AppState,
handlers::SessionUser,
responses::{ApiError, ApiSuccess},
},
};
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
struct SessionUser {
id: Uuid,
name: String,
email: String,
admin: bool,
}
impl From<User> for SessionUser {
fn from(value: User) -> Self {
Self {
id: *value.id(),
name: value.name().to_string(),
email: value.email().to_string(),
admin: value.admin(),
}
}
}
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FetchSessionResponseBody {

View File

@@ -4,14 +4,15 @@ use thiserror::Error;
use crate::{
domain::warren::{
models::{
auth_session::AuthSession,
user::{LoginUserRequest, UserEmail, UserEmailError, UserPassword, UserPasswordError},
models::user::{
LoginUserRequest, LoginUserResponse, UserEmail, UserEmailError, UserPassword,
UserPasswordError,
},
ports::{AuthService, WarrenService},
},
inbound::http::{
AppState,
handlers::SessionUser,
responses::{ApiError, ApiSuccess},
},
};
@@ -66,16 +67,19 @@ impl LoginUserHttpRequestBody {
}
}
// TODO: Include `user` and `expires_at` fields
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct LoginResponseBody {
token: String,
user: SessionUser,
expires_at: i64,
}
impl From<AuthSession> for LoginResponseBody {
fn from(value: AuthSession) -> Self {
impl From<LoginUserResponse> for LoginResponseBody {
fn from(value: LoginUserResponse) -> Self {
Self {
token: value.session_id().to_string(),
token: value.session().session_id().to_string(),
user: value.user().to_owned().into(),
expires_at: value.session().expires_at().and_utc().timestamp_millis(),
}
}
}

View File

@@ -1,2 +1,28 @@
use serde::Serialize;
use uuid::Uuid;
use crate::domain::warren::models::user::User;
pub mod auth;
pub mod warrens;
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
/// A session user that can be safely sent to the client
pub struct SessionUser {
id: Uuid,
name: String,
email: String,
admin: bool,
}
impl From<User> for SessionUser {
fn from(value: User) -> Self {
Self {
id: *value.id(),
name: value.name().to_string(),
email: value.email().to_string(),
admin: value.admin(),
}
}
}

View File

@@ -4,7 +4,7 @@ use crate::domain::warren::{
models::{
auth_session::requests::FetchAuthSessionResponse,
file::{File, FilePath},
user::User,
user::{LoginUserResponse, User},
warren::Warren,
},
ports::{AuthNotifier, FileSystemNotifier, WarrenNotifier},
@@ -122,8 +122,8 @@ impl AuthNotifier for NotifierDebugLogger {
tracing::debug!("[Notifier] Registered user {}", user.name());
}
async fn user_logged_in(&self, user: &User) {
tracing::debug!("[Notifier] Logged in user {}", user.name());
async fn user_logged_in(&self, response: &LoginUserResponse) {
tracing::debug!("[Notifier] Logged in user {}", response.user().name());
}
async fn auth_session_created(&self, user_id: &Uuid) {