mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
refactor(users): Add V2 user_roles data support (#5763)
Co-authored-by: Apoorv Dixit <apoorv.dixit@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -121,42 +121,10 @@ pub async fn get_user_details(
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn signup(
|
||||
state: SessionState,
|
||||
request: user_api::SignUpRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<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_org_level_user_role_in_db(
|
||||
state.clone(),
|
||||
common_utils::consts::ROLE_ID_ORGANIZATION_ADMIN.to_string(),
|
||||
UserStatus::Active,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
utils::user_role::set_role_permissions_in_cache_by_user_role(&state, &user_role).await;
|
||||
|
||||
let token =
|
||||
utils::user::generate_jwt_auth_token_without_profile(&state, &user_from_db, &user_role)
|
||||
.await?;
|
||||
let response =
|
||||
utils::user::get_dashboard_entry_response(&state, user_from_db, user_role, token.clone())?;
|
||||
|
||||
auth::cookies::set_cookie_response(user_api::TokenOrPayloadResponse::Payload(response), token)
|
||||
}
|
||||
|
||||
pub async fn signup_token_only_flow(
|
||||
state: SessionState,
|
||||
request: user_api::SignUpRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::SignUpResponse>> {
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
let new_user = domain::NewUser::try_from(request)?;
|
||||
new_user
|
||||
.get_new_merchant()
|
||||
@ -182,61 +150,17 @@ pub async fn signup_token_only_flow(
|
||||
.get_token_with_user_role(&state, &user_role)
|
||||
.await?;
|
||||
|
||||
let response = user_api::TokenOrPayloadResponse::Token(user_api::TokenResponse {
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: next_flow.get_flow().into(),
|
||||
});
|
||||
};
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
pub async fn signin(
|
||||
state: SessionState,
|
||||
request: user_api::SignInRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::SignInResponse>> {
|
||||
let user_from_db: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.find_user_by_email(&request.email)
|
||||
.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 signin_strategy =
|
||||
if let Some(preferred_merchant_id) = user_from_db.get_preferred_merchant_id() {
|
||||
let preferred_role = user_from_db
|
||||
.get_role_from_db_by_merchant_id(&state, &preferred_merchant_id)
|
||||
.await
|
||||
.to_not_found_response(UserErrors::InternalServerError)
|
||||
.attach_printable("User role with preferred_merchant_id not found")?;
|
||||
domain::SignInWithRoleStrategyType::SingleRole(domain::SignInWithSingleRoleStrategy {
|
||||
user: user_from_db,
|
||||
user_role: Box::new(preferred_role),
|
||||
})
|
||||
} else {
|
||||
let user_roles = user_from_db.get_roles_from_db(&state).await?;
|
||||
domain::SignInWithRoleStrategyType::decide_signin_strategy_by_user_roles(
|
||||
user_from_db,
|
||||
user_roles,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
let response = signin_strategy.get_signin_response(&state).await?;
|
||||
let token = utils::user::get_token_from_signin_response(&response);
|
||||
auth::cookies::set_cookie_response(user_api::TokenOrPayloadResponse::Payload(response), token)
|
||||
}
|
||||
|
||||
pub async fn signin_token_only_flow(
|
||||
state: SessionState,
|
||||
request: user_api::SignInRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::SignInResponse>> {
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
let user_from_db: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.find_user_by_email(&request.email)
|
||||
@ -251,10 +175,10 @@ pub async fn signin_token_only_flow(
|
||||
|
||||
let token = next_flow.get_token(&state).await?;
|
||||
|
||||
let response = user_api::TokenOrPayloadResponse::Token(user_api::TokenResponse {
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: next_flow.get_flow().into(),
|
||||
});
|
||||
};
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
@ -573,105 +497,11 @@ pub async fn reset_password_token_only_flow(
|
||||
auth::cookies::remove_cookie_response()
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn reset_password(
|
||||
state: SessionState,
|
||||
request: user_api::ResetPasswordRequest,
|
||||
) -> UserResponse<()> {
|
||||
let token = request.token.expose();
|
||||
let email_token = auth::decode_jwt::<email_types::EmailToken>(&token, &state)
|
||||
.await
|
||||
.change_context(UserErrors::LinkInvalid)?;
|
||||
|
||||
auth::blacklist::check_email_token_in_blacklist(&state, &token).await?;
|
||||
|
||||
let password = domain::UserPassword::new(request.password)?;
|
||||
let hash_password = utils::user::password::generate_password_hash(password.get_secret())?;
|
||||
|
||||
let user = state
|
||||
.global_store
|
||||
.update_user_by_email(
|
||||
&email_token
|
||||
.get_email()
|
||||
.change_context(UserErrors::InternalServerError)?,
|
||||
storage_user::UserUpdate::PasswordUpdate {
|
||||
password: hash_password,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
if let Some(inviter_merchant_id) = email_token.get_merchant_id() {
|
||||
let key_manager_state = &(&state).into();
|
||||
|
||||
let key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
inviter_merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("merchant_key_store not found")?;
|
||||
|
||||
let merchant_account = state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
inviter_merchant_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("merchant_account not found")?;
|
||||
|
||||
let (update_v1_result, update_v2_result) =
|
||||
utils::user_role::update_v1_and_v2_user_roles_in_db(
|
||||
&state,
|
||||
user.user_id.clone().as_str(),
|
||||
&merchant_account.organization_id,
|
||||
inviter_merchant_id,
|
||||
None,
|
||||
UserRoleUpdate::UpdateStatus {
|
||||
status: UserStatus::Active,
|
||||
modified_by: user.user_id.clone(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
if update_v1_result
|
||||
.as_ref()
|
||||
.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
|| update_v2_result
|
||||
.as_ref()
|
||||
.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
{
|
||||
return Err(report!(UserErrors::InternalServerError));
|
||||
}
|
||||
|
||||
if update_v1_result.is_err() && update_v2_result.is_err() {
|
||||
return Err(report!(UserErrors::InvalidRoleOperation))
|
||||
.attach_printable("User not found in the organization")?;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = auth::blacklist::insert_email_token_in_blacklist(&state, &token)
|
||||
.await
|
||||
.map_err(|error| logger::error!(?error));
|
||||
let _ = auth::blacklist::insert_user_in_blacklist(&state, &user.user_id)
|
||||
.await
|
||||
.map_err(|error| logger::error!(?error));
|
||||
|
||||
auth::cookies::remove_cookie_response()
|
||||
}
|
||||
|
||||
pub async fn invite_multiple_user(
|
||||
state: SessionState,
|
||||
user_from_token: auth::UserFromToken,
|
||||
requests: Vec<user_api::InviteUserRequest>,
|
||||
req_state: ReqState,
|
||||
is_token_only: Option<bool>,
|
||||
auth_id: Option<String>,
|
||||
) -> UserResponse<Vec<InviteMultipleUserResponse>> {
|
||||
if requests.len() > 10 {
|
||||
@ -680,16 +510,7 @@ pub async fn invite_multiple_user(
|
||||
}
|
||||
|
||||
let responses = futures::future::join_all(requests.iter().map(|request| async {
|
||||
match handle_invitation(
|
||||
&state,
|
||||
&user_from_token,
|
||||
request,
|
||||
&req_state,
|
||||
is_token_only,
|
||||
&auth_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
match handle_invitation(&state, &user_from_token, request, &req_state, &auth_id).await {
|
||||
Ok(response) => response,
|
||||
Err(error) => InviteMultipleUserResponse {
|
||||
email: request.email.clone(),
|
||||
@ -709,7 +530,6 @@ async fn handle_invitation(
|
||||
user_from_token: &auth::UserFromToken,
|
||||
request: &user_api::InviteUserRequest,
|
||||
req_state: &ReqState,
|
||||
is_token_only: Option<bool>,
|
||||
auth_id: &Option<String>,
|
||||
) -> UserResult<InviteMultipleUserResponse> {
|
||||
let inviter_user = user_from_token.get_user_from_db(state).await?;
|
||||
@ -756,15 +576,8 @@ async fn handle_invitation(
|
||||
.err()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
handle_new_user_invitation(
|
||||
state,
|
||||
user_from_token,
|
||||
request,
|
||||
req_state.clone(),
|
||||
is_token_only,
|
||||
auth_id,
|
||||
)
|
||||
.await
|
||||
handle_new_user_invitation(state, user_from_token, request, req_state.clone(), auth_id)
|
||||
.await
|
||||
} else {
|
||||
Err(UserErrors::InternalServerError.into())
|
||||
}
|
||||
@ -877,7 +690,6 @@ async fn handle_new_user_invitation(
|
||||
user_from_token: &auth::UserFromToken,
|
||||
request: &user_api::InviteUserRequest,
|
||||
req_state: ReqState,
|
||||
is_token_only: Option<bool>,
|
||||
auth_id: &Option<String>,
|
||||
) -> UserResult<InviteMultipleUserResponse> {
|
||||
let new_user = domain::NewUser::try_from((request.clone(), user_from_token.clone()))?;
|
||||
@ -912,8 +724,6 @@ async fn handle_new_user_invitation(
|
||||
.await?;
|
||||
|
||||
let is_email_sent;
|
||||
// TODO: Adding this to avoid clippy lints, remove this once the token only flow is being used
|
||||
let _ = is_token_only;
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
{
|
||||
@ -921,8 +731,7 @@ async fn handle_new_user_invitation(
|
||||
// Will be adding actual usage for this variable later
|
||||
let _ = req_state.clone();
|
||||
let invitee_email = domain::UserEmail::from_pii_email(request.email.clone())?;
|
||||
let email_contents: Box<dyn EmailData + Send + 'static> = if let Some(true) = is_token_only
|
||||
{
|
||||
let email_contents: Box<dyn EmailData + Send + 'static> =
|
||||
Box::new(email_types::InviteRegisteredUser {
|
||||
recipient_email: invitee_email,
|
||||
user_name: domain::UserName::new(new_user.get_name())?,
|
||||
@ -930,17 +739,7 @@ async fn handle_new_user_invitation(
|
||||
subject: "You have been invited to join Hyperswitch Community!",
|
||||
merchant_id: user_from_token.merchant_id.clone(),
|
||||
auth_id: auth_id.clone(),
|
||||
})
|
||||
} else {
|
||||
Box::new(email_types::InviteUser {
|
||||
recipient_email: invitee_email,
|
||||
user_name: domain::UserName::new(new_user.get_name())?,
|
||||
settings: state.conf.clone(),
|
||||
subject: "You have been invited to join Hyperswitch Community!",
|
||||
merchant_id: user_from_token.merchant_id.clone(),
|
||||
auth_id: auth_id.clone(),
|
||||
})
|
||||
};
|
||||
});
|
||||
let send_email_result = state
|
||||
.email_client
|
||||
.compose_and_send_email(email_contents, state.conf.proxy.https_url.as_ref())
|
||||
@ -1047,115 +846,12 @@ pub async fn resend_invite(
|
||||
Ok(ApplicationResponse::StatusOk)
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn accept_invite_from_email(
|
||||
state: SessionState,
|
||||
request: user_api::AcceptInviteFromEmailRequest,
|
||||
) -> UserResponse<user_api::DashboardEntryResponse> {
|
||||
let token = request.token.expose();
|
||||
|
||||
let email_token = auth::decode_jwt::<email_types::EmailToken>(&token, &state)
|
||||
.await
|
||||
.change_context(UserErrors::LinkInvalid)?;
|
||||
|
||||
auth::blacklist::check_email_token_in_blacklist(&state, &token).await?;
|
||||
|
||||
let user: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.find_user_by_email(
|
||||
&email_token
|
||||
.get_email()
|
||||
.change_context(UserErrors::InternalServerError)?,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into();
|
||||
|
||||
let merchant_id = email_token
|
||||
.get_merchant_id()
|
||||
.ok_or(UserErrors::InternalServerError)?;
|
||||
|
||||
let key_manager_state = &(&state).into();
|
||||
|
||||
let key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("merchant_key_store not found")?;
|
||||
|
||||
let merchant_account = state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("merchant_account not found")?;
|
||||
|
||||
let (update_v1_result, update_v2_result) = utils::user_role::update_v1_and_v2_user_roles_in_db(
|
||||
&state,
|
||||
user.get_user_id(),
|
||||
&merchant_account.organization_id,
|
||||
merchant_id,
|
||||
None,
|
||||
UserRoleUpdate::UpdateStatus {
|
||||
status: UserStatus::Active,
|
||||
modified_by: user.get_user_id().to_string(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
if update_v1_result
|
||||
.as_ref()
|
||||
.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
|| update_v2_result
|
||||
.as_ref()
|
||||
.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
{
|
||||
return Err(report!(UserErrors::InternalServerError));
|
||||
}
|
||||
|
||||
if update_v1_result.is_err() && update_v2_result.is_err() {
|
||||
return Err(report!(UserErrors::InvalidRoleOperation))
|
||||
.attach_printable("User not found in the organization")?;
|
||||
}
|
||||
|
||||
let _ = auth::blacklist::insert_email_token_in_blacklist(&state, &token)
|
||||
.await
|
||||
.map_err(|error| logger::error!(?error));
|
||||
|
||||
let user_from_db: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.update_user_by_user_id(user.get_user_id(), storage_user::UserUpdate::VerifyUser)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into();
|
||||
|
||||
let user_role = user_from_db
|
||||
.get_preferred_or_active_user_role_from_db(&state)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
let token =
|
||||
utils::user::generate_jwt_auth_token_without_profile(&state, &user_from_db, &user_role)
|
||||
.await?;
|
||||
utils::user_role::set_role_permissions_in_cache_by_user_role(&state, &user_role).await;
|
||||
|
||||
let response =
|
||||
utils::user::get_dashboard_entry_response(&state, user_from_db, user_role, token.clone())?;
|
||||
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn accept_invite_from_email_token_only_flow(
|
||||
state: SessionState,
|
||||
user_token: auth::UserFromSinglePurposeToken,
|
||||
request: user_api::AcceptInviteFromEmailRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
let token = request.token.expose();
|
||||
|
||||
let email_token = auth::decode_jwt::<email_types::EmailToken>(&token, &state)
|
||||
@ -1261,10 +957,10 @@ pub async fn accept_invite_from_email_token_only_flow(
|
||||
.get_token_with_user_role(&state, &user_role)
|
||||
.await?;
|
||||
|
||||
let response = user_api::TokenOrPayloadResponse::Token(user_api::TokenResponse {
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: next_flow.get_flow().into(),
|
||||
});
|
||||
};
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
@ -1503,7 +1199,7 @@ pub async fn list_merchants_for_user(
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
let merchant_accounts = state
|
||||
let merchant_accounts_map = state
|
||||
.store
|
||||
.list_multiple_merchant_accounts(
|
||||
&(&state).into(),
|
||||
@ -1517,17 +1213,62 @@ pub async fn list_merchants_for_user(
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.map(|merchant_account| (merchant_account.get_id().clone(), merchant_account))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let roles =
|
||||
utils::user_role::get_multiple_role_info_for_user_roles(&state, &user_roles).await?;
|
||||
let roles_map = futures::future::try_join_all(user_roles.iter().map(|user_role| async {
|
||||
let Some(merchant_id) = &user_role.merchant_id else {
|
||||
return Err(report!(UserErrors::InternalServerError))
|
||||
.attach_printable("merchant_id not found for user_role");
|
||||
};
|
||||
let Some(org_id) = &user_role.org_id else {
|
||||
return Err(report!(UserErrors::InternalServerError)
|
||||
.attach_printable("org_id not found in user_role"));
|
||||
};
|
||||
roles::RoleInfo::from_role_id(&state, &user_role.role_id, merchant_id, org_id)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Unable to find role info for user role")
|
||||
}))
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|role_info| (role_info.get_role_id().to_owned(), role_info))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
Ok(ApplicationResponse::Json(
|
||||
utils::user::get_multiple_merchant_details_with_status(
|
||||
user_roles,
|
||||
merchant_accounts,
|
||||
roles,
|
||||
)?,
|
||||
user_roles
|
||||
.into_iter()
|
||||
.map(|user_role| {
|
||||
let Some(merchant_id) = &user_role.merchant_id else {
|
||||
return Err(report!(UserErrors::InternalServerError))
|
||||
.attach_printable("merchant_id not found for user_role");
|
||||
};
|
||||
let Some(org_id) = &user_role.org_id else {
|
||||
return Err(report!(UserErrors::InternalServerError)
|
||||
.attach_printable("org_id not found in user_role"));
|
||||
};
|
||||
let merchant_account = merchant_accounts_map
|
||||
.get(merchant_id)
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("Merchant account for user role doesn't exist")?;
|
||||
|
||||
let role_info = roles_map
|
||||
.get(&user_role.role_id)
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("Role info for user role doesn't exist")?;
|
||||
|
||||
Ok(user_api::UserMerchantAccount {
|
||||
merchant_id: merchant_id.to_owned(),
|
||||
merchant_name: merchant_account.merchant_name.clone(),
|
||||
is_active: user_role.status == UserStatus::Active,
|
||||
role_id: user_role.role_id,
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
org_id: org_id.to_owned(),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
@ -1650,71 +1391,12 @@ pub async fn list_users_for_merchant_account(
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn verify_email(
|
||||
state: SessionState,
|
||||
req: user_api::VerifyEmailRequest,
|
||||
) -> UserResponse<user_api::SignInResponse> {
|
||||
let token = req.token.clone().expose();
|
||||
let email_token = auth::decode_jwt::<email_types::EmailToken>(&token, &state)
|
||||
.await
|
||||
.change_context(UserErrors::LinkInvalid)?;
|
||||
|
||||
auth::blacklist::check_email_token_in_blacklist(&state, &token).await?;
|
||||
|
||||
let user = state
|
||||
.global_store
|
||||
.find_user_by_email(
|
||||
&email_token
|
||||
.get_email()
|
||||
.change_context(UserErrors::InternalServerError)?,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
let user = state
|
||||
.global_store
|
||||
.update_user_by_user_id(user.user_id.as_str(), storage_user::UserUpdate::VerifyUser)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
let user_from_db: domain::UserFromStorage = user.into();
|
||||
|
||||
let signin_strategy =
|
||||
if let Some(preferred_merchant_id) = user_from_db.get_preferred_merchant_id() {
|
||||
let preferred_role = user_from_db
|
||||
.get_role_from_db_by_merchant_id(&state, &preferred_merchant_id)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("User role with preferred_merchant_id not found")?;
|
||||
domain::SignInWithRoleStrategyType::SingleRole(domain::SignInWithSingleRoleStrategy {
|
||||
user: user_from_db,
|
||||
user_role: Box::new(preferred_role),
|
||||
})
|
||||
} else {
|
||||
let user_roles = user_from_db.get_roles_from_db(&state).await?;
|
||||
domain::SignInWithRoleStrategyType::decide_signin_strategy_by_user_roles(
|
||||
user_from_db,
|
||||
user_roles,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
let _ = auth::blacklist::insert_email_token_in_blacklist(&state, &token)
|
||||
.await
|
||||
.map_err(|error| logger::error!(?error));
|
||||
|
||||
let response = signin_strategy.get_signin_response(&state).await?;
|
||||
let token = utils::user::get_token_from_signin_response(&response);
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub async fn verify_email_token_only_flow(
|
||||
state: SessionState,
|
||||
user_token: auth::UserFromSinglePurposeToken,
|
||||
req: user_api::VerifyEmailRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::SignInResponse>> {
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
let token = req.token.clone().expose();
|
||||
let email_token = auth::decode_jwt::<email_types::EmailToken>(&token, &state)
|
||||
.await
|
||||
@ -1754,10 +1436,10 @@ pub async fn verify_email_token_only_flow(
|
||||
let next_flow = current_flow.next(user_from_db, &state).await?;
|
||||
let token = next_flow.get_token(&state).await?;
|
||||
|
||||
let response = user_api::TokenOrPayloadResponse::Token(user_api::TokenResponse {
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: next_flow.get_flow().into(),
|
||||
});
|
||||
};
|
||||
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
@ -2839,24 +2521,7 @@ pub async fn switch_org_for_user(
|
||||
))?
|
||||
.to_owned();
|
||||
|
||||
let merchant_id = if let Some(merchant_id) = &user_role.merchant_id {
|
||||
merchant_id.clone()
|
||||
} else {
|
||||
state
|
||||
.store
|
||||
.list_merchant_accounts_by_organization_id(
|
||||
key_manager_state,
|
||||
request.org_id.get_string_repr(),
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list merchant accounts by organization_id")?
|
||||
.first()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No merchant account found for the given organization_id")?
|
||||
.get_id()
|
||||
.clone()
|
||||
};
|
||||
let merchant_id = utils::user_role::get_single_merchant_id(&state, &user_role).await?;
|
||||
|
||||
let profile_id = if let Some(profile_id) = &user_role.profile_id {
|
||||
profile_id.clone()
|
||||
|
||||
@ -24,20 +24,6 @@ pub mod role;
|
||||
use common_enums::{EntityType, PermissionGroup};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
// TODO: To be deprecated once groups are stable
|
||||
pub async fn get_authorization_info_with_modules(
|
||||
_state: SessionState,
|
||||
) -> UserResponse<user_role_api::AuthorizationInfoResponse> {
|
||||
Ok(ApplicationResponse::Json(
|
||||
user_role_api::AuthorizationInfoResponse(
|
||||
info::get_module_authorization_info()
|
||||
.into_iter()
|
||||
.map(|module_info| user_role_api::AuthorizationInfo::Module(module_info.into()))
|
||||
.collect(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_authorization_info_with_groups(
|
||||
_state: SessionState,
|
||||
) -> UserResponse<user_role_api::AuthorizationInfoResponse> {
|
||||
@ -50,6 +36,7 @@ pub async fn get_authorization_info_with_groups(
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_authorization_info_with_group_tag(
|
||||
) -> UserResponse<user_role_api::AuthorizationInfoResponse> {
|
||||
static GROUPS_WITH_PARENT_TAGS: Lazy<Vec<user_role_api::ParentInfo>> = Lazy::new(|| {
|
||||
@ -309,85 +296,11 @@ pub async fn accept_invitation(
|
||||
Ok(ApplicationResponse::StatusOk)
|
||||
}
|
||||
|
||||
pub async fn merchant_select(
|
||||
state: SessionState,
|
||||
user_token: auth::UserFromSinglePurposeToken,
|
||||
req: user_role_api::MerchantSelectRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
||||
let merchant_accounts = state
|
||||
.store
|
||||
.list_multiple_merchant_accounts(&(&state).into(), req.merchant_ids)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
let update_result =
|
||||
futures::future::join_all(merchant_accounts.iter().map(|merchant_account| async {
|
||||
let (update_v1_result, update_v2_result) =
|
||||
utils::user_role::update_v1_and_v2_user_roles_in_db(
|
||||
&state,
|
||||
user_token.user_id.as_str(),
|
||||
&merchant_account.organization_id,
|
||||
merchant_account.get_id(),
|
||||
None,
|
||||
UserRoleUpdate::UpdateStatus {
|
||||
status: UserStatus::Active,
|
||||
modified_by: user_token.user_id.clone(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
if update_v1_result.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
|| update_v2_result.is_err_and(|err| !err.current_context().is_db_not_found())
|
||||
{
|
||||
Err(report!(UserErrors::InternalServerError))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}))
|
||||
.await;
|
||||
|
||||
if update_result.iter().all(Result::is_err) {
|
||||
return Err(UserErrors::MerchantIdNotFound.into());
|
||||
}
|
||||
|
||||
if let Some(true) = req.need_dashboard_entry_response {
|
||||
let user_from_db: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.find_user_by_id(user_token.user_id.as_str())
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into();
|
||||
|
||||
let user_role = user_from_db
|
||||
.get_preferred_or_active_user_role_from_db(&state)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?;
|
||||
|
||||
utils::user_role::set_role_permissions_in_cache_by_user_role(&state, &user_role).await;
|
||||
|
||||
let token =
|
||||
utils::user::generate_jwt_auth_token_without_profile(&state, &user_from_db, &user_role)
|
||||
.await?;
|
||||
let response = utils::user::get_dashboard_entry_response(
|
||||
&state,
|
||||
user_from_db,
|
||||
user_role,
|
||||
token.clone(),
|
||||
)?;
|
||||
return auth::cookies::set_cookie_response(
|
||||
user_api::TokenOrPayloadResponse::Payload(response),
|
||||
token,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(ApplicationResponse::StatusOk)
|
||||
}
|
||||
|
||||
pub async fn merchant_select_token_only_flow(
|
||||
state: SessionState,
|
||||
user_token: auth::UserFromSinglePurposeToken,
|
||||
req: user_role_api::MerchantSelectRequest,
|
||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
let merchant_accounts = state
|
||||
.store
|
||||
.list_multiple_merchant_accounts(&(&state).into(), req.merchant_ids)
|
||||
@ -444,10 +357,10 @@ pub async fn merchant_select_token_only_flow(
|
||||
.get_token_with_user_role(&state, &user_role)
|
||||
.await?;
|
||||
|
||||
let response = user_api::TokenOrPayloadResponse::Token(user_api::TokenResponse {
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: next_flow.get_flow().into(),
|
||||
});
|
||||
};
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
|
||||
@ -16,30 +16,10 @@ use crate::{
|
||||
utils,
|
||||
};
|
||||
|
||||
pub async fn get_role_from_token_with_permissions(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
) -> UserResponse<role_api::GetRoleFromTokenResponse> {
|
||||
let role_info = user_from_token
|
||||
.get_role_info_from_db(&state)
|
||||
.await
|
||||
.attach_printable("Invalid role_id in JWT")?;
|
||||
|
||||
let permissions = role_info
|
||||
.get_permissions_set()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
|
||||
Ok(ApplicationResponse::Json(
|
||||
role_api::GetRoleFromTokenResponse::Permissions(permissions),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_role_from_token_with_groups(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
) -> UserResponse<role_api::GetRoleFromTokenResponse> {
|
||||
) -> UserResponse<Vec<role_api::PermissionGroup>> {
|
||||
let role_info = user_from_token
|
||||
.get_role_info_from_db(&state)
|
||||
.await
|
||||
@ -47,9 +27,7 @@ pub async fn get_role_from_token_with_groups(
|
||||
|
||||
let permissions = role_info.get_permission_groups().to_vec();
|
||||
|
||||
Ok(ApplicationResponse::Json(
|
||||
role_api::GetRoleFromTokenResponse::Groups(permissions),
|
||||
))
|
||||
Ok(ApplicationResponse::Json(permissions))
|
||||
}
|
||||
|
||||
pub async fn create_role(
|
||||
@ -105,56 +83,6 @@ pub async fn create_role(
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: To be deprecated once groups are stable
|
||||
pub async fn list_invitable_roles_with_permissions(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
) -> UserResponse<role_api::ListRolesResponse> {
|
||||
let predefined_roles_map = PREDEFINED_ROLES
|
||||
.iter()
|
||||
.filter(|(_, role_info)| role_info.is_invitable())
|
||||
.map(|(role_id, role_info)| {
|
||||
role_api::RoleInfoResponse::Permissions(role_api::RoleInfoWithPermissionsResponse {
|
||||
permissions: role_info
|
||||
.get_permissions_set()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
role_id: role_id.to_string(),
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
})
|
||||
});
|
||||
|
||||
let custom_roles_map = state
|
||||
.store
|
||||
.list_all_roles(&user_from_token.merchant_id, &user_from_token.org_id)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)?
|
||||
.into_iter()
|
||||
.filter_map(|role| {
|
||||
let role_info = roles::RoleInfo::from(role);
|
||||
role_info
|
||||
.is_invitable()
|
||||
.then_some(role_api::RoleInfoResponse::Permissions(
|
||||
role_api::RoleInfoWithPermissionsResponse {
|
||||
permissions: role_info
|
||||
.get_permissions_set()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
role_id: role_info.get_role_id().to_string(),
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
},
|
||||
))
|
||||
});
|
||||
|
||||
Ok(ApplicationResponse::Json(role_api::ListRolesResponse(
|
||||
predefined_roles_map.chain(custom_roles_map).collect(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub async fn list_invitable_roles_with_groups(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
@ -162,14 +90,14 @@ pub async fn list_invitable_roles_with_groups(
|
||||
let predefined_roles_map = PREDEFINED_ROLES
|
||||
.iter()
|
||||
.filter(|(_, role_info)| role_info.is_invitable())
|
||||
.map(|(role_id, role_info)| {
|
||||
role_api::RoleInfoResponse::Groups(role_api::RoleInfoWithGroupsResponse {
|
||||
.map(
|
||||
|(role_id, role_info)| role_api::RoleInfoWithGroupsResponse {
|
||||
groups: role_info.get_permission_groups().to_vec(),
|
||||
role_id: role_id.to_string(),
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
})
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let custom_roles_map = state
|
||||
.store
|
||||
@ -181,14 +109,12 @@ pub async fn list_invitable_roles_with_groups(
|
||||
let role_info = roles::RoleInfo::from(role);
|
||||
role_info
|
||||
.is_invitable()
|
||||
.then_some(role_api::RoleInfoResponse::Groups(
|
||||
role_api::RoleInfoWithGroupsResponse {
|
||||
groups: role_info.get_permission_groups().to_vec(),
|
||||
role_id: role_info.get_role_id().to_string(),
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
},
|
||||
))
|
||||
.then_some(role_api::RoleInfoWithGroupsResponse {
|
||||
groups: role_info.get_permission_groups().to_vec(),
|
||||
role_id: role_info.get_role_id().to_string(),
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
})
|
||||
});
|
||||
|
||||
Ok(ApplicationResponse::Json(role_api::ListRolesResponse(
|
||||
@ -196,46 +122,11 @@ pub async fn list_invitable_roles_with_groups(
|
||||
)))
|
||||
}
|
||||
|
||||
// TODO: To be deprecated once groups are stable
|
||||
pub async fn get_role_with_permissions(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
role: role_api::GetRoleRequest,
|
||||
) -> UserResponse<role_api::RoleInfoResponse> {
|
||||
let role_info = roles::RoleInfo::from_role_id(
|
||||
&state,
|
||||
&role.role_id,
|
||||
&user_from_token.merchant_id,
|
||||
&user_from_token.org_id,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(UserErrors::InvalidRoleId)?;
|
||||
|
||||
if role_info.is_internal() {
|
||||
return Err(UserErrors::InvalidRoleId.into());
|
||||
}
|
||||
|
||||
let permissions = role_info
|
||||
.get_permissions_set()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
|
||||
Ok(ApplicationResponse::Json(
|
||||
role_api::RoleInfoResponse::Permissions(role_api::RoleInfoWithPermissionsResponse {
|
||||
permissions,
|
||||
role_id: role.role_id,
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_role_with_groups(
|
||||
state: SessionState,
|
||||
user_from_token: UserFromToken,
|
||||
role: role_api::GetRoleRequest,
|
||||
) -> UserResponse<role_api::RoleInfoResponse> {
|
||||
) -> UserResponse<role_api::RoleInfoWithGroupsResponse> {
|
||||
let role_info = roles::RoleInfo::from_role_id(
|
||||
&state,
|
||||
&role.role_id,
|
||||
@ -250,12 +141,12 @@ pub async fn get_role_with_groups(
|
||||
}
|
||||
|
||||
Ok(ApplicationResponse::Json(
|
||||
role_api::RoleInfoResponse::Groups(role_api::RoleInfoWithGroupsResponse {
|
||||
role_api::RoleInfoWithGroupsResponse {
|
||||
groups: role_info.get_permission_groups().to_vec(),
|
||||
role_id: role.role_id,
|
||||
role_name: role_info.get_role_name().to_string(),
|
||||
role_scope: role_info.get_scope(),
|
||||
}),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user