use std::time::Duration; use axum::{ extract::State, response::{IntoResponse, Response}, routing::post, Json, Router, }; use http::StatusCode; use crate::{ db::{insert_new_user, NewUserEntity, UserEntity}, models::ApiResponse, requests::AppState, services::{auth_token::generate_token, hash_string, UserConfirmationMessage}, }; use super::models::{UserPostRequest, UserPostResponse}; static FIFTEEN_MINUTES: u64 = 60 * 15; pub fn request(app_state: AppState) -> Router { Router::new() .route("/", post(user_post_handler)) .with_state(app_state) } async fn user_post_handler( State(app_state): State, Json(request): Json, ) -> Result { let UserPostRequest { username, password, email, name, } = request; let hashed_password = hash_string(password.as_str()); let new_user = NewUserEntity::new(username, email.clone(), hashed_password, name.clone()); let UserEntity { id: user_id, name, email , ..} = insert_new_user(app_state.pool(), new_user).await .map_err(|err| { if err.is_duplicate_record() { (StatusCode::CONFLICT, ApiResponse::error("There is already an account associated with this username or email address.").into_json_response()).into_response() } else { (StatusCode::INTERNAL_SERVER_ERROR, ApiResponse::error("An error occurred while creating your new user account. Please try again later.").into_json_response()).into_response() } })?; let (auth_token, expiration) = generate_token( app_state.env().token_key(), user_id, Some(Duration::from_secs(FIFTEEN_MINUTES)), Some(format!("/user/{user_id}/verify").as_str()), ); let new_user_confirmation_message = UserConfirmationMessage::new(email.as_str(), name.as_str(), auth_token.as_str()); let _ = app_state .env() .email_sender() .send(new_user_confirmation_message) .inspect_err(|err| { eprintln!("Got the rollowing error while sending across the channel: {err}"); }); let response = ( StatusCode::CREATED, Json(ApiResponse::::new(UserPostResponse::new( user_id, auth_token, expiration, ))), ); Ok(response.into_response()) }