Bug: feat(users): Role info api with parent tags




diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs
index 02e40e2fe1a..5319c81385a 100644
--- a/crates/api_models/src/user_role.rs
+++ b/crates/api_models/src/user_role.rs
@@ -38,6 +38,19 @@ pub enum Permission {
     GenerateReport,
 }
 
+#[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash)]
+pub enum ParentGroup {
+    Operations,
+    Connectors,
+    Workflows,
+    Analytics,
+    Users,
+    #[serde(rename = "MerchantAccess")]
+    Merchant,
+    #[serde(rename = "OrganizationAccess")]
+    Organization,
+}
+
 #[derive(Debug, serde::Serialize)]
 pub enum PermissionModule {
     Payments,
@@ -63,6 +76,7 @@ pub struct AuthorizationInfoResponse(pub Vec<AuthorizationInfo>);
 pub enum AuthorizationInfo {
     Module(ModuleInfo),
     Group(GroupInfo),
+    GroupWithTag(ParentInfo),
 }
 
 #[derive(Debug, serde::Serialize)]
@@ -79,6 +93,13 @@ pub struct GroupInfo {
     pub permissions: Vec<PermissionInfo>,
 }
 
+#[derive(Debug, serde::Serialize, Clone)]
+pub struct ParentInfo {
+    pub name: ParentGroup,
+    pub description: &'static str,
+    pub groups: Vec<PermissionGroup>,
+}
+
 #[derive(Debug, serde::Serialize)]
 pub struct PermissionInfo {
     pub enum_name: Permission,
diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs
index f2fddd61bb6..d9ee8f21805 100644
--- a/crates/router/src/core/user_role.rs
+++ b/crates/router/src/core/user_role.rs
@@ -1,9 +1,12 @@
+use std::collections::HashMap;
+
 use api_models::{user as user_api, user_role as user_role_api};
 use diesel_models::{
     enums::{UserRoleVersion, UserStatus},
     user_role::UserRoleUpdate,
 };
 use error_stack::{report, ResultExt};
+use once_cell::sync::Lazy;
 use router_env::logger;
 
 use crate::{
@@ -18,8 +21,9 @@ use crate::{
     types::domain,
     utils,
 };
-
 pub mod role;
+use common_enums::PermissionGroup;
+use strum::IntoEnumIterator;
 
 // TODO: To be deprecated once groups are stable
 pub async fn get_authorization_info_with_modules(
@@ -47,6 +51,38 @@ 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(|| {
+        PermissionGroup::iter()
+            .map(|value| (info::get_parent_name(value), value))
+            .fold(
+                HashMap::new(),
+                |mut acc: HashMap<user_role_api::ParentGroup, Vec<PermissionGroup>>,
+                 (key, value)| {
+                    acc.entry(key).or_default().push(value);
+                    acc
+                },
+            )
+            .into_iter()
+            .map(|(name, value)| user_role_api::ParentInfo {
+                name: name.clone(),
+                description: info::get_parent_group_description(name),
+                groups: value,
+            })
+            .collect()
+    });
+
+    Ok(ApplicationResponse::Json(
+        user_role_api::AuthorizationInfoResponse(
+            GROUPS_WITH_PARENT_TAGS
+                .iter()
+                .cloned()
+                .map(user_role_api::AuthorizationInfo::GroupWithTag)
+                .collect(),
+        ),
+    ))
+}
 
 pub async fn update_user_role(
     state: SessionState,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 2bb1a5eee8e..37b3f7cbd03 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -1609,6 +1609,7 @@ impl User {
                     .route(web::get().to(list_merchants_for_user)),
             )
             .service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
+            .service(web::resource("/module/list").route(web::get().to(get_role_information)))
             .service(web::resource("/update").route(web::post().to(update_user_account_details)))
             .service(
                 web::resource("/data")
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 9f073853d88..a0e8ed2f8b7 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -250,6 +250,7 @@ impl From<Flow> for ApiIdentifier {
             | Flow::GetRoleFromToken
             | Flow::UpdateUserRole
             | Flow::GetAuthorizationInfo
+            | Flow::GetRolesInfo
             | Flow::AcceptInvitation
             | Flow::MerchantSelect
             | Flow::DeleteUserRole
diff --git a/crates/router/src/routes/user_role.rs b/crates/router/src/routes/user_role.rs
index 4239f2d3814..bce0e6da147 100644
--- a/crates/router/src/routes/user_role.rs
+++ b/crates/router/src/routes/user_role.rs
@@ -268,3 +268,23 @@ pub async fn delete_user_role(
     ))
     .await
 }
+
+pub async fn get_role_information(
+    state: web::Data<AppState>,
+    http_req: HttpRequest,
+) -> HttpResponse {
+    let flow = Flow::GetRolesInfo;
+
+    Box::pin(api::server_wrap(
+        flow,
+        state.clone(),
+        &http_req,
+        (),
+        |_, _: (), _, _| async move {
+            user_role_core::get_authorization_info_with_group_tag().await
+        },
+        &auth::JWTAuth(Permission::UsersRead),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs
index 371087cc303..ca5a6689395 100644
--- a/crates/router/src/services/authorization/info.rs
+++ b/crates/router/src/services/authorization/info.rs
@@ -1,4 +1,4 @@
-use api_models::user_role::{GroupInfo, PermissionInfo};
+use api_models::user_role::{GroupInfo, ParentGroup, PermissionInfo};
 use common_enums::PermissionGroup;
 use strum::{EnumIter, IntoEnumIterator};
 
@@ -217,3 +217,33 @@ fn get_group_description(group: PermissionGroup) -> &'static str {
         PermissionGroup::OrganizationManage => "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc",
     }
 }
+
+pub fn get_parent_name(group: PermissionGroup) -> ParentGroup {
+    match group {
+        PermissionGroup::OperationsView | PermissionGroup::OperationsManage => {
+            ParentGroup::Operations
+        }
+        PermissionGroup::ConnectorsView | PermissionGroup::ConnectorsManage => {
+            ParentGroup::Connectors
+        }
+        PermissionGroup::WorkflowsView | PermissionGroup::WorkflowsManage => ParentGroup::Workflows,
+        PermissionGroup::AnalyticsView => ParentGroup::Analytics,
+        PermissionGroup::UsersView | PermissionGroup::UsersManage => ParentGroup::Users,
+        PermissionGroup::MerchantDetailsView | PermissionGroup::MerchantDetailsManage => {
+            ParentGroup::Merchant
+        }
+        PermissionGroup::OrganizationManage => ParentGroup::Organization,
+    }
+}
+
+pub fn get_parent_group_description(group: ParentGroup) -> &'static str {
+    match group {
+        ParentGroup::Operations => "Payments, Refunds, Payouts, Mandates, Disputes and Customers",
+        ParentGroup::Connectors => "Create, modify and delete connectors like Payment Processors, Payout Processors and Fraud & Risk Manager",
+        ParentGroup::Workflows => "Create, modify and delete Routing, 3DS Decision Manager, Surcharge Decision Manager",
+       ParentGroup::Analytics => "View Analytics",
+        ParentGroup::Users =>  "Manage and invite Users to the Team",
+       ParentGroup::Merchant => "Create, modify and delete Merchant Details like api keys, webhooks, etc",
+       ParentGroup::Organization =>"Manage organization level tasks like create new Merchant accounts, Organization level roles, etc",
+    }
+}
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index f1d2e5d8dcc..8142aa437ed 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -354,6 +354,8 @@ pub enum Flow {
     SwitchMerchant,
     /// Get permission info
     GetAuthorizationInfo,
+    /// Get Roles info
+    GetRolesInfo,
     /// List roles
     ListRoles,
     /// Get role

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [X] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
The permission_info API previously returned permission groups, each with its own description. With this update, permission groups are now organized under parent groups, and descriptions are tied to the parent group instead of individual groups. Additionally, permissions for each group have been removed, as the dashboard no longer utilizes that data.
Older structure : 
```
[
    {
        "group": "operations_view",
        "description": "View Payments, Refunds, Payouts, Mandates, Disputes and Customers",
        "permissions": [
            {
                "enum_name": "PaymentRead",
                "description": "View all payments"
            },
            {
                "enum_name": "RefundRead",
                "description": "View all refunds"
            },
            {
                "enum_name": "MandateRead",
                "description": "View mandates"
            },
            {
                "enum_name": "DisputeRead",
                "description": "View disputes"
            },
            {
                "enum_name": "CustomerRead",
                "description": "View customers"
            },
            {
                "enum_name": "GenerateReport",
                "description": "Generate reports for payments, refunds and disputes"
            },
            {
                "enum_name": "PayoutRead",
                "description": "View all payouts"
            },
            {
                "enum_name": "MerchantAccountRead",
                "description": "View merchant account details"
            }
        ]
    },
    {
        "group": "operations_manage",
        "description": "Create, modify and delete Payments, Refunds, Payouts, Mandates, Disputes and Customers",
        "permissions": [
            {
                "enum_name": "PaymentWrite",
                "description": "Create payment, download payments data"
            },
            {
                "enum_name": "RefundWrite",
                "description": "Create refund, download refunds data"
            },
            {
                "enum_name": "MandateWrite",
                "description": "Create and update mandates"
            },
            {
                "enum_name": "DisputeWrite",
                "description": "Create and update disputes"
            },
            {
                "enum_name": "CustomerWrite",
                "description": "Create, update and delete customers"
            },
            {
                "enum_name": "PayoutWrite",
                "description": "Create payout, download payout data"
            },
            {
                "enum_name": "MerchantAccountRead",
                "description": "View merchant account details"
            }
        ]
    },
]
```
New structure : 
```
 {
        "name": "Operations",
        "description": "Payments, Refunds, Payouts, Mandates, Disputes and Customers",
        "groups": [
            "operations_view",
            "operations_manage"
        ]
}
```


### Additional Changes

- [X] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
This will close the issue 


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Request : 
```
curl --location 'http://localhost:8080/user/module/list' \
--header 'Authorization: Bearer token '
```
Response : 
```
[
    {
        "name": "Users",
        "description": "Manage and invite Users to the Team",
        "groups": [
            "users_view",
            "users_manage"
        ]
    },
    {
        "name": "MerchantAccess",
        "description": "Create, modify and delete Merchant Details like api keys, webhooks, etc",
        "groups": [
            "merchant_details_view",
            "merchant_details_manage"
        ]
    },
    {
        "name": "OrganizationAccess",
        "description": "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc",
        "groups": [
            "organization_manage"
        ]
    },
    {
        "name": "Analytics",
        "description": "View Analytics",
        "groups": [
            "analytics_view"
        ]
    },
    {
        "name": "Connectors",
        "description": "Create, modify and delete connectors like Payment Processors, Payout Processors and Fraud & Risk Manager",
        "groups": [
            "connectors_view",
            "connectors_manage"
        ]
    },
    {
        "name": "Operations",
        "description": "Payments, Refunds, Payouts, Mandates, Disputes and Customers",
        "groups": [
            "operations_view",
            "operations_manage"
        ]
    },
    {
        "name": "Workflows",
        "description": "Create, modify and delete Routing, 3DS Decision Manager, Surcharge Decision Manager",
        "groups": [
            "workflows_view",
            "workflows_manage"
        ]
    }
]
```
## Checklist
<!-- Put an `x` in the boxes that apply -->

- [X] I formatted the code `cargo +nightly fmt --all`
- [X] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
