refactor(users): Separate signup and signin (#2921)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Mani Chandra
2023-12-04 17:03:44 +05:30
committed by GitHub
parent 9d93533219
commit 80efeb76b1
9 changed files with 453 additions and 109 deletions

View File

@ -1,10 +1,17 @@
use api_models::user as user_api;
use diesel_models::{enums::UserStatus, user as storage_user};
use error_stack::{IntoReport, ResultExt};
use masking::{ExposeInterface, Secret};
#[cfg(feature = "email")]
use error_stack::IntoReport;
use error_stack::ResultExt;
use masking::ExposeInterface;
#[cfg(feature = "email")]
use router_env::env;
#[cfg(feature = "email")]
use router_env::logger;
use super::errors::{UserErrors, UserResponse};
#[cfg(feature = "email")]
use crate::services::email::types as email_types;
use crate::{
consts,
db::user::UserInterface,
@ -13,11 +20,112 @@ use crate::{
types::domain,
utils,
};
pub mod dashboard_metadata;
#[cfg(feature = "dummy_connector")]
pub mod sample_data;
pub mod dashboard_metadata;
#[cfg(feature = "email")]
pub async fn signup_with_merchant_id(
state: AppState,
request: user_api::SignUpWithMerchantIdRequest,
) -> UserResponse<user_api::SignUpWithMerchantIdResponse> {
let new_user = domain::NewUser::try_from(request.clone())?;
new_user
.get_new_merchant()
.get_new_organization()
.insert_org_in_db(state.clone())
.await?;
let user_from_db = new_user
.insert_user_and_merchant_in_db(state.clone())
.await?;
let user_role = new_user
.insert_user_role_in_db(
state.clone(),
consts::user_role::ROLE_ID_ORGANIZATION_ADMIN.to_string(),
UserStatus::Active,
)
.await?;
let email_contents = email_types::ResetPassword {
recipient_email: user_from_db.get_email().try_into()?,
user_name: domain::UserName::new(user_from_db.get_name())?,
settings: state.conf.clone(),
subject: "Get back to Hyperswitch - Reset Your Password Now",
};
let send_email_result = state
.email_client
.compose_and_send_email(
Box::new(email_contents),
state.conf.proxy.https_url.as_ref(),
)
.await;
logger::info!(?send_email_result);
Ok(ApplicationResponse::Json(user_api::AuthorizeResponse {
is_email_sent: send_email_result.is_ok(),
user_id: user_from_db.get_user_id().to_string(),
merchant_id: user_role.merchant_id,
}))
}
pub async fn signup(
state: AppState,
request: user_api::SignUpRequest,
) -> UserResponse<user_api::SignUpResponse> {
let new_user = domain::NewUser::try_from(request)?;
new_user
.get_new_merchant()
.get_new_organization()
.insert_org_in_db(state.clone())
.await?;
let user_from_db = new_user
.insert_user_and_merchant_in_db(state.clone())
.await?;
let user_role = new_user
.insert_user_role_in_db(
state.clone(),
consts::user_role::ROLE_ID_ORGANIZATION_ADMIN.to_string(),
UserStatus::Active,
)
.await?;
let token = utils::user::generate_jwt_auth_token(state, &user_from_db, &user_role).await?;
Ok(ApplicationResponse::Json(
utils::user::get_dashboard_entry_response(user_from_db, user_role, token),
))
}
pub async fn signin(
state: AppState,
request: user_api::SignInRequest,
) -> UserResponse<user_api::SignInResponse> {
let user_from_db: domain::UserFromStorage = state
.store
.find_user_by_email(request.email.clone().expose().expose().as_str())
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(UserErrors::InvalidCredentials)
} else {
e.change_context(UserErrors::InternalServerError)
}
})?
.into();
user_from_db.compare_password(request.password)?;
let user_role = user_from_db.get_role_from_db(state.clone()).await?;
let token = utils::user::generate_jwt_auth_token(state, &user_from_db, &user_role).await?;
Ok(ApplicationResponse::Json(
utils::user::get_dashboard_entry_response(user_from_db, user_role, token),
))
}
#[cfg(feature = "email")]
pub async fn connect_account(
state: AppState,
request: user_api::ConnectAccountRequest,
@ -29,26 +137,34 @@ pub async fn connect_account(
if let Ok(found_user) = find_user {
let user_from_db: domain::UserFromStorage = found_user.into();
user_from_db.compare_password(request.password)?;
let user_role = user_from_db.get_role_from_db(state.clone()).await?;
let jwt_token = user_from_db
.get_jwt_auth_token(state.clone(), user_role.org_id)
.await?;
let email_contents = email_types::MagicLink {
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
settings: state.conf.clone(),
user_name: domain::UserName::new(user_from_db.get_name())?,
subject: "Unlock Hyperswitch: Use Your Magic Link to Sign In",
};
let send_email_result = state
.email_client
.compose_and_send_email(
Box::new(email_contents),
state.conf.proxy.https_url.as_ref(),
)
.await;
logger::info!(?send_email_result);
return Ok(ApplicationResponse::Json(
user_api::ConnectAccountResponse {
token: Secret::new(jwt_token),
merchant_id: user_role.merchant_id,
name: user_from_db.get_name(),
email: user_from_db.get_email(),
verification_days_left: None,
user_role: user_role.role_id,
is_email_sent: send_email_result.is_ok(),
user_id: user_from_db.get_user_id().to_string(),
merchant_id: user_role.merchant_id,
},
));
} else if find_user
.as_ref()
.map_err(|e| e.current_context().is_db_not_found())
.err()
.unwrap_or(false)
@ -73,46 +189,35 @@ pub async fn connect_account(
UserStatus::Active,
)
.await?;
let jwt_token = user_from_db
.get_jwt_auth_token(state.clone(), user_role.org_id)
.await?;
#[cfg(feature = "email")]
{
use router_env::logger;
let email_contents = email_types::VerifyEmail {
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
settings: state.conf.clone(),
subject: "Welcome to the Hyperswitch community!",
};
use crate::services::email::types as email_types;
let send_email_result = state
.email_client
.compose_and_send_email(
Box::new(email_contents),
state.conf.proxy.https_url.as_ref(),
)
.await;
let email_contents = email_types::VerifyEmail {
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
settings: state.conf.clone(),
subject: "Welcome to the Hyperswitch community!",
};
let send_email_result = state
.email_client
.compose_and_send_email(
Box::new(email_contents),
state.conf.proxy.https_url.as_ref(),
)
.await;
logger::info!(?send_email_result);
}
logger::info!(?send_email_result);
return Ok(ApplicationResponse::Json(
user_api::ConnectAccountResponse {
token: Secret::new(jwt_token),
merchant_id: user_role.merchant_id,
name: user_from_db.get_name(),
email: user_from_db.get_email(),
verification_days_left: None,
user_role: user_role.role_id,
is_email_sent: send_email_result.is_ok(),
user_id: user_from_db.get_user_id().to_string(),
merchant_id: user_role.merchant_id,
},
));
} else {
Err(UserErrors::InternalServerError.into())
Err(find_user
.err()
.map(|e| e.change_context(UserErrors::InternalServerError))
.unwrap_or(UserErrors::InternalServerError.into()))
}
}
@ -215,7 +320,7 @@ pub async fn switch_merchant_id(
state: AppState,
request: user_api::SwitchMerchantIdRequest,
user_from_token: auth::UserFromToken,
) -> UserResponse<user_api::ConnectAccountResponse> {
) -> UserResponse<user_api::SwitchMerchantResponse> {
if !utils::user_role::is_internal_role(&user_from_token.role_id) {
let merchant_list =
utils::user_role::get_merchant_ids_for_user(state.clone(), &user_from_token.user_id)
@ -252,7 +357,7 @@ pub async fn switch_merchant_id(
}
})?;
let org_id = state
let _org_id = state
.store
.find_merchant_account_by_merchant_id(request.merchant_id.as_str(), &key_store)
.await
@ -272,23 +377,23 @@ pub async fn switch_merchant_id(
.await
.change_context(UserErrors::InternalServerError)?;
let token = Box::pin(user.get_jwt_auth_token_with_custom_merchant_id(
state.clone(),
let token = utils::user::generate_jwt_auth_token_with_custom_merchant_id(
state,
&user,
&user_role,
request.merchant_id.clone(),
org_id,
))
.await?
.into();
)
.await?;
Ok(ApplicationResponse::Json(
user_api::ConnectAccountResponse {
merchant_id: request.merchant_id,
user_api::SwitchMerchantResponse {
token,
name: user.get_name(),
email: user.get_email(),
user_id: user.get_user_id().to_string(),
verification_days_left: None,
user_role: user_role.role_id,
merchant_id: user_role.merchant_id,
},
))
}