Bug: feat: get user role from token




diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs
index 72fca2b2f08..b057f8ca8bc 100644
--- a/crates/api_models/src/user_role.rs
+++ b/crates/api_models/src/user_role.rs
@@ -43,6 +43,7 @@ pub enum Permission {
     SurchargeDecisionManagerRead,
     UsersRead,
     UsersWrite,
+    MerchantAccountCreate,
 }
 
 #[derive(Debug, serde::Serialize)]
@@ -60,6 +61,7 @@ pub enum PermissionModule {
     Files,
     ThreeDsDecisionManager,
     SurchargeDecisionManager,
+    AccountCreate,
 }
 
 #[derive(Debug, serde::Serialize)]
diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs
index 2b7752d1904..d8ff836e1f8 100644
--- a/crates/router/src/core/user_role.rs
+++ b/crates/router/src/core/user_role.rs
@@ -20,7 +20,7 @@ pub async fn get_authorization_info(
         user_role_api::AuthorizationInfoResponse(
             info::get_authorization_info()
                 .into_iter()
-                .filter_map(|module| module.try_into().ok())
+                .map(Into::into)
                 .collect(),
         ),
     ))
@@ -63,6 +63,22 @@ pub async fn get_role(
     Ok(ApplicationResponse::Json(info))
 }
 
