mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
feat(user_roles): support switch for new hierarchy (#5692)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -1320,12 +1320,12 @@ pub async fn create_internal_user(
|
||||
|
||||
pub async fn switch_merchant_id(
|
||||
state: SessionState,
|
||||
request: user_api::SwitchMerchantIdRequest,
|
||||
request: user_api::SwitchMerchantRequest,
|
||||
user_from_token: auth::UserFromToken,
|
||||
) -> UserResponse<user_api::DashboardEntryResponse> {
|
||||
if user_from_token.merchant_id == request.merchant_id {
|
||||
return Err(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"User switching to same merchant id".to_string(),
|
||||
"User switching to same merchant_id".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
@ -1375,9 +1375,9 @@ pub async fn switch_merchant_id(
|
||||
})?
|
||||
.organization_id;
|
||||
|
||||
let token = utils::user::generate_jwt_auth_token_with_custom_role_attributes(
|
||||
let token = utils::user::generate_jwt_auth_token_with_attributes(
|
||||
&state,
|
||||
&user,
|
||||
user_from_token.user_id,
|
||||
request.merchant_id.clone(),
|
||||
org_id.clone(),
|
||||
user_from_token.role_id.clone(),
|
||||
@ -1557,7 +1557,7 @@ pub async fn list_users_for_merchant_account(
|
||||
.list_user_roles_by_merchant_id(&user_from_token.merchant_id, UserRoleVersion::V1)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("No user roles for given merchant id")?
|
||||
.attach_printable("No user roles for given merchant_id")?
|
||||
.into_iter()
|
||||
.map(|role| (role.user_id.clone(), role))
|
||||
.collect();
|
||||
@ -1569,7 +1569,7 @@ pub async fn list_users_for_merchant_account(
|
||||
.find_users_by_user_ids(user_ids)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("No users for given merchant id")?;
|
||||
.attach_printable("No users for given merchant_id")?;
|
||||
|
||||
let users_and_user_roles: Vec<_> = users
|
||||
.into_iter()
|
||||
@ -2134,7 +2134,7 @@ pub async fn verify_recovery_code(
|
||||
state: SessionState,
|
||||
user_token: auth::UserIdFromAuth,
|
||||
req: user_api::VerifyRecoveryCodeRequest,
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
) -> UserResponse<()> {
|
||||
let user_from_db: domain::UserFromStorage = state
|
||||
.global_store
|
||||
.find_user_by_id(&user_token.user_id)
|
||||
@ -2760,3 +2760,442 @@ pub async fn list_profiles_for_user_in_org_and_merchant_account(
|
||||
|
||||
Ok(ApplicationResponse::Json(profiles))
|
||||
}
|
||||
|
||||
pub async fn switch_org_for_user(
|
||||
state: SessionState,
|
||||
request: user_api::SwitchOrganizationRequest,
|
||||
user_from_token: auth::UserFromToken,
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
if user_from_token.org_id == request.org_id {
|
||||
return Err(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"User switching to same org".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let key_manager_state = &(&state).into();
|
||||
let role_info = roles::RoleInfo::from_role_id(
|
||||
&state,
|
||||
&user_from_token.role_id,
|
||||
&user_from_token.merchant_id,
|
||||
&user_from_token.org_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to retrieve role information")?;
|
||||
|
||||
if role_info.get_entity_type() == EntityType::Internal {
|
||||
return Err(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"Org switching not allowed for Internal role".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles(
|
||||
&user_from_token.user_id,
|
||||
Some(&request.org_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list user roles by user_id and org_id")?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role found for the requested org_id".to_string(),
|
||||
))?
|
||||
.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 profile_id = if let Some(profile_id) = &user_role.profile_id {
|
||||
profile_id.clone()
|
||||
} else {
|
||||
let merchant_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("Failed to retrieve merchant key store by merchant_id")?;
|
||||
|
||||
state
|
||||
.store
|
||||
.list_business_profile_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&merchant_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the merchant_id")?
|
||||
.profile_id
|
||||
.clone()
|
||||
};
|
||||
|
||||
let token = utils::user::generate_jwt_auth_token_with_attributes(
|
||||
&state,
|
||||
user_from_token.user_id,
|
||||
merchant_id.clone(),
|
||||
request.org_id.clone(),
|
||||
user_role.role_id.clone(),
|
||||
Some(profile_id.clone()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id(
|
||||
&state,
|
||||
&user_role.role_id,
|
||||
&merchant_id,
|
||||
&request.org_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: common_enums::TokenPurpose::UserInfo,
|
||||
};
|
||||
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
pub async fn switch_merchant_for_user_in_org(
|
||||
state: SessionState,
|
||||
request: user_api::SwitchMerchantRequest,
|
||||
user_from_token: auth::UserFromToken,
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
if user_from_token.merchant_id == request.merchant_id {
|
||||
return Err(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"User switching to same merchant".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let key_manager_state = &(&state).into();
|
||||
let role_info = roles::RoleInfo::from_role_id(
|
||||
&state,
|
||||
&user_from_token.role_id,
|
||||
&user_from_token.merchant_id,
|
||||
&user_from_token.org_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to retrieve role information")?;
|
||||
|
||||
let (org_id, merchant_id, profile_id, role_id) = match role_info.get_entity_type() {
|
||||
EntityType::Internal => {
|
||||
let merchant_key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&request.merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(UserErrors::MerchantIdNotFound)?;
|
||||
|
||||
let merchant_account = state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
&request.merchant_id,
|
||||
&merchant_key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(UserErrors::MerchantIdNotFound)?;
|
||||
|
||||
let profile_id = state
|
||||
.store
|
||||
.list_business_profile_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&request.merchant_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the given merchant_id")?
|
||||
.profile_id
|
||||
.clone();
|
||||
|
||||
(
|
||||
merchant_account.organization_id,
|
||||
request.merchant_id,
|
||||
profile_id,
|
||||
user_from_token.role_id.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
EntityType::Organization => {
|
||||
let merchant_key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&request.merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(UserErrors::MerchantIdNotFound)?;
|
||||
|
||||
let merchant_id = state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
&request.merchant_id,
|
||||
&merchant_key_store,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::MerchantIdNotFound)?
|
||||
.organization_id
|
||||
.eq(&user_from_token.org_id)
|
||||
.then(|| request.merchant_id.clone())
|
||||
.ok_or_else(|| {
|
||||
UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No such merchant_id found for the user in the org".to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let profile_id = state
|
||||
.store
|
||||
.list_business_profile_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&merchant_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles by merchant_id")?
|
||||
.first()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the merchant_id")?
|
||||
.profile_id
|
||||
.clone();
|
||||
|
||||
(
|
||||
user_from_token.org_id.clone(),
|
||||
merchant_id,
|
||||
profile_id,
|
||||
user_from_token.role_id.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
EntityType::Merchant | EntityType::Profile => {
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles(
|
||||
&user_from_token.user_id,
|
||||
Some(&user_from_token.org_id),
|
||||
Some(&request.merchant_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable(
|
||||
"Failed to list user roles for the given user_id, org_id and merchant_id",
|
||||
)?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role associated with the requested merchant_id".to_string(),
|
||||
))?
|
||||
.to_owned();
|
||||
|
||||
let profile_id = if let Some(profile_id) = &user_role.profile_id {
|
||||
profile_id.clone()
|
||||
} else {
|
||||
let merchant_key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&request.merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to retrieve merchant key store by merchant_id")?;
|
||||
|
||||
state
|
||||
.store
|
||||
.list_business_profile_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&request.merchant_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list business profiles for the given merchant_id")?
|
||||
.first()
|
||||
.ok_or(UserErrors::InternalServerError)
|
||||
.attach_printable("No business profile found for the given merchant_id")?
|
||||
.profile_id
|
||||
.clone()
|
||||
};
|
||||
(
|
||||
user_from_token.org_id,
|
||||
request.merchant_id,
|
||||
profile_id,
|
||||
user_role.role_id,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let token = utils::user::generate_jwt_auth_token_with_attributes(
|
||||
&state,
|
||||
user_from_token.user_id,
|
||||
merchant_id.clone(),
|
||||
org_id.clone(),
|
||||
role_id.clone(),
|
||||
Some(profile_id),
|
||||
)
|
||||
.await?;
|
||||
|
||||
utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id(
|
||||
&state,
|
||||
&role_id,
|
||||
&merchant_id,
|
||||
&org_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: common_enums::TokenPurpose::UserInfo,
|
||||
};
|
||||
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
pub async fn switch_profile_for_user_in_org_and_merchant(
|
||||
state: SessionState,
|
||||
request: user_api::SwitchProfileRequest,
|
||||
user_from_token: auth::UserFromToken,
|
||||
) -> UserResponse<user_api::TokenResponse> {
|
||||
if user_from_token.profile_id == Some(request.profile_id.clone()) {
|
||||
return Err(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"User switching to same profile".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let key_manager_state = &(&state).into();
|
||||
let role_info = roles::RoleInfo::from_role_id(
|
||||
&state,
|
||||
&user_from_token.role_id,
|
||||
&user_from_token.merchant_id,
|
||||
&user_from_token.org_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to retrieve role information")?;
|
||||
|
||||
let (profile_id, role_id) = match role_info.get_entity_type() {
|
||||
EntityType::Internal | EntityType::Organization | EntityType::Merchant => {
|
||||
let merchant_key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&user_from_token.merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to retrieve merchant key store by merchant_id")?;
|
||||
|
||||
let profile_id = state
|
||||
.store
|
||||
.find_business_profile_by_merchant_id_profile_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&user_from_token.merchant_id,
|
||||
&request.profile_id,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No such profile found for the merchant".to_string(),
|
||||
))?
|
||||
.profile_id;
|
||||
(profile_id, user_from_token.role_id)
|
||||
}
|
||||
|
||||
EntityType::Profile => {
|
||||
let user_role = state
|
||||
.store
|
||||
.list_user_roles(
|
||||
&user_from_token.user_id,
|
||||
Some(&user_from_token.org_id),
|
||||
Some(&user_from_token.merchant_id),
|
||||
Some(&request.profile_id),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.change_context(UserErrors::InternalServerError)
|
||||
.attach_printable("Failed to list user roles for the given user_id, org_id, merchant_id and profile_id")?
|
||||
.into_iter()
|
||||
.find(|role| role.status == UserStatus::Active)
|
||||
.ok_or(UserErrors::InvalidRoleOperationWithMessage(
|
||||
"No user role associated with the profile".to_string(),
|
||||
))?
|
||||
.to_owned();
|
||||
|
||||
(request.profile_id, user_role.role_id)
|
||||
}
|
||||
};
|
||||
|
||||
let token = utils::user::generate_jwt_auth_token_with_attributes(
|
||||
&state,
|
||||
user_from_token.user_id,
|
||||
user_from_token.merchant_id.clone(),
|
||||
user_from_token.org_id.clone(),
|
||||
role_id.clone(),
|
||||
Some(profile_id),
|
||||
)
|
||||
.await?;
|
||||
|
||||
utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id(
|
||||
&state,
|
||||
&role_id,
|
||||
&user_from_token.merchant_id,
|
||||
&user_from_token.org_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
let response = user_api::TokenResponse {
|
||||
token: token.clone(),
|
||||
token_type: common_enums::TokenPurpose::UserInfo,
|
||||
};
|
||||
|
||||
auth::cookies::set_cookie_response(response, token)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user