From fbe9d2f19e9c0ca3af45a60e3d82b3ea774e11ce Mon Sep 17 00:00:00 2001 From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com> Date: Tue, 27 Feb 2024 18:26:46 +0530 Subject: [PATCH] feat(roles): Change list roles, get role and authorization info api to respond with groups (#3837) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/events/user_role.rs | 10 +- crates/api_models/src/user_role.rs | 17 ++- crates/api_models/src/user_role/role.rs | 26 +++- crates/common_enums/src/enums.rs | 1 + crates/router/src/core/user.rs | 8 +- crates/router/src/core/user_role.rs | 26 +++- crates/router/src/core/user_role/role.rs | 140 ++++++++++++++---- crates/router/src/routes/user_role.rs | 55 +++++-- crates/router/src/services/authorization.rs | 1 + .../router/src/services/authorization/info.rs | 95 ++++++++---- .../src/services/authorization/roles.rs | 30 ++-- crates/router/src/types/domain/user.rs | 9 -- crates/router/src/utils/user.rs | 2 +- 13 files changed, 310 insertions(+), 110 deletions(-) diff --git a/crates/api_models/src/events/user_role.rs b/crates/api_models/src/events/user_role.rs index f19ff95f9e..f46c5cf312 100644 --- a/crates/api_models/src/events/user_role.rs +++ b/crates/api_models/src/events/user_role.rs @@ -2,15 +2,15 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::user_role::{ role::{ - CreateRoleRequest, GetRoleRequest, ListRolesResponse, RoleInfoResponse, UpdateRoleRequest, + CreateRoleRequest, GetRoleRequest, ListRolesResponse, RoleInfoResponse, + RoleInfoWithPermissionsResponse, UpdateRoleRequest, }, AcceptInvitationRequest, AuthorizationInfoResponse, DeleteUserRoleRequest, TransferOrgOwnershipRequest, UpdateUserRoleRequest, }; common_utils::impl_misc_api_event_type!( - ListRolesResponse, - RoleInfoResponse, + RoleInfoWithPermissionsResponse, GetRoleRequest, AuthorizationInfoResponse, UpdateUserRoleRequest, @@ -18,5 +18,7 @@ common_utils::impl_misc_api_event_type!( DeleteUserRoleRequest, TransferOrgOwnershipRequest, CreateRoleRequest, - UpdateRoleRequest + UpdateRoleRequest, + ListRolesResponse, + RoleInfoResponse ); diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs index ed0838adc2..80d3861969 100644 --- a/crates/api_models/src/user_role.rs +++ b/crates/api_models/src/user_role.rs @@ -1,3 +1,4 @@ +use common_enums::PermissionGroup; use common_utils::pii; use crate::user::DashboardEntryResponse; @@ -51,7 +52,14 @@ pub enum PermissionModule { } #[derive(Debug, serde::Serialize)] -pub struct AuthorizationInfoResponse(pub Vec); +pub struct AuthorizationInfoResponse(pub Vec); + +#[derive(Debug, serde::Serialize)] +#[serde(untagged)] +pub enum AuthorizationInfo { + Module(ModuleInfo), + Group(GroupInfo), +} #[derive(Debug, serde::Serialize)] pub struct ModuleInfo { @@ -60,6 +68,13 @@ pub struct ModuleInfo { pub permissions: Vec, } +#[derive(Debug, serde::Serialize)] +pub struct GroupInfo { + pub group: PermissionGroup, + pub description: &'static str, + pub permissions: Vec, +} + #[derive(Debug, serde::Serialize)] pub struct PermissionInfo { pub enum_name: Permission, diff --git a/crates/api_models/src/user_role/role.rs b/crates/api_models/src/user_role/role.rs index 4a767cfa72..fafb8fede0 100644 --- a/crates/api_models/src/user_role/role.rs +++ b/crates/api_models/src/user_role/role.rs @@ -1,5 +1,7 @@ use common_enums::{PermissionGroup, RoleScope}; +use super::Permission; + #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct CreateRoleRequest { pub role_name: String, @@ -16,10 +18,30 @@ pub struct UpdateRoleRequest { #[derive(Debug, serde::Serialize)] pub struct ListRolesResponse(pub Vec); +#[derive(Debug, serde::Deserialize)] +pub struct GetGroupsQueryParam { + pub groups: Option, +} + #[derive(Debug, serde::Serialize)] -pub struct RoleInfoResponse { +#[serde(untagged)] +pub enum RoleInfoResponse { + Permissions(RoleInfoWithPermissionsResponse), + Groups(RoleInfoWithGroupsResponse), +} + +#[derive(Debug, serde::Serialize)] +pub struct RoleInfoWithPermissionsResponse { pub role_id: String, - pub permissions: Vec, + pub permissions: Vec, + pub role_name: String, + pub role_scope: RoleScope, +} + +#[derive(Debug, serde::Serialize)] +pub struct RoleInfoWithGroupsResponse { + pub role_id: String, + pub groups: Vec, pub role_name: String, pub role_scope: RoleScope, } diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 29c416e9a8..e0b6a1cc5a 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -2246,6 +2246,7 @@ pub enum RoleScope { serde::Deserialize, strum::Display, strum::EnumString, + strum::EnumIter, )] #[router_derive::diesel_enum(storage_type = "text")] #[serde(rename_all = "snake_case")] diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index b38faa3455..b8b8cbd24c 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -442,7 +442,7 @@ pub async fn invite_user( .into()); } - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, &request.role_id, &user_from_token.merchant_id, @@ -659,7 +659,7 @@ async fn handle_invitation( .into()); } - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( state, &request.role_id, &user_from_token.merchant_id, @@ -1054,7 +1054,7 @@ pub async fn switch_merchant_id( let user = user_from_token.get_user_from_db(&state).await?; - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, &user_from_token.role_id, &user_from_token.merchant_id, @@ -1207,7 +1207,7 @@ pub async fn get_users_for_merchant_account( let users_user_roles_and_roles = futures::future::try_join_all(users_and_user_roles.into_iter().map( |(user, user_role)| async { - roles::get_role_info_from_role_id( + roles::RoleInfo::from_role_id( &state, &user_role.role_id, &user_role.merchant_id, diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs index b954e0df6c..9dca9b43d9 100644 --- a/crates/router/src/core/user_role.rs +++ b/crates/router/src/core/user_role.rs @@ -19,14 +19,28 @@ use crate::{ pub mod role; -pub async fn get_authorization_info( +// TODO: To be deprecated once groups are stable +pub async fn get_authorization_info_with_modules( _state: AppState, ) -> UserResponse { Ok(ApplicationResponse::Json( user_role_api::AuthorizationInfoResponse( - info::get_authorization_info() + info::get_module_authorization_info() .into_iter() - .map(Into::into) + .map(|module_info| user_role_api::AuthorizationInfo::Module(module_info.into())) + .collect(), + ), + )) +} + +pub async fn get_authorization_info_with_groups( + _state: AppState, +) -> UserResponse { + Ok(ApplicationResponse::Json( + user_role_api::AuthorizationInfoResponse( + info::get_group_authorization_info() + .into_iter() + .map(user_role_api::AuthorizationInfo::Group) .collect(), ), )) @@ -37,7 +51,7 @@ pub async fn update_user_role( user_from_token: auth::UserFromToken, req: user_role_api::UpdateUserRoleRequest, ) -> UserResponse<()> { - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, &req.role_id, &user_from_token.merchant_id, @@ -67,7 +81,7 @@ pub async fn update_user_role( .await .to_not_found_response(UserErrors::InvalidRoleOperation)?; - let role_to_be_updated = roles::get_role_info_from_role_id( + let role_to_be_updated = roles::RoleInfo::from_role_id( &state, &user_role_to_be_updated.role_id, &user_from_token.merchant_id, @@ -236,7 +250,7 @@ pub async fn delete_user_role( .find(|&role| role.merchant_id == user_from_token.merchant_id.as_str()) { Some(user_role) => { - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, &user_role.role_id, &user_from_token.merchant_id, diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs index 6edbda85bf..cc31798bd8 100644 --- a/crates/router/src/core/user_role/role.rs +++ b/crates/router/src/core/user_role/role.rs @@ -86,22 +86,25 @@ pub async fn create_role( Ok(ApplicationResponse::StatusOk) } -pub async fn list_invitable_roles( +// TODO: To be deprecated once groups are stable +pub async fn list_invitable_roles_with_permissions( state: AppState, user_from_token: UserFromToken, ) -> UserResponse { let predefined_roles_map = PREDEFINED_ROLES .iter() .filter(|(_, role_info)| role_info.is_invitable()) - .map(|(role_id, role_info)| role_api::RoleInfoResponse { - 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(), + .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 @@ -110,17 +113,22 @@ pub async fn list_invitable_roles( .await .change_context(UserErrors::InternalServerError)? .into_iter() - .map(roles::RoleInfo::from) - .filter(|role_info| role_info.is_invitable()) - .map(|role_info| role_api::RoleInfoResponse { - 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(), + .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( @@ -128,12 +136,54 @@ pub async fn list_invitable_roles( ))) } -pub async fn get_role( +pub async fn list_invitable_roles_with_groups( + state: AppState, + user_from_token: UserFromToken, +) -> UserResponse { + 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 { + 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 + .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::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(), + }, + )) + }); + + Ok(ApplicationResponse::Json(role_api::ListRolesResponse( + predefined_roles_map.chain(custom_roles_map).collect(), + ))) +} + +// TODO: To be deprecated once groups are stable +pub async fn get_role_with_permissions( state: AppState, user_from_token: UserFromToken, role: role_api::GetRoleRequest, ) -> UserResponse { - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, &role.role_id, &user_from_token.merchant_id, @@ -152,12 +202,42 @@ pub async fn get_role( .map(Into::into) .collect(); - Ok(ApplicationResponse::Json(role_api::RoleInfoResponse { - permissions, - role_id: role.role_id, - role_name: role_info.get_role_name().to_string(), - role_scope: role_info.get_scope(), - })) + 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: AppState, + user_from_token: UserFromToken, + role: role_api::GetRoleRequest, +) -> UserResponse { + 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()); + } + + Ok(ApplicationResponse::Json( + role_api::RoleInfoResponse::Groups(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(), + }), + )) } pub async fn update_role( @@ -182,7 +262,7 @@ pub async fn update_role( .await?; } - let role_info = roles::get_role_info_from_role_id( + let role_info = roles::RoleInfo::from_role_id( &state, role_id, &user_from_token.merchant_id, diff --git a/crates/router/src/routes/user_role.rs b/crates/router/src/routes/user_role.rs index 52e739c36e..75de9e7e6f 100644 --- a/crates/router/src/routes/user_role.rs +++ b/crates/router/src/routes/user_role.rs @@ -1,10 +1,13 @@ use actix_web::{web, HttpRequest, HttpResponse}; -use api_models::user_role as user_role_api; +use api_models::user_role::{self as user_role_api, role as role_api}; use router_env::Flow; use super::AppState; use crate::{ - core::{api_locking, user_role as user_role_core}, + core::{ + api_locking, + user_role::{self as user_role_core, role as role_core}, + }, services::{ api, authentication::{self as auth}, @@ -15,14 +18,23 @@ use crate::{ pub async fn get_authorization_info( state: web::Data, http_req: HttpRequest, + query: web::Query, ) -> HttpResponse { let flow = Flow::GetAuthorizationInfo; + let respond_with_groups = query.into_inner().groups.unwrap_or(false); Box::pin(api::server_wrap( flow, state.clone(), &http_req, (), - |state, _: (), _| user_role_core::get_authorization_info(state), + |state, _: (), _| async move { + // TODO: Permissions to be deprecated once groups are stable + if respond_with_groups { + user_role_core::get_authorization_info_with_groups(state).await + } else { + user_role_core::get_authorization_info_with_modules(state).await + } + }, &auth::JWTAuth(Permission::UsersRead), api_locking::LockAction::NotApplicable, )) @@ -36,7 +48,7 @@ pub async fn get_role_from_token(state: web::Data, req: HttpRequest) - state.clone(), &req, (), - |state, user, _| user_role_core::role::get_role_from_token(state, user), + |state, user, _| role_core::get_role_from_token(state, user), &auth::DashboardNoPermissionAuth, api_locking::LockAction::NotApplicable, )) @@ -46,7 +58,7 @@ pub async fn get_role_from_token(state: web::Data, req: HttpRequest) - pub async fn create_role( state: web::Data, req: HttpRequest, - json_payload: web::Json, + json_payload: web::Json, ) -> HttpResponse { let flow = Flow::CreateRole; Box::pin(api::server_wrap( @@ -54,21 +66,33 @@ pub async fn create_role( state.clone(), &req, json_payload.into_inner(), - user_role_core::role::create_role, + role_core::create_role, &auth::JWTAuth(Permission::UsersWrite), api_locking::LockAction::NotApplicable, )) .await } -pub async fn list_all_roles(state: web::Data, req: HttpRequest) -> HttpResponse { +pub async fn list_all_roles( + state: web::Data, + req: HttpRequest, + query: web::Query, +) -> HttpResponse { let flow = Flow::ListRoles; + let respond_with_groups = query.into_inner().groups.unwrap_or(false); Box::pin(api::server_wrap( flow, state.clone(), &req, (), - |state, user, _| user_role_core::role::list_invitable_roles(state, user), + |state, user, _| async move { + // TODO: Permissions to be deprecated once groups are stable + if respond_with_groups { + role_core::list_invitable_roles_with_groups(state, user).await + } else { + role_core::list_invitable_roles_with_permissions(state, user).await + } + }, &auth::JWTAuth(Permission::UsersRead), api_locking::LockAction::NotApplicable, )) @@ -79,17 +103,26 @@ pub async fn get_role( state: web::Data, req: HttpRequest, path: web::Path, + query: web::Query, ) -> HttpResponse { let flow = Flow::GetRole; let request_payload = user_role_api::role::GetRoleRequest { role_id: path.into_inner(), }; + let respond_with_groups = query.into_inner().groups.unwrap_or(false); Box::pin(api::server_wrap( flow, state.clone(), &req, request_payload, - user_role_core::role::get_role, + |state, user, payload| async move { + // TODO: Permissions to be deprecated once groups are stable + if respond_with_groups { + role_core::get_role_with_groups(state, user, payload).await + } else { + role_core::get_role_with_permissions(state, user, payload).await + } + }, &auth::JWTAuth(Permission::UsersRead), api_locking::LockAction::NotApplicable, )) @@ -99,7 +132,7 @@ pub async fn get_role( pub async fn update_role( state: web::Data, req: HttpRequest, - json_payload: web::Json, + json_payload: web::Json, path: web::Path, ) -> HttpResponse { let flow = Flow::UpdateRole; @@ -110,7 +143,7 @@ pub async fn update_role( state.clone(), &req, json_payload.into_inner(), - |state, user, req| user_role_core::role::update_role(state, user, req, &role_id), + |state, user, req| role_core::update_role(state, user, req, &role_id), &auth::JWTAuth(Permission::UsersWrite), api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs index 034773a07e..2a516cc82d 100644 --- a/crates/router/src/services/authorization.rs +++ b/crates/router/src/services/authorization.rs @@ -6,6 +6,7 @@ use crate::{ routes::app::AppStateInfo, }; +#[cfg(feature = "olap")] pub mod info; pub mod permission_groups; pub mod permissions; diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs index d982317e02..d6a20b7f8e 100644 --- a/crates/router/src/services/authorization/info.rs +++ b/crates/router/src/services/authorization/info.rs @@ -1,30 +1,32 @@ +use api_models::user_role::{GroupInfo, PermissionInfo}; +use common_enums::PermissionGroup; use strum::{EnumIter, IntoEnumIterator}; -use super::permissions::Permission; +use super::{permission_groups::get_permissions_vec, permissions::Permission}; -pub fn get_authorization_info() -> Vec { +pub fn get_module_authorization_info() -> Vec { PermissionModule::iter() .map(|module| ModuleInfo::new(&module)) .collect() } -pub struct PermissionInfo { - pub enum_name: Permission, - pub description: &'static str, +pub fn get_group_authorization_info() -> Vec { + PermissionGroup::iter() + .map(get_group_info_from_permission_group) + .collect() } -impl PermissionInfo { - pub fn new(permissions: &[Permission]) -> Vec { - permissions - .iter() - .map(|&per| Self { - description: Permission::get_permission_description(&per), - enum_name: per, - }) - .collect() - } +pub fn get_permission_info_from_permissions(permissions: &[Permission]) -> Vec { + permissions + .iter() + .map(|&per| PermissionInfo { + description: Permission::get_permission_description(&per), + enum_name: per.into(), + }) + .collect() } +// TODO: Deprecate once groups are stable #[derive(PartialEq, EnumIter, Clone)] pub enum PermissionModule { Payments, @@ -60,6 +62,7 @@ impl PermissionModule { } } +// TODO: Deprecate once groups are stable pub struct ModuleInfo { pub module: PermissionModule, pub description: &'static str, @@ -75,7 +78,7 @@ impl ModuleInfo { PermissionModule::Payments => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::PaymentRead, Permission::PaymentWrite, ]), @@ -83,7 +86,7 @@ impl ModuleInfo { PermissionModule::Refunds => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::RefundRead, Permission::RefundWrite, ]), @@ -91,7 +94,7 @@ impl ModuleInfo { PermissionModule::MerchantAccount => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::MerchantAccountRead, Permission::MerchantAccountWrite, ]), @@ -99,7 +102,7 @@ impl ModuleInfo { PermissionModule::Connectors => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::MerchantConnectorAccountRead, Permission::MerchantConnectorAccountWrite, ]), @@ -107,7 +110,7 @@ impl ModuleInfo { PermissionModule::Routing => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::RoutingRead, Permission::RoutingWrite, ]), @@ -115,12 +118,12 @@ impl ModuleInfo { PermissionModule::Analytics => Self { module: module_name, description, - permissions: PermissionInfo::new(&[Permission::Analytics]), + permissions: get_permission_info_from_permissions(&[Permission::Analytics]), }, PermissionModule::Mandates => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::MandateRead, Permission::MandateWrite, ]), @@ -128,7 +131,7 @@ impl ModuleInfo { PermissionModule::Customer => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::CustomerRead, Permission::CustomerWrite, ]), @@ -136,7 +139,7 @@ impl ModuleInfo { PermissionModule::Disputes => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::DisputeRead, Permission::DisputeWrite, ]), @@ -144,7 +147,7 @@ impl ModuleInfo { PermissionModule::ThreeDsDecisionManager => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::ThreeDsDecisionManagerRead, Permission::ThreeDsDecisionManagerWrite, ]), @@ -153,7 +156,7 @@ impl ModuleInfo { PermissionModule::SurchargeDecisionManager => Self { module: module_name, description, - permissions: PermissionInfo::new(&[ + permissions: get_permission_info_from_permissions(&[ Permission::SurchargeDecisionManagerRead, Permission::SurchargeDecisionManagerWrite, ]), @@ -161,8 +164,46 @@ impl ModuleInfo { PermissionModule::AccountCreate => Self { module: module_name, description, - permissions: PermissionInfo::new(&[Permission::MerchantAccountCreate]), + permissions: get_permission_info_from_permissions(&[ + Permission::MerchantAccountCreate, + ]), }, } } } + +fn get_group_info_from_permission_group(group: PermissionGroup) -> GroupInfo { + let description = get_group_description(group); + GroupInfo { + group, + description, + permissions: get_permission_info_from_permissions(get_permissions_vec(&group)), + } +} + +fn get_group_description(group: PermissionGroup) -> &'static str { + match group { + PermissionGroup::OperationsView => { + "View Payments, Refunds, Mandates, Disputes and Customers" + } + PermissionGroup::OperationsManage => { + "Create,modify and delete Payments, Refunds, Mandates, Disputes and Customers" + } + PermissionGroup::ConnectorsView => { + "View connected Payment Processors, Payout Processors and Fraud & Risk Manager details" + } + PermissionGroup::ConnectorsManage => "Create, modify and delete connectors like Payment Processors, Payout Processors and Fraud & Risk Manager", + PermissionGroup::WorkflowsView => { + "View Routing, 3DS Decision Manager, Surcharge Decision Manager" + } + PermissionGroup::WorkflowsManage => { + "Create, modify and delete Routing, 3DS Decision Manager, Surcharge Decision Manager" + } + PermissionGroup::AnalyticsView => "View Analytics", + PermissionGroup::UsersView => "View Users", + PermissionGroup::UsersManage => "Manage and invite Users to the Team", + PermissionGroup::MerchantDetailsView => "View Merchant Details", + PermissionGroup::MerchantDetailsManage => "Create, modify and delete Merchant Details like api keys, webhooks, etc", + PermissionGroup::OrganizationManage => "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc", + } +} diff --git a/crates/router/src/services/authorization/roles.rs b/crates/router/src/services/authorization/roles.rs index 6372799f98..f99892c565 100644 --- a/crates/router/src/services/authorization/roles.rs +++ b/crates/router/src/services/authorization/roles.rs @@ -65,22 +65,22 @@ impl RoleInfo { .iter() .any(|group| get_permissions_vec(group).contains(required_permission)) } -} -pub async fn get_role_info_from_role_id( - state: &AppState, - role_id: &str, - merchant_id: &str, - org_id: &str, -) -> CustomResult { - if let Some(role) = predefined_roles::PREDEFINED_ROLES.get(role_id) { - Ok(role.clone()) - } else { - state - .store - .find_role_by_role_id_in_merchant_scope(role_id, merchant_id, org_id) - .await - .map(RoleInfo::from) + pub async fn from_role_id( + state: &AppState, + role_id: &str, + merchant_id: &str, + org_id: &str, + ) -> CustomResult { + if let Some(role) = predefined_roles::PREDEFINED_ROLES.get(role_id) { + Ok(role.clone()) + } else { + state + .store + .find_role_by_role_id_in_merchant_scope(role_id, merchant_id, org_id) + .await + .map(Self::from) + } } } diff --git a/crates/router/src/types/domain/user.rs b/crates/router/src/types/domain/user.rs index a759bf0080..d6e878456e 100644 --- a/crates/router/src/types/domain/user.rs +++ b/crates/router/src/types/domain/user.rs @@ -811,15 +811,6 @@ impl From for user_role_api::PermissionModule { } } -impl From for user_role_api::PermissionInfo { - fn from(value: info::PermissionInfo) -> Self { - Self { - enum_name: value.enum_name.into(), - description: value.description, - } - } -} - pub enum SignInWithRoleStrategyType { SingleRole(SignInWithSingleRoleStrategy), MultipleRoles(SignInWithMultipleRolesStrategy), diff --git a/crates/router/src/utils/user.rs b/crates/router/src/utils/user.rs index e9b7143a26..c3b795d1a5 100644 --- a/crates/router/src/utils/user.rs +++ b/crates/router/src/utils/user.rs @@ -64,7 +64,7 @@ impl UserFromToken { } pub async fn get_role_info_from_db(&self, state: &AppState) -> UserResult { - roles::get_role_info_from_role_id(state, &self.role_id, &self.merchant_id, &self.org_id) + roles::RoleInfo::from_role_id(state, &self.role_id, &self.merchant_id, &self.org_id) .await .change_context(UserErrors::InternalServerError) }