+pub async fn get_role_from_token(
+    _state: AppState,
+    user: auth::UserFromToken,
+) -> UserResponse<Vec<user_role_api::Permission>> {
+    Ok(ApplicationResponse::Json(
+        predefined_permissions::PREDEFINED_PERMISSIONS
+            .get(user.role_id.as_str())
+            .ok_or(UserErrors::InternalServerError.into())
+            .attach_printable("Invalid Role Id in JWT")?
+            .get_permissions()
+            .iter()
+            .map(|&per| per.into())
+            .collect(),
+    ))
+}
+
 pub async fn update_user_role(
     state: AppState,
     user_from_token: auth::UserFromToken,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 0c489dbe63a..34a3b5db51b 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -919,6 +919,7 @@ impl User {
             .service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
             .service(web::resource("/user/update_role").route(web::post().to(update_user_role)))
             .service(web::resource("/role/list").route(web::get().to(list_roles)))
+            .service(web::resource("/role").route(web::get().to(get_role_from_token)))
             .service(web::resource("/role/{role_id}").route(web::get().to(get_role)))
             .service(web::resource("/user/invite").route(web::post().to(invite_user)))
             .service(
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 12cf76be475..4dffcb1d38d 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -180,9 +180,11 @@ impl From<Flow> for ApiIdentifier {
             | Flow::VerifyEmail
             | Flow::VerifyEmailRequest => Self::User,
 
-            Flow::ListRoles | Flow::GetRole | Flow::UpdateUserRole | Flow::GetAuthorizationInfo => {
-                Self::UserRole
-            }
+            Flow::ListRoles
+            | Flow::GetRole
+            | Flow::GetRoleFromToken
+            | Flow::UpdateUserRole
+            | Flow::GetAuthorizationInfo => Self::UserRole,
 
             Flow::GetActionUrl | Flow::SyncOnboardingStatus | Flow::ResetTrackingId => {
                 Self::ConnectorOnboarding
diff --git a/crates/router/src/routes/user_role.rs b/crates/router/src/routes/user_role.rs
index c96e099ab16..fe305942d03 100644
--- a/crates/router/src/routes/user_role.rs
+++ b/crates/router/src/routes/user_role.rs
@@ -7,7 +7,7 @@ use crate::{
     core::{api_locking, user_role as user_role_core},
     services::{
         api,
-        authentication::{self as auth},
+        authentication::{self as auth, UserFromToken},
         authorization::permissions::Permission,
     },
 };
@@ -64,6 +64,20 @@ pub async fn get_role(
     .await
 }
 
+pub async fn get_role_from_token(state: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
+    let flow = Flow::GetRoleFromToken;
+    Box::pin(api::server_wrap(
+        flow,
+        state.clone(),
+        &req,
+        (),
+        |state, user: UserFromToken, _| user_role_core::get_role_from_token(state, user),
+        &auth::DashboardNoPermissionAuth,
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
 pub async fn update_user_role(
     state: web::Data<AppState>,
     req: HttpRequest,
diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs
index cef93f82739..99e4f1b6c09 100644
--- a/crates/router/src/services/authorization/info.rs
+++ b/crates/router/src/services/authorization/info.rs
@@ -15,16 +15,13 @@ pub struct PermissionInfo {
 
 impl PermissionInfo {
     pub fn new(permissions: &[Permission]) -> Vec<Self> {
-        let mut permission_infos = Vec::with_capacity(permissions.len());
-        for permission in permissions {
-            if let Some(description) = Permission::get_permission_description(permission) {
-                permission_infos.push(Self {
-                    enum_name: permission.clone(),
-                    description,
-                })
-            }
-        }
-        permission_infos
+        permissions
+            .iter()
+            .map(|&per| Self {
+                description: Permission::get_permission_description(&per),
+                enum_name: per,
+            })
+            .collect()
     }
 }
 
@@ -43,6 +40,7 @@ pub enum PermissionModule {
     Files,
     ThreeDsDecisionManager,
     SurchargeDecisionManager,
+    AccountCreate,
 }
 
 impl PermissionModule {
@@ -60,7 +58,8 @@ impl PermissionModule {
             Self::Disputes => "Everything related to disputes - like creating and viewing dispute related information are within this module",
             Self::Files => "Permissions for uploading, deleting and viewing files for disputes",
             Self::ThreeDsDecisionManager => "View and configure 3DS decision rules configured for a merchant",
-            Self::SurchargeDecisionManager =>"View and configure surcharge decision rules configured for a merchant"
+            Self::SurchargeDecisionManager =>"View and configure surcharge decision rules configured for a merchant",
+            Self::AccountCreate => "Create new account within your organization"
         }
     }
 }
@@ -173,6 +172,11 @@ impl ModuleInfo {
                     Permission::SurchargeDecisionManagerRead,
                 ]),
             },
+            PermissionModule::AccountCreate => Self {
+                module: module_name,
+                description,
+                permissions: PermissionInfo::new(&[Permission::MerchantAccountCreate]),
+            },
         }
     }
 }
diff --git a/crates/router/src/services/authorization/permissions.rs b/crates/router/src/services/authorization/permissions.rs
index 426b048e88b..5c5e3ecce30 100644
--- a/crates/router/src/services/authorization/permissions.rs
+++ b/crates/router/src/services/authorization/permissions.rs
@@ -1,6 +1,6 @@
 use strum::Display;
 
-#[derive(PartialEq, Display, Clone, Debug)]
+#[derive(PartialEq, Display, Clone, Debug, Copy)]
 pub enum Permission {
     PaymentRead,
     PaymentWrite,
@@ -34,45 +34,43 @@ pub enum Permission {
 }
 
 impl Permission {
-    pub fn get_permission_description(&self) -> Option<&'static str> {
+    pub fn get_permission_description(&self) -> &'static str {
         match self {
-            Self::PaymentRead => Some("View all payments"),
-            Self::PaymentWrite => Some("Create payment, download payments data"),
-            Self::RefundRead => Some("View all refunds"),
-            Self::RefundWrite => Some("Create refund, download refunds data"),
-            Self::ApiKeyRead => Some("View API keys (masked generated for the system"),
-            Self::ApiKeyWrite => Some("Create and update API keys"),
-            Self::MerchantAccountRead => Some("View merchant account details"),
+            Self::PaymentRead => "View all payments",
+            Self::PaymentWrite => "Create payment, download payments data",
+            Self::RefundRead => "View all refunds",
+            Self::RefundWrite => "Create refund, download refunds data",
+            Self::ApiKeyRead => "View API keys (masked generated for the system",
+            Self::ApiKeyWrite => "Create and update API keys",
+            Self::MerchantAccountRead => "View merchant account details",
             Self::MerchantAccountWrite => {
-                Some("Update merchant account details, configure webhooks, manage api keys")
+                "Update merchant account details, configure webhooks, manage api keys"
             }
-            Self::MerchantConnectorAccountRead => Some("View connectors configured"),
+            Self::MerchantConnectorAccountRead => "View connectors configured",
             Self::MerchantConnectorAccountWrite => {
-                Some("Create, update, verify and delete connector configurations")
+                "Create, update, verify and delete connector configurations"
             }
-            Self::ForexRead => Some("Query Forex data"),
-            Self::RoutingRead => Some("View routing configuration"),
-            Self::RoutingWrite => Some("Create and activate routing configurations"),
-            Self::DisputeRead => Some("View disputes"),
-            Self::DisputeWrite => Some("Create and update disputes"),
-            Self::MandateRead => Some("View mandates"),
-            Self::MandateWrite => Some("Create and update mandates"),
-            Self::CustomerRead => Some("View customers"),
-            Self::CustomerWrite => Some("Create, update and delete customers"),
-            Self::FileRead => Some("View files"),
-            Self::FileWrite => Some("Create, update and delete files"),
-            Self::Analytics => Some("Access to analytics module"),
-            Self::ThreeDsDecisionManagerWrite => Some("Create and update 3DS decision rules"),
+            Self::ForexRead => "Query Forex data",
+            Self::RoutingRead => "View routing configuration",
+            Self::RoutingWrite => "Create and activate routing configurations",
+            Self::DisputeRead => "View disputes",
+            Self::DisputeWrite => "Create and update disputes",
+            Self::MandateRead => "View mandates",
+            Self::MandateWrite => "Create and update mandates",
+            Self::CustomerRead => "View customers",
+            Self::CustomerWrite => "Create, update and delete customers",
+            Self::FileRead => "View files",
+            Self::FileWrite => "Create, update and delete files",
+            Self::Analytics => "Access to analytics module",
+            Self::ThreeDsDecisionManagerWrite => "Create and update 3DS decision rules",
             Self::ThreeDsDecisionManagerRead => {
-                Some("View all 3DS decision rules configured for a merchant")
+                "View all 3DS decision rules configured for a merchant"
             }
-            Self::SurchargeDecisionManagerWrite => {
-                Some("Create and update the surcharge decision rules")
-            }
-            Self::SurchargeDecisionManagerRead => Some("View all the surcharge decision rules"),
-            Self::UsersRead => Some("View all the users for a merchant"),
-            Self::UsersWrite => Some("Invite users, assign and update roles"),
-            Self::MerchantAccountCreate => None,
+            Self::SurchargeDecisionManagerWrite => "Create and update the surcharge decision rules",
+            Self::SurchargeDecisionManagerRead => "View all the surcharge decision rules",
+            Self::UsersRead => "View all the users for a merchant",
+            Self::UsersWrite => "Invite users, assign and update roles",
+            Self::MerchantAccountCreate => "Create merchant account",
         }
     }
 }
diff --git a/crates/router/src/types/domain/user.rs b/crates/router/src/types/domain/user.rs
index d271ed5e29d..53c88f8aea1 100644
--- a/crates/router/src/types/domain/user.rs
+++ b/crates/router/src/types/domain/user.rs
@@ -762,19 +762,13 @@ impl UserFromStorage {
     }
 }
 
-impl TryFrom<info::ModuleInfo> for user_role_api::ModuleInfo {
-    type Error = ();
-    fn try_from(value: info::ModuleInfo) -> Result<Self, Self::Error> {
-        let mut permissions = Vec::with_capacity(value.permissions.len());
-        for permission in value.permissions {
-            let permission = permission.try_into()?;
-            permissions.push(permission);
-        }
-        Ok(Self {
+impl From<info::ModuleInfo> for user_role_api::ModuleInfo {
+    fn from(value: info::ModuleInfo) -> Self {
+        Self {
             module: value.module.into(),
             description: value.description,
-            permissions,
-        })
+            permissions: value.permissions.into_iter().map(Into::into).collect(),
+        }
     }
 }
 
@@ -794,18 +788,17 @@ impl From<info::PermissionModule> for user_role_api::PermissionModule {
             info::PermissionModule::Files => Self::Files,
             info::PermissionModule::ThreeDsDecisionManager => Self::ThreeDsDecisionManager,
             info::PermissionModule::SurchargeDecisionManager => Self::SurchargeDecisionManager,
+            info::PermissionModule::AccountCreate => Self::AccountCreate,
         }
     }
 }
 
-impl TryFrom<info::PermissionInfo> for user_role_api::PermissionInfo {
-    type Error = ();
-    fn try_from(value: info::PermissionInfo) -> Result<Self, Self::Error> {
-        let enum_name = (&value.enum_name).try_into()?;
-        Ok(Self {
-            enum_name,
+impl From<info::PermissionInfo> for user_role_api::PermissionInfo {
+    fn from(value: info::PermissionInfo) -> Self {
+        Self {
+            enum_name: value.enum_name.into(),
             description: value.description,
-        })
+        }
     }
 }
 
diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs
index c474a82981b..65ead92ad34 100644
--- a/crates/router/src/utils/user_role.rs
+++ b/crates/router/src/utils/user_role.rs
@@ -1,7 +1,6 @@
 use api_models::user_role as user_role_api;
 use diesel_models::enums::UserStatus;
 use error_stack::ResultExt;
-use router_env::logger;
 
 use crate::{
     consts,
@@ -44,52 +43,50 @@ pub fn validate_role_id(role_id: &str) -> UserResult<()> {
 pub fn get_role_name_and_permission_response(
     role_info: &RoleInfo,
 ) -> Option<(Vec<user_role_api::Permission>, &'static str)> {
-    role_info
-        .get_permissions()
-        .iter()
-        .map(TryInto::try_into)
-        .collect::<Result<Vec<user_role_api::Permission>, _>>()
-        .ok()
-        .zip(role_info.get_name())
+    role_info.get_name().map(|name| {
+        (
+            role_info
+                .get_permissions()
+                .iter()
+                .map(|&per| per.into())
+                .collect::<Vec<user_role_api::Permission>>(),
+            name,
+        )
+    })
 }
 
-impl TryFrom<&Permission> for user_role_api::Permission {
-    type Error = ();
-    fn try_from(value: &Permission) -> Result<Self, Self::Error> {
+impl From<Permission> for user_role_api::Permission {
+    fn from(value: Permission) -> Self {
         match value {
-            Permission::PaymentRead => Ok(Self::PaymentRead),
-            Permission::PaymentWrite => Ok(Self::PaymentWrite),
-            Permission::RefundRead => Ok(Self::RefundRead),
-            Permission::RefundWrite => Ok(Self::RefundWrite),
-            Permission::ApiKeyRead => Ok(Self::ApiKeyRead),
-            Permission::ApiKeyWrite => Ok(Self::ApiKeyWrite),
-            Permission::MerchantAccountRead => Ok(Self::MerchantAccountRead),
-            Permission::MerchantAccountWrite => Ok(Self::MerchantAccountWrite),
-            Permission::MerchantConnectorAccountRead => Ok(Self::MerchantConnectorAccountRead),
-            Permission::MerchantConnectorAccountWrite => Ok(Self::MerchantConnectorAccountWrite),
-            Permission::ForexRead => Ok(Self::ForexRead),
-            Permission::RoutingRead => Ok(Self::RoutingRead),
-            Permission::RoutingWrite => Ok(Self::RoutingWrite),
-            Permission::DisputeRead => Ok(Self::DisputeRead),
-            Permission::DisputeWrite => Ok(Self::DisputeWrite),
-            Permission::MandateRead => Ok(Self::MandateRead),
-            Permission::MandateWrite => Ok(Self::MandateWrite),
-            Permission::CustomerRead => Ok(Self::CustomerRead),
-            Permission::CustomerWrite => Ok(Self::CustomerWrite),
-            Permission::FileRead => Ok(Self::FileRead),
-            Permission::FileWrite => Ok(Self::FileWrite),
-            Permission::Analytics => Ok(Self::Analytics),
-            Permission::ThreeDsDecisionManagerWrite => Ok(Self::ThreeDsDecisionManagerWrite),
-            Permission::ThreeDsDecisionManagerRead => Ok(Self::ThreeDsDecisionManagerRead),
-            Permission::SurchargeDecisionManagerWrite => Ok(Self::SurchargeDecisionManagerWrite),
-            Permission::SurchargeDecisionManagerRead => Ok(Self::SurchargeDecisionManagerRead),
-            Permission::UsersRead => Ok(Self::UsersRead),
-            Permission::UsersWrite => Ok(Self::UsersWrite),
-
-            Permission::MerchantAccountCreate => {
-                logger::error!("Invalid use of internal permission");
-                Err(())
-            }
+            Permission::PaymentRead => Self::PaymentRead,
+            Permission::PaymentWrite => Self::PaymentWrite,
+            Permission::RefundRead => Self::RefundRead,
+            Permission::RefundWrite => Self::RefundWrite,
+            Permission::ApiKeyRead => Self::ApiKeyRead,
+            Permission::ApiKeyWrite => Self::ApiKeyWrite,
+            Permission::MerchantAccountRead => Self::MerchantAccountRead,
+            Permission::MerchantAccountWrite => Self::MerchantAccountWrite,
+            Permission::MerchantConnectorAccountRead => Self::MerchantConnectorAccountRead,
+            Permission::MerchantConnectorAccountWrite => Self::MerchantConnectorAccountWrite,
+            Permission::ForexRead => Self::ForexRead,
+            Permission::RoutingRead => Self::RoutingRead,
+            Permission::RoutingWrite => Self::RoutingWrite,
+            Permission::DisputeRead => Self::DisputeRead,
+            Permission::DisputeWrite => Self::DisputeWrite,
+            Permission::MandateRead => Self::MandateRead,
+            Permission::MandateWrite => Self::MandateWrite,
+            Permission::CustomerRead => Self::CustomerRead,
+            Permission::CustomerWrite => Self::CustomerWrite,
+            Permission::FileRead => Self::FileRead,
+            Permission::FileWrite => Self::FileWrite,
+            Permission::Analytics => Self::Analytics,
+            Permission::ThreeDsDecisionManagerWrite => Self::ThreeDsDecisionManagerWrite,
+            Permission::ThreeDsDecisionManagerRead => Self::ThreeDsDecisionManagerRead,
+            Permission::SurchargeDecisionManagerWrite => Self::SurchargeDecisionManagerWrite,
+            Permission::SurchargeDecisionManagerRead => Self::SurchargeDecisionManagerRead,
+            Permission::UsersRead => Self::UsersRead,
+            Permission::UsersWrite => Self::UsersWrite,
+            Permission::MerchantAccountCreate => Self::MerchantAccountCreate,
         }
     }
 }
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index 0d6636e567d..d48aa5f95fe 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -297,6 +297,8 @@ pub enum Flow {
     ListRoles,
     /// Get role
     GetRole,
+    /// Get role from token
+    GetRoleFromToken,
     /// Update user role
     UpdateUserRole,
     /// Create merchant account for user in a org

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

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

## Description
Added API to get list of permission user has.
<!-- Describe your changes in detail -->


### 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
Required for hyperswitch control centre
<!--
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).
-->


## How did you test it?
```
curl --location --request GET '<URL>/user/role' \
--header 'Authorization: Bearer <JWT>'
```

Above API should give an array of permission.
All roles and their permission can be found [here](https://github.com/juspay/hyperswitch/blob/main/crates/router/src/services/authorization/predefined_permissions.rs#L28).

Example response,

```
[
    "PaymentRead",
    "RefundRead",
    "ApiKeyRead",
    "MerchantAccountRead",
    "MerchantConnectorAccountRead",
    "RoutingRead",
    "ForexRead",
    "ThreeDsDecisionManagerRead",
    "SurchargeDecisionManagerRead",
    "Analytics",
    "DisputeRead",
    "MandateRead",
    "CustomerRead",
    "FileRead",
    "UsersRead"
]
```
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## 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`
- [X] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
