mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
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:
@ -6,11 +6,12 @@ use crate::user::{
|
||||
dashboard_metadata::{
|
||||
GetMetaDataRequest, GetMetaDataResponse, GetMultipleMetaDataPayload, SetMetaDataRequest,
|
||||
},
|
||||
ChangePasswordRequest, ConnectAccountRequest, ConnectAccountResponse,
|
||||
CreateInternalUserRequest, GetUsersResponse, SwitchMerchantIdRequest, UserMerchantCreate,
|
||||
AuthorizeResponse, ChangePasswordRequest, ConnectAccountRequest, CreateInternalUserRequest,
|
||||
DashboardEntryResponse, GetUsersResponse, SignUpRequest, SignUpWithMerchantIdRequest,
|
||||
SwitchMerchantIdRequest, UserMerchantCreate,
|
||||
};
|
||||
|
||||
impl ApiEventMetric for ConnectAccountResponse {
|
||||
impl ApiEventMetric for DashboardEntryResponse {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::User {
|
||||
merchant_id: self.merchant_id.clone(),
|
||||
@ -19,9 +20,9 @@ impl ApiEventMetric for ConnectAccountResponse {
|
||||
}
|
||||
}
|
||||
|
||||
impl ApiEventMetric for ConnectAccountRequest {}
|
||||
|
||||
common_utils::impl_misc_api_event_type!(
|
||||
SignUpRequest,
|
||||
SignUpWithMerchantIdRequest,
|
||||
ChangePasswordRequest,
|
||||
GetMultipleMetaDataPayload,
|
||||
GetMetaDataResponse,
|
||||
@ -30,7 +31,9 @@ common_utils::impl_misc_api_event_type!(
|
||||
SwitchMerchantIdRequest,
|
||||
CreateInternalUserRequest,
|
||||
UserMerchantCreate,
|
||||
GetUsersResponse
|
||||
GetUsersResponse,
|
||||
AuthorizeResponse,
|
||||
ConnectAccountRequest
|
||||
);
|
||||
|
||||
#[cfg(feature = "dummy_connector")]
|
||||
|
||||
@ -7,13 +7,25 @@ pub mod dashboard_metadata;
|
||||
pub mod sample_data;
|
||||
|
||||
#[derive(serde::Deserialize, Debug, Clone, serde::Serialize)]
|
||||
pub struct ConnectAccountRequest {
|
||||
pub struct SignUpWithMerchantIdRequest {
|
||||
pub name: Secret<String>,
|
||||
pub email: pii::Email,
|
||||
pub password: Secret<String>,
|
||||
pub company_name: String,
|
||||
}
|
||||
|
||||
pub type SignUpWithMerchantIdResponse = AuthorizeResponse;
|
||||
|
||||
#[derive(serde::Deserialize, Debug, Clone, serde::Serialize)]
|
||||
pub struct SignUpRequest {
|
||||
pub email: pii::Email,
|
||||
pub password: Secret<String>,
|
||||
}
|
||||
|
||||
pub type SignUpResponse = DashboardEntryResponse;
|
||||
|
||||
#[derive(serde::Serialize, Debug, Clone)]
|
||||
pub struct ConnectAccountResponse {
|
||||
pub struct DashboardEntryResponse {
|
||||
pub token: Secret<String>,
|
||||
pub merchant_id: String,
|
||||
pub name: Secret<String>,
|
||||
@ -25,6 +37,28 @@ pub struct ConnectAccountResponse {
|
||||
pub user_id: String,
|
||||
}
|
||||
|
||||
pub type SignInRequest = SignUpRequest;
|
||||
|
||||
pub type SignInResponse = DashboardEntryResponse;
|
||||
|
||||
#[derive(serde::Deserialize, Debug, Clone, serde::Serialize)]
|
||||
pub struct ConnectAccountRequest {
|
||||
pub email: pii::Email,
|
||||
}
|
||||
|
||||
pub type ConnectAccountResponse = AuthorizeResponse;
|
||||
|
||||
#[derive(serde::Serialize, Debug, Clone)]
|
||||
pub struct AuthorizeResponse {
|
||||
pub is_email_sent: bool,
|
||||
//this field is added for audit/debug reasons
|
||||
#[serde(skip_serializing)]
|
||||
pub user_id: String,
|
||||
//this field is added for audit/debug reasons
|
||||
#[serde(skip_serializing)]
|
||||
pub merchant_id: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, serde::Serialize)]
|
||||
pub struct ChangePasswordRequest {
|
||||
pub new_password: Secret<String>,
|
||||
@ -36,6 +70,8 @@ pub struct SwitchMerchantIdRequest {
|
||||
pub merchant_id: String,
|
||||
}
|
||||
|
||||
pub type SwitchMerchantResponse = DashboardEntryResponse;
|
||||
|
||||
#[derive(serde::Deserialize, Debug, serde::Serialize)]
|
||||
pub struct CreateInternalUserRequest {
|
||||
pub name: Secret<String>,
|
||||
|
||||
@ -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,15 +189,6 @@ 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;
|
||||
|
||||
use crate::services::email::types as email_types;
|
||||
|
||||
let email_contents = email_types::VerifyEmail {
|
||||
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
|
||||
@ -98,21 +205,19 @@ pub async fn connect_account(
|
||||
.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 {
|
||||
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,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
@ -823,10 +823,7 @@ impl User {
|
||||
let mut route = web::scope("/user").app_data(web::Data::new(state));
|
||||
|
||||
route = route
|
||||
.service(web::resource("/signin").route(web::post().to(user_connect_account)))
|
||||
.service(web::resource("/signup").route(web::post().to(user_connect_account)))
|
||||
.service(web::resource("/v2/signin").route(web::post().to(user_connect_account)))
|
||||
.service(web::resource("/v2/signup").route(web::post().to(user_connect_account)))
|
||||
.service(web::resource("/signin").route(web::post().to(user_signin)))
|
||||
.service(web::resource("/change_password").route(web::post().to(change_password)))
|
||||
.service(
|
||||
web::resource("/data/merchant")
|
||||
@ -841,7 +838,6 @@ impl User {
|
||||
)
|
||||
.service(web::resource("/switch/list").route(web::get().to(list_merchant_ids_for_user)))
|
||||
.service(web::resource("/user/list").route(web::get().to(get_user_details)))
|
||||
// User Role APIs
|
||||
.service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
|
||||
.service(web::resource("/user/update_role").route(web::post().to(update_user_role)))
|
||||
.service(web::resource("/role/list").route(web::get().to(list_roles)))
|
||||
@ -855,6 +851,21 @@ impl User {
|
||||
.route(web::delete().to(delete_sample_data)),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "email")]
|
||||
{
|
||||
route = route
|
||||
.service(
|
||||
web::resource("/connect_account").route(web::post().to(user_connect_account)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/signup_with_merchant_id")
|
||||
.route(web::post().to(user_signup_with_merchant_id)),
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "email"))]
|
||||
{
|
||||
route = route.service(web::resource("/signup").route(web::post().to(user_signup)))
|
||||
}
|
||||
route
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +149,8 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::GsmRuleDelete => Self::Gsm,
|
||||
|
||||
Flow::UserConnectAccount
|
||||
| Flow::UserSignUp
|
||||
| Flow::UserSignIn
|
||||
| Flow::ChangePassword
|
||||
| Flow::SetDashboardMetadata
|
||||
| Flow::GetMutltipleDashboardMetadata
|
||||
@ -159,7 +161,8 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::GenerateSampleData
|
||||
| Flow::DeleteSampleData
|
||||
| Flow::UserMerchantAccountList
|
||||
| Flow::GetUserDetails => Self::User,
|
||||
| Flow::GetUserDetails
|
||||
| Flow::UserSignUpWithMerchantId => Self::User,
|
||||
|
||||
Flow::ListRoles | Flow::GetRole | Flow::UpdateUserRole | Flow::GetAuthorizationInfo => {
|
||||
Self::UserRole
|
||||
|
||||
@ -19,6 +19,65 @@ use crate::{
|
||||
utils::user::dashboard_metadata::{parse_string_to_enums, set_ip_address_if_required},
|
||||
};
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn user_signup_with_merchant_id(
|
||||
state: web::Data<AppState>,
|
||||
http_req: HttpRequest,
|
||||
json_payload: web::Json<user_api::SignUpWithMerchantIdRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::UserSignUpWithMerchantId;
|
||||
let req_payload = json_payload.into_inner();
|
||||
Box::pin(api::server_wrap(
|
||||
flow.clone(),
|
||||
state,
|
||||
&http_req,
|
||||
req_payload.clone(),
|
||||
|state, _, req_body| user_core::signup_with_merchant_id(state, req_body),
|
||||
&auth::NoAuth,
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn user_signup(
|
||||
state: web::Data<AppState>,
|
||||
http_req: HttpRequest,
|
||||
json_payload: web::Json<user_api::SignUpRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::UserSignUp;
|
||||
let req_payload = json_payload.into_inner();
|
||||
Box::pin(api::server_wrap(
|
||||
flow.clone(),
|
||||
state,
|
||||
&http_req,
|
||||
req_payload.clone(),
|
||||
|state, _, req_body| user_core::signup(state, req_body),
|
||||
&auth::NoAuth,
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn user_signin(
|
||||
state: web::Data<AppState>,
|
||||
http_req: HttpRequest,
|
||||
json_payload: web::Json<user_api::SignInRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::UserSignIn;
|
||||
let req_payload = json_payload.into_inner();
|
||||
Box::pin(api::server_wrap(
|
||||
flow.clone(),
|
||||
state,
|
||||
&http_req,
|
||||
req_payload.clone(),
|
||||
|state, _, req_body| user_core::signin(state, req_body),
|
||||
&auth::NoAuth,
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn user_connect_account(
|
||||
state: web::Data<AppState>,
|
||||
http_req: HttpRequest,
|
||||
|
||||
@ -26,7 +26,7 @@ use crate::{
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services::{
|
||||
authentication::{AuthToken, UserFromToken},
|
||||
authentication::UserFromToken,
|
||||
authorization::{info, predefined_permissions},
|
||||
},
|
||||
types::transformers::ForeignFrom,
|
||||
@ -215,6 +215,25 @@ impl NewUserOrganization {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::SignUpWithMerchantIdRequest> for NewUserOrganization {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
fn try_from(value: user_api::SignUpWithMerchantIdRequest) -> UserResult<Self> {
|
||||
let new_organization = api_org::OrganizationNew::new(Some(
|
||||
UserCompanyName::new(value.company_name)?.get_secret(),
|
||||
));
|
||||
let db_organization = ForeignFrom::foreign_from(new_organization);
|
||||
Ok(Self(db_organization))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<user_api::SignUpRequest> for NewUserOrganization {
|
||||
fn from(_value: user_api::SignUpRequest) -> Self {
|
||||
let new_organization = api_org::OrganizationNew::new(None);
|
||||
let db_organization = ForeignFrom::foreign_from(new_organization);
|
||||
Self(db_organization)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<user_api::ConnectAccountRequest> for NewUserOrganization {
|
||||
fn from(_value: user_api::ConnectAccountRequest) -> Self {
|
||||
let new_organization = api_org::OrganizationNew::new(None);
|
||||
@ -334,6 +353,24 @@ impl NewUserMerchant {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::SignUpRequest> for NewUserMerchant {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
fn try_from(value: user_api::SignUpRequest) -> UserResult<Self> {
|
||||
let merchant_id = MerchantId::new(format!(
|
||||
"merchant_{}",
|
||||
common_utils::date_time::now_unix_timestamp()
|
||||
))?;
|
||||
let new_organization = NewUserOrganization::from(value);
|
||||
|
||||
Ok(Self {
|
||||
company_name: None,
|
||||
merchant_id,
|
||||
new_organization,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::ConnectAccountRequest> for NewUserMerchant {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
@ -352,6 +389,21 @@ impl TryFrom<user_api::ConnectAccountRequest> for NewUserMerchant {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::SignUpWithMerchantIdRequest> for NewUserMerchant {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
fn try_from(value: user_api::SignUpWithMerchantIdRequest) -> UserResult<Self> {
|
||||
let company_name = Some(UserCompanyName::new(value.company_name.clone())?);
|
||||
let merchant_id = MerchantId::new(value.company_name.clone())?;
|
||||
let new_organization = NewUserOrganization::try_from(value)?;
|
||||
|
||||
Ok(Self {
|
||||
company_name,
|
||||
merchant_id,
|
||||
new_organization,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::CreateInternalUserRequest> for NewUserMerchant {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
@ -434,10 +486,23 @@ impl NewUser {
|
||||
.attach_printable("Error while inserting user")
|
||||
}
|
||||
|
||||
pub async fn check_if_already_exists_in_db(&self, state: AppState) -> UserResult<()> {
|
||||
if state
|
||||
.store
|
||||
.find_user_by_email(self.get_email().into_inner().expose().expose().as_str())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(UserErrors::UserExists).into_report();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_user_and_merchant_in_db(
|
||||
&self,
|
||||
state: AppState,
|
||||
) -> UserResult<UserFromStorage> {
|
||||
self.check_if_already_exists_in_db(state.clone()).await?;
|
||||
let db = state.store.as_ref();
|
||||
let merchant_id = self.get_new_merchant().get_merchant_id();
|
||||
self.new_merchant
|
||||
@ -495,6 +560,46 @@ impl TryFrom<NewUser> for storage_user::UserNew {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::SignUpWithMerchantIdRequest> for NewUser {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
fn try_from(value: user_api::SignUpWithMerchantIdRequest) -> UserResult<Self> {
|
||||
let email = value.email.clone().try_into()?;
|
||||
let name = UserName::new(value.name.clone())?;
|
||||
let password = UserPassword::new(value.password.clone())?;
|
||||
let user_id = uuid::Uuid::new_v4().to_string();
|
||||
let new_merchant = NewUserMerchant::try_from(value)?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
user_id,
|
||||
new_merchant,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::SignUpRequest> for NewUser {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
fn try_from(value: user_api::SignUpRequest) -> UserResult<Self> {
|
||||
let user_id = uuid::Uuid::new_v4().to_string();
|
||||
let email = value.email.clone().try_into()?;
|
||||
let name = UserName::try_from(value.email.clone())?;
|
||||
let password = UserPassword::new(value.password.clone())?;
|
||||
let new_merchant = NewUserMerchant::try_from(value)?;
|
||||
|
||||
Ok(Self {
|
||||
user_id,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
new_merchant,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<user_api::ConnectAccountRequest> for NewUser {
|
||||
type Error = error_stack::Report<UserErrors>;
|
||||
|
||||
@ -502,7 +607,7 @@ impl TryFrom<user_api::ConnectAccountRequest> for NewUser {
|
||||
let user_id = uuid::Uuid::new_v4().to_string();
|
||||
let email = value.email.clone().try_into()?;
|
||||
let name = UserName::try_from(value.email.clone())?;
|
||||
let password = UserPassword::new(value.password.clone())?;
|
||||
let password = UserPassword::new(uuid::Uuid::new_v4().to_string().into())?;
|
||||
let new_merchant = NewUserMerchant::try_from(value)?;
|
||||
|
||||
Ok(Self {
|
||||
@ -582,41 +687,6 @@ impl UserFromStorage {
|
||||
self.0.email.clone()
|
||||
}
|
||||
|
||||
pub async fn get_jwt_auth_token(&self, state: AppState, org_id: String) -> UserResult<String> {
|
||||
let role_id = self.get_role_from_db(state.clone()).await?.role_id;
|
||||
let merchant_id = state
|
||||
.store
|
||||
.find_user_role_by_user_id(self.get_user_id())
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.merchant_id;
|
||||
AuthToken::new_token(
|
||||
self.0.user_id.clone(),
|
||||
merchant_id,
|
||||
role_id,
|
||||
&state.conf,
|
||||
org_id,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_jwt_auth_token_with_custom_merchant_id(
|
||||
&self,
|
||||
state: AppState,
|
||||
merchant_id: String,
|
||||
org_id: String,
|
||||
) -> UserResult<String> {
|
||||
let role_id = self.get_role_from_db(state.clone()).await?.role_id;
|
||||
AuthToken::new_token(
|
||||
self.0.user_id.clone(),
|
||||
merchant_id,
|
||||
role_id,
|
||||
&state.conf,
|
||||
org_id,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_role_from_db(&self, state: AppState) -> UserResult<UserRole> {
|
||||
state
|
||||
.store
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
use diesel_models::enums::UserStatus;
|
||||
use api_models::user as user_api;
|
||||
use diesel_models::{enums::UserStatus, user_role::UserRole};
|
||||
use error_stack::ResultExt;
|
||||
use masking::Secret;
|
||||
|
||||
use crate::{
|
||||
core::errors::{UserErrors, UserResult},
|
||||
routes::AppState,
|
||||
services::authentication::UserFromToken,
|
||||
types::domain::MerchantAccount,
|
||||
services::authentication::{AuthToken, UserFromToken},
|
||||
types::domain::{MerchantAccount, UserFromStorage},
|
||||
};
|
||||
|
||||
pub mod dashboard_metadata;
|
||||
@ -68,3 +70,52 @@ pub async fn get_merchant_ids_for_user(state: AppState, user_id: &str) -> UserRe
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn generate_jwt_auth_token(
|
||||
state: AppState,
|
||||
user: &UserFromStorage,
|
||||
user_role: &UserRole,
|
||||
) -> UserResult<Secret<String>> {
|
||||
let token = AuthToken::new_token(
|
||||
user.get_user_id().to_string(),
|
||||
user_role.merchant_id.clone(),
|
||||
user_role.role_id.clone(),
|
||||
&state.conf,
|
||||
user_role.org_id.clone(),
|
||||
)
|
||||
.await?;
|
||||
Ok(Secret::new(token))
|
||||
}
|
||||
|
||||
pub async fn generate_jwt_auth_token_with_custom_merchant_id(
|
||||
state: AppState,
|
||||
user: &UserFromStorage,
|
||||
user_role: &UserRole,
|
||||
merchant_id: String,
|
||||
) -> UserResult<Secret<String>> {
|
||||
let token = AuthToken::new_token(
|
||||
user.get_user_id().to_string(),
|
||||
merchant_id,
|
||||
user_role.role_id.clone(),
|
||||
&state.conf,
|
||||
user_role.org_id.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
Ok(Secret::new(token))
|
||||
}
|
||||
|
||||
pub fn get_dashboard_entry_response(
|
||||
user: UserFromStorage,
|
||||
user_role: UserRole,
|
||||
token: Secret<String>,
|
||||
) -> user_api::DashboardEntryResponse {
|
||||
user_api::DashboardEntryResponse {
|
||||
merchant_id: user_role.merchant_id,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,6 +249,12 @@ pub enum Flow {
|
||||
GsmRuleUpdate,
|
||||
/// Gsm Rule Delete flow
|
||||
GsmRuleDelete,
|
||||
/// User Sign Up
|
||||
UserSignUp,
|
||||
/// User Sign Up
|
||||
UserSignUpWithMerchantId,
|
||||
/// User Sign In
|
||||
UserSignIn,
|
||||
/// User connect account
|
||||
UserConnectAccount,
|
||||
/// Upsert Decision Manager Config
|
||||
|
||||
Reference in New Issue
Block a user