From 05d85c03559b38d499e05e6ff5a8335484a1122c Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Thu, 11 Jan 2024 13:26:41 +0530 Subject: [PATCH 1/6] feat: list of permissions call --- .../hyperswitch/HyperSwitchApp.res | 29 ++++++++++++++++++- .../hyperswitch/HyperswitchAtom.res | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/entryPoints/hyperswitch/HyperSwitchApp.res b/src/entryPoints/hyperswitch/HyperSwitchApp.res index 795a31657..27ae9a179 100644 --- a/src/entryPoints/hyperswitch/HyperSwitchApp.res +++ b/src/entryPoints/hyperswitch/HyperSwitchApp.res @@ -40,7 +40,7 @@ let make = () => { ->QuickStartUtils.getTypedValueFromDict let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom - + let setUserPermissions = Recoil.useSetRecoilState(HyperswitchAtom.userPermissionAtom) let getEnumDetails = EnumVariantHook.useFetchEnumDetails() let verificationDays = getFromMerchantDetails("verification")->LogicUtils.getIntFromString(-1) let userRole = getFromUserDetails("user_role") @@ -116,8 +116,35 @@ let make = () => { } } + let fetchPermissionsForARole = async () => { + try { + let url = getURL( + ~entityName=USER_MANAGEMENT, + ~userRoleTypes=ROLE_ID, + ~id={ + Some(userRole === "org_admin" ? "merchant_admin" : userRole) + }, + ~methodType=Get, + (), + ) + let response = await fetchDetails(url) + let permissionsValue = + response + ->LogicUtils.getDictFromJsonObject + ->LogicUtils.getArrayFromDict("permissions", []) + ->Array.map(ele => ele->Js.Json.decodeString->Option.getWithDefault("")) + setUserPermissions(._ => permissionsValue) + } catch { + | Js.Exn.Error(e) => { + let err = Js.Exn.message(e)->Belt.Option.getWithDefault("Failed to Fetch!") + Js.Exn.raiseError(err) + } + } + } + let setUpDashboard = async () => { try { + let _ = await fetchPermissionsForARole() let _ = await Window.connectorWasmInit() let _ = await fetchBusinessProfiles() let _ = await fetchConnectorListResponse() diff --git a/src/entryPoints/hyperswitch/HyperswitchAtom.res b/src/entryPoints/hyperswitch/HyperswitchAtom.res index 11db93cca..bf4c9d084 100644 --- a/src/entryPoints/hyperswitch/HyperswitchAtom.res +++ b/src/entryPoints/hyperswitch/HyperswitchAtom.res @@ -10,8 +10,8 @@ let featureFlagAtom: Recoil.recoilAtom = Recoil.at "featureFlag", Js.Json.null->FeatureFlagUtils.featureFlagType, ) - let paypalAccountStatusAtom: Recoil.recoilAtom = Recoil.atom(. "paypalAccountStatusAtom", PayPalFlowTypes.Account_not_found, ) +let userPermissionAtom: Recoil.recoilAtom> = Recoil.atom(. "userPermissionAtom", []) From 0906f2ce3a1d7c62b1faf81aaace679388f62c34 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Jan 2024 16:39:30 +0530 Subject: [PATCH 2/6] fix: Sidebar blocked for Permissions --- src/components/EntityScaffold.res | 4 - .../hyperswitch/HyperSwitchApp.res | 13 +- .../hyperswitch/HyperswitchAtom.res | 5 +- src/entryPoints/hyperswitch/SidebarValues.res | 345 +++++++++++------- .../UserManagement/PermissionHelper.res | 110 ++++++ .../Utils/HSwitchGlobalSearchBar.res | 9 +- src/screens/login/AuthTypes.res | 2 +- 7 files changed, 342 insertions(+), 146 deletions(-) create mode 100644 src/screens/HyperSwitch/UserManagement/PermissionHelper.res diff --git a/src/components/EntityScaffold.res b/src/components/EntityScaffold.res index bea10957d..d9d048b33 100644 --- a/src/components/EntityScaffold.res +++ b/src/components/EntityScaffold.res @@ -52,7 +52,6 @@ let make = ( | list{"new"} => switch access { | ReadWrite => renderNewForm() - | Checker => isAdminAccount ? renderNewForm() : | _ => } | list{id, "clone"} => @@ -69,14 +68,11 @@ let make = ( | list{id, "edit"} => switch access { | ReadWrite => renderEdit(id) - | Checker => isAdminAccount ? renderEdit(id) : | _ => } | list{id1, id2, "edit"} => switch access { | ReadWrite => renderEditWithMultiId(id1, id2) - | Checker => - isAdminAccount ? renderEditWithMultiId(id1, id2) : | _ => } | list{"order", id} => diff --git a/src/entryPoints/hyperswitch/HyperSwitchApp.res b/src/entryPoints/hyperswitch/HyperSwitchApp.res index 27ae9a179..e9e8f1cac 100644 --- a/src/entryPoints/hyperswitch/HyperSwitchApp.res +++ b/src/entryPoints/hyperswitch/HyperSwitchApp.res @@ -40,7 +40,7 @@ let make = () => { ->QuickStartUtils.getTypedValueFromDict let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom - let setUserPermissions = Recoil.useSetRecoilState(HyperswitchAtom.userPermissionAtom) + let setUserPermissionsList = Recoil.useSetRecoilState(HyperswitchAtom.userPermissionAtom) let getEnumDetails = EnumVariantHook.useFetchEnumDetails() let verificationDays = getFromMerchantDetails("verification")->LogicUtils.getIntFromString(-1) let userRole = getFromUserDetails("user_role") @@ -55,12 +55,7 @@ let make = () => { let isReconEnabled = (merchantDetailsValue->MerchantAccountUtils.getMerchantDetails).recon_status === Active - let hyperSwitchAppSidebars = SidebarValues.getHyperSwitchAppSidebars( - ~isReconEnabled, - ~featureFlagDetails, - ~userRole, - (), - ) + let hyperSwitchAppSidebars = SidebarValues.useGetSidebarValues(~isReconEnabled) let comingSoonPage = { ->LogicUtils.getDictFromJsonObject ->LogicUtils.getArrayFromDict("permissions", []) ->Array.map(ele => ele->Js.Json.decodeString->Option.getWithDefault("")) - setUserPermissions(._ => permissionsValue) + let mapPermissionArrayToType = + permissionsValue->Array.map(ele => ele->PermissionHelper.mapStringToPermissionType) + setUserPermissionsList(._ => mapPermissionArrayToType) } catch { | Js.Exn.Error(e) => { let err = Js.Exn.message(e)->Belt.Option.getWithDefault("Failed to Fetch!") diff --git a/src/entryPoints/hyperswitch/HyperswitchAtom.res b/src/entryPoints/hyperswitch/HyperswitchAtom.res index bf4c9d084..d2dcbca7d 100644 --- a/src/entryPoints/hyperswitch/HyperswitchAtom.res +++ b/src/entryPoints/hyperswitch/HyperswitchAtom.res @@ -14,4 +14,7 @@ let paypalAccountStatusAtom: Recoil.recoilAtom> = Recoil.atom(. "userPermissionAtom", []) +let userPermissionAtom: Recoil.recoilAtom> = Recoil.atom(. + "userPermissionAtom", + [], +) diff --git a/src/entryPoints/hyperswitch/SidebarValues.res b/src/entryPoints/hyperswitch/SidebarValues.res index 3463c58bc..b35550b19 100644 --- a/src/entryPoints/hyperswitch/SidebarValues.res +++ b/src/entryPoints/hyperswitch/SidebarValues.res @@ -1,4 +1,5 @@ open SidebarTypes +open PermissionHelper // * Custom Component @@ -39,6 +40,7 @@ module GetProductionAccess = { let emptyComponent = CustomComponent({ component: React.null, }) + let productionAccessComponent = isProductionAccessEnabled => isProductionAccessEnabled ? CustomComponent({ @@ -58,35 +60,59 @@ let home = isHomeEnabled => }) : emptyComponent -let payments = SubLevelLink({ - name: "Payments", - link: `/payments`, - access: ReadWrite, - searchOptions: [("View payment operations", "")], -}) +let payments = permissionList => { + let paymentPermission = PaymentRead + let accessValue = getAccessValue(~permissionValue=paymentPermission, permissionList) -let refunds = SubLevelLink({ - name: "Refunds", - link: `/refunds`, - access: ReadWrite, - searchOptions: [("View refund operations", "")], -}) + SubLevelLink({ + name: "Payments", + link: `/payments`, + access: accessValue, + searchOptions: [("View payment operations", "")], + }) +} -let disputes = SubLevelLink({ - name: "Disputes", - link: `/disputes`, - access: ReadWrite, - searchOptions: [("View dispute operations", "")], -}) +let refunds = permissionList => { + let refundPermission = RefundRead + let accessValue = getAccessValue(~permissionValue=refundPermission, permissionList) -let customers = SubLevelLink({ - name: "Customers", - link: `/customers`, - access: ReadWrite, - searchOptions: [("View customers", "")], -}) + SubLevelLink({ + name: "Refunds", + link: `/refunds`, + access: accessValue, + searchOptions: [("View refund operations", "")], + }) +} + +let disputes = permissionList => { + let disputePermission = DisputeRead + let accessValue = getAccessValue(~permissionValue=disputePermission, permissionList) + + SubLevelLink({ + name: "Disputes", + link: `/disputes`, + access: accessValue, + searchOptions: [("View dispute operations", "")], + }) +} + +let customers = permissionList => { + let customersPermission = CustomerRead + let accessValue = getAccessValue(~permissionValue=customersPermission, permissionList) + SubLevelLink({ + name: "Customers", + link: `/customers`, + access: accessValue, + searchOptions: [("View customers", "")], + }) +} + +let operations = (isOperationsEnabled, customersModule, ~permissionList) => { + let payments = payments(permissionList) + let refunds = refunds(permissionList) + let disputes = disputes(permissionList) + let customers = customers(permissionList) -let operations = (isOperationsEnabled, customersModule) => { isOperationsEnabled ? Section({ name: "Operations", @@ -99,13 +125,15 @@ let operations = (isOperationsEnabled, customersModule) => { : emptyComponent } -let connectors = (isConnectorsEnabled, isLiveMode) => { +let connectors = (isConnectorsEnabled, isLiveMode, ~permissionList) => { + let connectorPermission = MerchantConnectorAccountRead + let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) isConnectorsEnabled ? Link({ name: "Processors", link: `/connectors`, icon: "connectors", - access: ReadWrite, + access: accessValue, searchOptions: HSwitchUtils.getSearchOptionsForProcessors( ~processorList=isLiveMode ? ConnectorUtils.connectorListForLive @@ -138,45 +166,63 @@ let userJourneyAnalytics = SubLevelLink({ searchOptions: [("View analytics", "")], }) -let analytics = (isAnalyticsEnabled, userJourneyAnalyticsFlag) => +let analytics = (isAnalyticsEnabled, userJourneyAnalyticsFlag, ~permissionList) => { + let analyticsPermission = Analytics + let accessValue = getAccessValue(~permissionValue=analyticsPermission, permissionList) + isAnalyticsEnabled ? Section({ name: "Analytics", icon: "analytics", - showSection: true, + showSection: accessValue === Read, links: userJourneyAnalyticsFlag ? [paymentAnalytcis, refundAnalytics, userJourneyAnalytics] : [paymentAnalytcis, refundAnalytics], }) : emptyComponent +} +let routing = permissionList => { + let routingPermission = RoutingRead + let accessValue = getAccessValue(~permissionValue=routingPermission, permissionList) + SubLevelLink({ + name: "Routing", + link: `/routing`, + access: accessValue, + searchOptions: [ + ("Manage default routing configuration", "/default"), + ("Create new volume based routing", "/volume"), + ("Create new rule based routing", "/rule"), + ("Manage smart routing", ""), + ], + }) +} -let routing = SubLevelLink({ - name: "Routing", - link: `/routing`, - access: ReadWrite, - searchOptions: [ - ("Manage default routing configuration", "/default"), - ("Create new volume based routing", "/volume"), - ("Create new rule based routing", "/rule"), - ("Manage smart routing", ""), - ], -}) - -let threeDs = SubLevelLink({ - name: "3DS Decision Manager", - link: `/3ds`, - access: ReadWrite, - searchOptions: [("Configure 3ds", "")], -}) +let threeDs = permissionList => { + let threeDsPermission = ThreeDsDecisionManagerRead + let accessValue = getAccessValue(~permissionValue=threeDsPermission, permissionList) + SubLevelLink({ + name: "3DS Decision Manager", + link: `/3ds`, + access: accessValue, + searchOptions: [("Configure 3ds", "")], + }) +} +let surcharge = permissionList => { + let surchargePermission = SurchargeDecisionManagerRead + let accessValue = getAccessValue(~permissionValue=surchargePermission, permissionList) + SubLevelLink({ + name: "Surcharge", + link: `/surcharge`, + access: accessValue, + searchOptions: [("Add Surcharge", "")], + }) +} -let surcharge = SubLevelLink({ - name: "Surcharge", - link: `/surcharge`, - access: ReadWrite, - searchOptions: [("Add Surcharge", "")], -}) +let workflow = (isWorkflowEnabled, isSurchargeEnabled, ~permissionList) => { + let routing = routing(permissionList) + let threeDs = threeDs(permissionList) + let surcharge = surcharge(permissionList) -let workflow = (isWorkflowEnabled, isSurchargeEnabled) => isWorkflowEnabled ? Section({ name: "Workflow", @@ -185,50 +231,74 @@ let workflow = (isWorkflowEnabled, isSurchargeEnabled) => links: isSurchargeEnabled ? [routing, threeDs, surcharge] : [routing, threeDs], }) : emptyComponent +} -let userManagement = SubLevelLink({ - name: "Team", - link: `/users`, - access: ReadWrite, - searchOptions: [("View team management", "")], -}) +let userManagement = permissionList => { + let userPermission = UsersRead + let accessValue = getAccessValue(~permissionValue=userPermission, permissionList) + SubLevelLink({ + name: "Team", + link: `/users`, + access: accessValue, + searchOptions: [("View team management", "")], + }) +} -let accountSettings = SubLevelLink({ - name: "Account Settings", - link: `/account-settings`, - access: ReadWrite, - searchOptions: [ - ("View profile", "/profile"), - ("Change password", "/profile"), - ("Manage your personal profile and preferences", "/profile"), - ], -}) +let accountSettings = permissionList => { + // Because it has delete sample data + let merchantAccountPermission = MerchantAccountWrite + let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) + + SubLevelLink({ + name: "Account Settings", + link: `/account-settings`, + access: accessValue, + searchOptions: [ + ("View profile", "/profile"), + ("Change password", "/profile"), + ("Manage your personal profile and preferences", "/profile"), + ], + }) +} -let businessDetails = SubLevelLink({ - name: "Business Details", - link: `/business-details`, - access: ReadWrite, - searchOptions: [("Configure business details", "")], -}) +let businessDetails = permissionList => { + let merchantAccountPermission = MerchantAccountRead + let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) -let businessProfiles = SubLevelLink({ - name: "Business Profiles", - link: `/business-profiles`, - access: ReadWrite, - searchOptions: [("Configure business profiles", "")], -}) + SubLevelLink({ + name: "Business Details", + link: `/business-details`, + access: accessValue, + searchOptions: [("Configure business details", "")], + }) +} -let settings = (~isSampleDataEnabled, ~isUserManagementEnabled, ~isBusinessProfileEnabled) => { - let settingsLinkArray = [businessDetails] +let businessProfiles = permissionList => { + let merchantAccountPermission = MerchantAccountRead + let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) + SubLevelLink({ + name: "Business Profiles", + link: `/business-profiles`, + access: accessValue, + searchOptions: [("Configure business profiles", "")], + }) +} +let settings = ( + ~isSampleDataEnabled, + ~isUserManagementEnabled, + ~isBusinessProfileEnabled, + ~permissionList, +) => { + let settingsLinkArray = [businessDetails(permissionList)] if isBusinessProfileEnabled { - settingsLinkArray->Array.push(businessProfiles)->ignore + settingsLinkArray->Array.push(businessProfiles(permissionList))->ignore } if isSampleDataEnabled { - settingsLinkArray->Array.push(accountSettings)->ignore + settingsLinkArray->Array.push(accountSettings(permissionList))->ignore } if isUserManagementEnabled { - settingsLinkArray->Array.push(userManagement)->ignore + settingsLinkArray->Array.push(userManagement(permissionList))->ignore } Section({ @@ -239,30 +309,48 @@ let settings = (~isSampleDataEnabled, ~isUserManagementEnabled, ~isBusinessProfi }) } -let apiKeys = SubLevelLink({ - name: "API Keys", - link: `/developer-api-keys`, - access: ReadWrite, - searchOptions: [("View API Keys", "")], -}) +let apiKeys = permissionList => { + let apiKeyPermission = ApiKeyRead + let accessValue = getAccessValue(~permissionValue=apiKeyPermission, permissionList) -let systemMetric = SubLevelLink({ - name: "System Metrics", - link: `/developer-system-metrics`, - access: ReadWrite, - iconTag: "betaTag", - searchOptions: [("View System Metrics", "")], -}) + SubLevelLink({ + name: "API Keys", + link: `/developer-api-keys`, + access: accessValue, + searchOptions: [("View API Keys", "")], + }) +} -let paymentSettings = SubLevelLink({ - name: "Payment Settings", - link: `/payment-settings`, - access: ReadWrite, - searchOptions: [("View payment settings", ""), ("View webhooks", ""), ("View return url", "")], -}) +let systemMetric = permissionList => { + let analyticsPermission = Analytics + let accessValue = getAccessValue(~permissionValue=analyticsPermission, permissionList) + + SubLevelLink({ + name: "System Metrics", + link: `/developer-system-metrics`, + access: accessValue, + iconTag: "betaTag", + searchOptions: [("View System Metrics", "")], + }) +} + +let paymentSettings = permissionList => { + let merchantAccountPermission = MerchantAccountRead + let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) + + SubLevelLink({ + name: "Payment Settings", + link: `/payment-settings`, + access: accessValue, + searchOptions: [("View payment settings", ""), ("View webhooks", ""), ("View return url", "")], + }) +} -let developers = (isDevelopersEnabled, userRole, systemMetrics) => { +let developers = (isDevelopersEnabled, userRole, systemMetrics, ~permissionList) => { let isInternalUser = userRole->String.includes("internal_") + let apiKeys = apiKeys(permissionList) + let paymentSettings = paymentSettings(permissionList) + let systemMetric = systemMetric(permissionList) isDevelopersEnabled ? Section({ @@ -276,30 +364,38 @@ let developers = (isDevelopersEnabled, userRole, systemMetrics) => { : emptyComponent } -let fraudAndRisk = isfraudAndRiskEnabled => +let fraudAndRisk = (isfraudAndRiskEnabled, ~permissionList) => { + let connectorPermission = MerchantConnectorAccountRead + let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) + isfraudAndRiskEnabled ? Link({ name: "Fraud & Risk", icon: "shield-alt", link: `/fraud-risk-management`, - access: isfraudAndRiskEnabled ? ReadWrite : NoAccess, + access: accessValue, searchOptions: [], }) : emptyComponent +} + +let payoutConnectors = (isPayoutConnectorsEnabled, ~permissionList) => { + let connectorPermission = MerchantConnectorAccountRead + let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) -let payoutConnectors = isPayoutConnectorsEnabled => isPayoutConnectorsEnabled ? Link({ name: "Payout Processors", link: `/payoutconnectors`, icon: "connectors", - access: ReadWrite, + access: accessValue, searchOptions: HSwitchUtils.getSearchOptionsForProcessors( ~processorList=ConnectorUtils.payoutConnectorList, ~getNameFromString=ConnectorUtils.getConnectorNameString, ), }) : emptyComponent +} let reconTag = (recon, isReconEnabled) => recon @@ -311,12 +407,11 @@ let reconTag = (recon, isReconEnabled) => }) : emptyComponent -let getHyperSwitchAppSidebars = ( - ~isReconEnabled: bool, - ~featureFlagDetails: FeatureFlagUtils.featureFlag, - ~userRole, - (), -) => { +let useGetSidebarValues = (~isReconEnabled: bool) => { + let userRole = HSLocalStorage.getFromUserDetails("user_role") + let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom + let permissionList = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom) + let { productionAccess, frm, @@ -332,21 +427,23 @@ let getHyperSwitchAppSidebars = ( isLiveMode, customersModule, } = featureFlagDetails + let sidebar = [ productionAccess->productionAccessComponent, default->home, - default->operations(customersModule), - default->analytics(userJourneyAnalyticsFlag), - default->connectors(isLiveMode), - default->workflow(isSurchargeEnabled), - frm->fraudAndRisk, - payOut->payoutConnectors, + default->operations(customersModule, ~permissionList), + default->analytics(userJourneyAnalyticsFlag, ~permissionList), + default->connectors(isLiveMode, ~permissionList), + default->workflow(isSurchargeEnabled, ~permissionList), + frm->fraudAndRisk(~permissionList), + payOut->payoutConnectors(~permissionList), recon->reconTag(isReconEnabled), - default->developers(userRole, systemMetrics), + default->developers(userRole, systemMetrics, ~permissionList), settings( ~isUserManagementEnabled=userManagement, ~isBusinessProfileEnabled=businessProfile, ~isSampleDataEnabled=sampleData, + ~permissionList, ), ] sidebar diff --git a/src/screens/HyperSwitch/UserManagement/PermissionHelper.res b/src/screens/HyperSwitch/UserManagement/PermissionHelper.res new file mode 100644 index 000000000..8084d8bf4 --- /dev/null +++ b/src/screens/HyperSwitch/UserManagement/PermissionHelper.res @@ -0,0 +1,110 @@ +type permissionType = + | PaymentRead + | PaymentWrite + | RefundRead + | RefundWrite + | ApiKeyRead + | ApiKeyWrite + | MerchantAccountRead + | MerchantAccountWrite + | MerchantConnectorAccountRead + | MerchantConnectorAccountWrite + | ForexRead + | RoutingRead + | RoutingWrite + | DisputeRead + | DisputeWrite + | MandateRead + | MandateWrite + | CustomerRead + | CustomerWrite + | FileRead + | FileWrite + | Analytics + | ThreeDsDecisionManagerWrite + | ThreeDsDecisionManagerRead + | SurchargeDecisionManagerWrite + | SurchargeDecisionManagerRead + | UsersRead + | UsersWrite + | UnknownPermission(string) + +let mapPermissionTypeToString = permissionType => { + switch permissionType { + | PaymentRead => "PaymentRead" + | PaymentWrite => "PaymentWrite" + | RefundRead => "RefundRead" + | RefundWrite => "RefundWrite" + | ApiKeyRead => "ApiKeyRead" + | ApiKeyWrite => "ApiKeyWrite" + | MerchantAccountRead => "MerchantAccountRead" + | MerchantAccountWrite => "MerchantAccountWrite" + | MerchantConnectorAccountRead => "MerchantConnectorAccountRead" + | MerchantConnectorAccountWrite => "MerchantConnectorAccountWrite" + | ForexRead => "ForexRead" + | RoutingRead => "RoutingRead" + | RoutingWrite => "RoutingWrite" + | DisputeRead => "DisputeRead" + | DisputeWrite => "DisputeWrite" + | MandateRead => "MandateRead" + | MandateWrite => "MandateWrite" + | CustomerRead => "CustomerRead" + | CustomerWrite => "CustomerWrite" + | FileRead => "FileRead" + | FileWrite => "FileWrite" + | Analytics => "Analytics" + | ThreeDsDecisionManagerWrite => "ThreeDsDecisionManagerWrite" + | ThreeDsDecisionManagerRead => "ThreeDsDecisionManagerRead" + | SurchargeDecisionManagerWrite => "SurchargeDecisionManagerWrite" + | SurchargeDecisionManagerRead => "SurchargeDecisionManagerRead" + | UsersRead => "UsersRead" + | UsersWrite => "UsersWrite" + | UnknownPermission(val) => val + } +} + +let mapStringToPermissionType = val => { + switch val { + | "PaymentRead" => PaymentRead + | "PaymentWrite" => PaymentWrite + | "RefundRead" => RefundRead + | "RefundWrite" => RefundWrite + | "ApiKeyRead" => ApiKeyRead + | "ApiKeyWrite" => ApiKeyWrite + | "MerchantAccountRead" => MerchantAccountRead + | "MerchantAccountWrite" => MerchantAccountWrite + | "MerchantConnectorAccountRead" => MerchantConnectorAccountRead + | "MerchantConnectorAccountWrite" => MerchantConnectorAccountWrite + | "ForexRead" => ForexRead + | "RoutingRead" => RoutingRead + | "RoutingWrite" => RoutingWrite + | "DisputeRead" => DisputeRead + | "DisputeWrite" => DisputeWrite + | "MandateRead" => MandateRead + | "MandateWrite" => MandateWrite + | "CustomerRead" => CustomerRead + | "CustomerWrite" => CustomerWrite + | "FileRead" => FileRead + | "FileWrite" => FileWrite + | "Analytics" => Analytics + | "ThreeDsDecisionManagerWrite" => ThreeDsDecisionManagerWrite + | "ThreeDsDecisionManagerRead" => ThreeDsDecisionManagerRead + | "SurchargeDecisionManagerWrite" => SurchargeDecisionManagerWrite + | "SurchargeDecisionManagerRead" => SurchargeDecisionManagerRead + | "UsersRead" => UsersRead + | "UsersWrite" => UsersWrite + | val => UnknownPermission(val) + } +} + +let getAccessValue = (~permissionValue: permissionType, permissionList) => { + open AuthTypes + let isPermissionFound = + permissionList + ->Array.find(ele => { + ele === permissionValue + }) + ->Option.getWithDefault(UnknownPermission("")) + + isPermissionFound->mapPermissionTypeToString->String.length > 0 ? Read : NoAccess +} diff --git a/src/screens/HyperSwitch/Utils/HSwitchGlobalSearchBar.res b/src/screens/HyperSwitch/Utils/HSwitchGlobalSearchBar.res index 9e4829184..d6e8f24ab 100644 --- a/src/screens/HyperSwitch/Utils/HSwitchGlobalSearchBar.res +++ b/src/screens/HyperSwitch/Utils/HSwitchGlobalSearchBar.res @@ -57,18 +57,11 @@ let make = () => { let (showModal, setShowModal) = React.useState(_ => false) let (searchText, setSearchText) = React.useState(_ => "") let (arr, setArr) = React.useState(_ => []) - let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom let merchentDetails = HSwitchUtils.useMerchantDetailsValue() - let userRole = HSLocalStorage.getFromUserDetails("user_role") let isReconEnabled = (merchentDetails->MerchantAccountUtils.getMerchantDetails).recon_status === Active - let hswitchTabs = SidebarValues.getHyperSwitchAppSidebars( - ~isReconEnabled, - ~featureFlagDetails, - ~userRole, - (), - ) + let hswitchTabs = SidebarValues.useGetSidebarValues(~isReconEnabled) let searchText = searchText->String.trim React.useEffect1(_ => { let matchedList = hswitchTabs->Array.reduce([], (acc, item) => { diff --git a/src/screens/login/AuthTypes.res b/src/screens/login/AuthTypes.res index cf51ce9fc..a28e0757d 100644 --- a/src/screens/login/AuthTypes.res +++ b/src/screens/login/AuthTypes.res @@ -1 +1 @@ -type authorization = NoAccess | Read | ReadWrite | Checker +type authorization = NoAccess | Read | ReadWrite From 8d87eb38cc976b9983a19aaa78f1ae47eb733d58 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Jan 2024 17:20:19 +0530 Subject: [PATCH 3/6] fix: app removal --- .../hyperswitch/HyperSwitchApp.res | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/src/entryPoints/hyperswitch/HyperSwitchApp.res b/src/entryPoints/hyperswitch/HyperSwitchApp.res index e9e8f1cac..c692c94d8 100644 --- a/src/entryPoints/hyperswitch/HyperSwitchApp.res +++ b/src/entryPoints/hyperswitch/HyperSwitchApp.res @@ -40,7 +40,6 @@ let make = () => { ->QuickStartUtils.getTypedValueFromDict let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom - let setUserPermissionsList = Recoil.useSetRecoilState(HyperswitchAtom.userPermissionAtom) let getEnumDetails = EnumVariantHook.useFetchEnumDetails() let verificationDays = getFromMerchantDetails("verification")->LogicUtils.getIntFromString(-1) let userRole = getFromUserDetails("user_role") @@ -111,37 +110,8 @@ let make = () => { } } - let fetchPermissionsForARole = async () => { - try { - let url = getURL( - ~entityName=USER_MANAGEMENT, - ~userRoleTypes=ROLE_ID, - ~id={ - Some(userRole === "org_admin" ? "merchant_admin" : userRole) - }, - ~methodType=Get, - (), - ) - let response = await fetchDetails(url) - let permissionsValue = - response - ->LogicUtils.getDictFromJsonObject - ->LogicUtils.getArrayFromDict("permissions", []) - ->Array.map(ele => ele->Js.Json.decodeString->Option.getWithDefault("")) - let mapPermissionArrayToType = - permissionsValue->Array.map(ele => ele->PermissionHelper.mapStringToPermissionType) - setUserPermissionsList(._ => mapPermissionArrayToType) - } catch { - | Js.Exn.Error(e) => { - let err = Js.Exn.message(e)->Belt.Option.getWithDefault("Failed to Fetch!") - Js.Exn.raiseError(err) - } - } - } - let setUpDashboard = async () => { try { - let _ = await fetchPermissionsForARole() let _ = await Window.connectorWasmInit() let _ = await fetchBusinessProfiles() let _ = await fetchConnectorListResponse() From f9b9a8d436a7effb4761cefab763d06740c3a84c Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Jan 2024 17:22:53 +0530 Subject: [PATCH 4/6] fix: sidebar values change --- src/entryPoints/hyperswitch/SidebarValues.res | 334 +++++++----------- 1 file changed, 118 insertions(+), 216 deletions(-) diff --git a/src/entryPoints/hyperswitch/SidebarValues.res b/src/entryPoints/hyperswitch/SidebarValues.res index b35550b19..3717fc222 100644 --- a/src/entryPoints/hyperswitch/SidebarValues.res +++ b/src/entryPoints/hyperswitch/SidebarValues.res @@ -1,5 +1,4 @@ open SidebarTypes -open PermissionHelper // * Custom Component @@ -40,7 +39,6 @@ module GetProductionAccess = { let emptyComponent = CustomComponent({ component: React.null, }) - let productionAccessComponent = isProductionAccessEnabled => isProductionAccessEnabled ? CustomComponent({ @@ -60,59 +58,35 @@ let home = isHomeEnabled => }) : emptyComponent -let payments = permissionList => { - let paymentPermission = PaymentRead - let accessValue = getAccessValue(~permissionValue=paymentPermission, permissionList) - - SubLevelLink({ - name: "Payments", - link: `/payments`, - access: accessValue, - searchOptions: [("View payment operations", "")], - }) -} - -let refunds = permissionList => { - let refundPermission = RefundRead - let accessValue = getAccessValue(~permissionValue=refundPermission, permissionList) - - SubLevelLink({ - name: "Refunds", - link: `/refunds`, - access: accessValue, - searchOptions: [("View refund operations", "")], - }) -} - -let disputes = permissionList => { - let disputePermission = DisputeRead - let accessValue = getAccessValue(~permissionValue=disputePermission, permissionList) +let payments = SubLevelLink({ + name: "Payments", + link: `/payments`, + access: ReadWrite, + searchOptions: [("View payment operations", "")], +}) - SubLevelLink({ - name: "Disputes", - link: `/disputes`, - access: accessValue, - searchOptions: [("View dispute operations", "")], - }) -} +let refunds = SubLevelLink({ + name: "Refunds", + link: `/refunds`, + access: ReadWrite, + searchOptions: [("View refund operations", "")], +}) -let customers = permissionList => { - let customersPermission = CustomerRead - let accessValue = getAccessValue(~permissionValue=customersPermission, permissionList) - SubLevelLink({ - name: "Customers", - link: `/customers`, - access: accessValue, - searchOptions: [("View customers", "")], - }) -} +let disputes = SubLevelLink({ + name: "Disputes", + link: `/disputes`, + access: ReadWrite, + searchOptions: [("View dispute operations", "")], +}) -let operations = (isOperationsEnabled, customersModule, ~permissionList) => { - let payments = payments(permissionList) - let refunds = refunds(permissionList) - let disputes = disputes(permissionList) - let customers = customers(permissionList) +let customers = SubLevelLink({ + name: "Customers", + link: `/customers`, + access: ReadWrite, + searchOptions: [("View customers", "")], +}) +let operations = (isOperationsEnabled, customersModule) => { isOperationsEnabled ? Section({ name: "Operations", @@ -125,15 +99,13 @@ let operations = (isOperationsEnabled, customersModule, ~permissionList) => { : emptyComponent } -let connectors = (isConnectorsEnabled, isLiveMode, ~permissionList) => { - let connectorPermission = MerchantConnectorAccountRead - let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) +let connectors = (isConnectorsEnabled, isLiveMode) => { isConnectorsEnabled ? Link({ name: "Processors", link: `/connectors`, icon: "connectors", - access: accessValue, + access: ReadWrite, searchOptions: HSwitchUtils.getSearchOptionsForProcessors( ~processorList=isLiveMode ? ConnectorUtils.connectorListForLive @@ -166,63 +138,45 @@ let userJourneyAnalytics = SubLevelLink({ searchOptions: [("View analytics", "")], }) -let analytics = (isAnalyticsEnabled, userJourneyAnalyticsFlag, ~permissionList) => { - let analyticsPermission = Analytics - let accessValue = getAccessValue(~permissionValue=analyticsPermission, permissionList) - +let analytics = (isAnalyticsEnabled, userJourneyAnalyticsFlag) => isAnalyticsEnabled ? Section({ name: "Analytics", icon: "analytics", - showSection: accessValue === Read, + showSection: true, links: userJourneyAnalyticsFlag ? [paymentAnalytcis, refundAnalytics, userJourneyAnalytics] : [paymentAnalytcis, refundAnalytics], }) : emptyComponent -} -let routing = permissionList => { - let routingPermission = RoutingRead - let accessValue = getAccessValue(~permissionValue=routingPermission, permissionList) - SubLevelLink({ - name: "Routing", - link: `/routing`, - access: accessValue, - searchOptions: [ - ("Manage default routing configuration", "/default"), - ("Create new volume based routing", "/volume"), - ("Create new rule based routing", "/rule"), - ("Manage smart routing", ""), - ], - }) -} -let threeDs = permissionList => { - let threeDsPermission = ThreeDsDecisionManagerRead - let accessValue = getAccessValue(~permissionValue=threeDsPermission, permissionList) - SubLevelLink({ - name: "3DS Decision Manager", - link: `/3ds`, - access: accessValue, - searchOptions: [("Configure 3ds", "")], - }) -} -let surcharge = permissionList => { - let surchargePermission = SurchargeDecisionManagerRead - let accessValue = getAccessValue(~permissionValue=surchargePermission, permissionList) - SubLevelLink({ - name: "Surcharge", - link: `/surcharge`, - access: accessValue, - searchOptions: [("Add Surcharge", "")], - }) -} +let routing = SubLevelLink({ + name: "Routing", + link: `/routing`, + access: ReadWrite, + searchOptions: [ + ("Manage default routing configuration", "/default"), + ("Create new volume based routing", "/volume"), + ("Create new rule based routing", "/rule"), + ("Manage smart routing", ""), + ], +}) -let workflow = (isWorkflowEnabled, isSurchargeEnabled, ~permissionList) => { - let routing = routing(permissionList) - let threeDs = threeDs(permissionList) - let surcharge = surcharge(permissionList) +let threeDs = SubLevelLink({ + name: "3DS Decision Manager", + link: `/3ds`, + access: ReadWrite, + searchOptions: [("Configure 3ds", "")], +}) + +let surcharge = SubLevelLink({ + name: "Surcharge", + link: `/surcharge`, + access: ReadWrite, + searchOptions: [("Add Surcharge", "")], +}) +let workflow = (isWorkflowEnabled, isSurchargeEnabled) => isWorkflowEnabled ? Section({ name: "Workflow", @@ -231,74 +185,50 @@ let workflow = (isWorkflowEnabled, isSurchargeEnabled, ~permissionList) => { links: isSurchargeEnabled ? [routing, threeDs, surcharge] : [routing, threeDs], }) : emptyComponent -} -let userManagement = permissionList => { - let userPermission = UsersRead - let accessValue = getAccessValue(~permissionValue=userPermission, permissionList) - SubLevelLink({ - name: "Team", - link: `/users`, - access: accessValue, - searchOptions: [("View team management", "")], - }) -} +let userManagement = SubLevelLink({ + name: "Team", + link: `/users`, + access: ReadWrite, + searchOptions: [("View team management", "")], +}) -let accountSettings = permissionList => { - // Because it has delete sample data - let merchantAccountPermission = MerchantAccountWrite - let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) - - SubLevelLink({ - name: "Account Settings", - link: `/account-settings`, - access: accessValue, - searchOptions: [ - ("View profile", "/profile"), - ("Change password", "/profile"), - ("Manage your personal profile and preferences", "/profile"), - ], - }) -} +let accountSettings = SubLevelLink({ + name: "Account Settings", + link: `/account-settings`, + access: ReadWrite, + searchOptions: [ + ("View profile", "/profile"), + ("Change password", "/profile"), + ("Manage your personal profile and preferences", "/profile"), + ], +}) -let businessDetails = permissionList => { - let merchantAccountPermission = MerchantAccountRead - let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) +let businessDetails = SubLevelLink({ + name: "Business Details", + link: `/business-details`, + access: ReadWrite, + searchOptions: [("Configure business details", "")], +}) - SubLevelLink({ - name: "Business Details", - link: `/business-details`, - access: accessValue, - searchOptions: [("Configure business details", "")], - }) -} +let businessProfiles = SubLevelLink({ + name: "Business Profiles", + link: `/business-profiles`, + access: ReadWrite, + searchOptions: [("Configure business profiles", "")], +}) -let businessProfiles = permissionList => { - let merchantAccountPermission = MerchantAccountRead - let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) - SubLevelLink({ - name: "Business Profiles", - link: `/business-profiles`, - access: accessValue, - searchOptions: [("Configure business profiles", "")], - }) -} -let settings = ( - ~isSampleDataEnabled, - ~isUserManagementEnabled, - ~isBusinessProfileEnabled, - ~permissionList, -) => { - let settingsLinkArray = [businessDetails(permissionList)] +let settings = (~isSampleDataEnabled, ~isUserManagementEnabled, ~isBusinessProfileEnabled) => { + let settingsLinkArray = [businessDetails] if isBusinessProfileEnabled { - settingsLinkArray->Array.push(businessProfiles(permissionList))->ignore + settingsLinkArray->Array.push(businessProfiles)->ignore } if isSampleDataEnabled { - settingsLinkArray->Array.push(accountSettings(permissionList))->ignore + settingsLinkArray->Array.push(accountSettings)->ignore } if isUserManagementEnabled { - settingsLinkArray->Array.push(userManagement(permissionList))->ignore + settingsLinkArray->Array.push(userManagement)->ignore } Section({ @@ -309,48 +239,30 @@ let settings = ( }) } -let apiKeys = permissionList => { - let apiKeyPermission = ApiKeyRead - let accessValue = getAccessValue(~permissionValue=apiKeyPermission, permissionList) - - SubLevelLink({ - name: "API Keys", - link: `/developer-api-keys`, - access: accessValue, - searchOptions: [("View API Keys", "")], - }) -} - -let systemMetric = permissionList => { - let analyticsPermission = Analytics - let accessValue = getAccessValue(~permissionValue=analyticsPermission, permissionList) - - SubLevelLink({ - name: "System Metrics", - link: `/developer-system-metrics`, - access: accessValue, - iconTag: "betaTag", - searchOptions: [("View System Metrics", "")], - }) -} +let apiKeys = SubLevelLink({ + name: "API Keys", + link: `/developer-api-keys`, + access: ReadWrite, + searchOptions: [("View API Keys", "")], +}) -let paymentSettings = permissionList => { - let merchantAccountPermission = MerchantAccountRead - let accessValue = getAccessValue(~permissionValue=merchantAccountPermission, permissionList) +let systemMetric = SubLevelLink({ + name: "System Metrics", + link: `/developer-system-metrics`, + access: ReadWrite, + iconTag: "betaTag", + searchOptions: [("View System Metrics", "")], +}) - SubLevelLink({ - name: "Payment Settings", - link: `/payment-settings`, - access: accessValue, - searchOptions: [("View payment settings", ""), ("View webhooks", ""), ("View return url", "")], - }) -} +let paymentSettings = SubLevelLink({ + name: "Payment Settings", + link: `/payment-settings`, + access: ReadWrite, + searchOptions: [("View payment settings", ""), ("View webhooks", ""), ("View return url", "")], +}) -let developers = (isDevelopersEnabled, userRole, systemMetrics, ~permissionList) => { +let developers = (isDevelopersEnabled, userRole, systemMetrics) => { let isInternalUser = userRole->String.includes("internal_") - let apiKeys = apiKeys(permissionList) - let paymentSettings = paymentSettings(permissionList) - let systemMetric = systemMetric(permissionList) isDevelopersEnabled ? Section({ @@ -364,38 +276,30 @@ let developers = (isDevelopersEnabled, userRole, systemMetrics, ~permissionList) : emptyComponent } -let fraudAndRisk = (isfraudAndRiskEnabled, ~permissionList) => { - let connectorPermission = MerchantConnectorAccountRead - let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) - +let fraudAndRisk = isfraudAndRiskEnabled => isfraudAndRiskEnabled ? Link({ name: "Fraud & Risk", icon: "shield-alt", link: `/fraud-risk-management`, - access: accessValue, + access: isfraudAndRiskEnabled ? ReadWrite : NoAccess, searchOptions: [], }) : emptyComponent -} - -let payoutConnectors = (isPayoutConnectorsEnabled, ~permissionList) => { - let connectorPermission = MerchantConnectorAccountRead - let accessValue = getAccessValue(~permissionValue=connectorPermission, permissionList) +let payoutConnectors = isPayoutConnectorsEnabled => isPayoutConnectorsEnabled ? Link({ name: "Payout Processors", link: `/payoutconnectors`, icon: "connectors", - access: accessValue, + access: ReadWrite, searchOptions: HSwitchUtils.getSearchOptionsForProcessors( ~processorList=ConnectorUtils.payoutConnectorList, ~getNameFromString=ConnectorUtils.getConnectorNameString, ), }) : emptyComponent -} let reconTag = (recon, isReconEnabled) => recon @@ -410,7 +314,6 @@ let reconTag = (recon, isReconEnabled) => let useGetSidebarValues = (~isReconEnabled: bool) => { let userRole = HSLocalStorage.getFromUserDetails("user_role") let featureFlagDetails = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom - let permissionList = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom) let { productionAccess, @@ -431,19 +334,18 @@ let useGetSidebarValues = (~isReconEnabled: bool) => { let sidebar = [ productionAccess->productionAccessComponent, default->home, - default->operations(customersModule, ~permissionList), - default->analytics(userJourneyAnalyticsFlag, ~permissionList), - default->connectors(isLiveMode, ~permissionList), - default->workflow(isSurchargeEnabled, ~permissionList), - frm->fraudAndRisk(~permissionList), - payOut->payoutConnectors(~permissionList), + default->operations(customersModule), + default->analytics(userJourneyAnalyticsFlag), + default->connectors(isLiveMode), + default->workflow(isSurchargeEnabled), + frm->fraudAndRisk, + payOut->payoutConnectors, recon->reconTag(isReconEnabled), - default->developers(userRole, systemMetrics, ~permissionList), + default->developers(userRole, systemMetrics), settings( ~isUserManagementEnabled=userManagement, ~isBusinessProfileEnabled=businessProfile, ~isSampleDataEnabled=sampleData, - ~permissionList, ), ] sidebar From 82465cf0ff5ac82f93ba31203c8942abeb92591c Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Jan 2024 17:49:33 +0530 Subject: [PATCH 5/6] chore: comments addressed --- .../HyperSwitch/UserManagement/PermissionHelper.res | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/screens/HyperSwitch/UserManagement/PermissionHelper.res b/src/screens/HyperSwitch/UserManagement/PermissionHelper.res index 8084d8bf4..d75e19b33 100644 --- a/src/screens/HyperSwitch/UserManagement/PermissionHelper.res +++ b/src/screens/HyperSwitch/UserManagement/PermissionHelper.res @@ -99,12 +99,9 @@ let mapStringToPermissionType = val => { let getAccessValue = (~permissionValue: permissionType, permissionList) => { open AuthTypes - let isPermissionFound = - permissionList - ->Array.find(ele => { - ele === permissionValue - }) - ->Option.getWithDefault(UnknownPermission("")) + let isPermissionFound = permissionList->Array.find(ele => { + ele === permissionValue + }) - isPermissionFound->mapPermissionTypeToString->String.length > 0 ? Read : NoAccess + isPermissionFound->Option.isSome ? Read : NoAccess } From 8e1f2ddc9761225714ff49f1e9b96aa1bbaa5100 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Jan 2024 17:52:38 +0530 Subject: [PATCH 6/6] chore: file name changes --- src/entryPoints/hyperswitch/HyperswitchAtom.res | 2 +- .../{PermissionHelper.res => PermissionUtils.res} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/screens/HyperSwitch/UserManagement/{PermissionHelper.res => PermissionUtils.res} (100%) diff --git a/src/entryPoints/hyperswitch/HyperswitchAtom.res b/src/entryPoints/hyperswitch/HyperswitchAtom.res index d2dcbca7d..9a600b266 100644 --- a/src/entryPoints/hyperswitch/HyperswitchAtom.res +++ b/src/entryPoints/hyperswitch/HyperswitchAtom.res @@ -14,7 +14,7 @@ let paypalAccountStatusAtom: Recoil.recoilAtom> = Recoil.atom(. +let userPermissionAtom: Recoil.recoilAtom> = Recoil.atom(. "userPermissionAtom", [], ) diff --git a/src/screens/HyperSwitch/UserManagement/PermissionHelper.res b/src/screens/HyperSwitch/UserManagement/PermissionUtils.res similarity index 100% rename from src/screens/HyperSwitch/UserManagement/PermissionHelper.res rename to src/screens/HyperSwitch/UserManagement/PermissionUtils.res