use std::{sync::mpsc::Sender, time::SystemTime}; use crate::{ db::{insert_new_user, DbPool, NewUserEntity, UserEntity}, models::{ApiResponse, AppError, Session}, requests::AppState, services::{ self, auth_token::generate_new_user_token, hash_password, CachePool, UserConfirmationMessage, }, }; use axum::{ debug_handler, extract::State, response::{IntoResponse, Response}, Json, }; use http::StatusCode; use pasetors::{keys::SymmetricKey, version4::V4}; use tracing::debug; use super::models::{UserRegistrationRequest, UserRegistrationResponse}; #[debug_handler] pub async fn user_registration_post_handler( State(state): State, Json(request): Json, ) -> Result { let env = state.env(); register_new_user_request( request, state.db_pool(), state.cache_pool(), env.token_key(), env.send_verification_email(), env.email_sender(), ) .await } async fn register_new_user_request( body: UserRegistrationRequest, db_pool: &DbPool, cache_pool: &CachePool, signing_key: &SymmetricKey, send_verification_email: bool, email_sender: &Sender, ) -> Result { debug!(?body, send_verification_email); let UserRegistrationRequest { username, password, email, name, } = body; let hashed_password = hash_password(password); let new_user = NewUserEntity { username: username.clone(), password: hashed_password.to_string(), email, name, }; let UserEntity { id: user_id, name, email, .. } = insert_new_user(db_pool, new_user).await.map_err(|err| { if err.is_duplicate_record() { AppError::duplicate_record( "There is already an account associated with this username or email address.", ) } else { err } })?; let (verification_token, token_id, expires_at) = generate_new_user_token(signing_key, user_id); let new_user_session = Session { user_id, username, created_at: SystemTime::now(), expires_at, }; let expires_in = expires_at.duration_since(SystemTime::now()).unwrap(); services::user_session::store_user_session( cache_pool, token_id, new_user_session, Some(expires_in), ) .await?; let response_body = if send_verification_email { let new_user_confirmation_message = UserConfirmationMessage { email, name, verification_token: verification_token.clone(), }; let _ = email_sender .send(new_user_confirmation_message) .inspect_err(|err| { eprintln!("Got the rollowing error while sending across the channel: {err}"); }); UserRegistrationResponse { id: user_id, expires_at, verification_token: None, } } else { UserRegistrationResponse { id: user_id, expires_at, verification_token: Some(verification_token), } }; let response = ( StatusCode::CREATED, ApiResponse::new(response_body).into_json_response(), ); Ok(response.into_response()) }