Skip to content

Commit

Permalink
Merge branch 'configurable-roles' into remove-client-queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Nil20 committed Nov 8, 2024
2 parents 733b752 + 5dbf04f commit a293994
Show file tree
Hide file tree
Showing 67 changed files with 1,370 additions and 1,931 deletions.
7 changes: 6 additions & 1 deletion packages/auth/src/features/authenticateSuperUser/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '@auth/features/authenticate/service'
import { unauthorized } from '@hapi/boom'
import { WEB_USER_JWT_AUDIENCES, JWT_ISSUER } from '@auth/constants'
import { SUPER_ADMIN_SCOPES } from '@opencrvs/commons/authentication'
import { Scope, SCOPES } from '@opencrvs/commons/authentication'
import { logger } from '@opencrvs/commons'

interface IAuthPayload {
Expand All @@ -43,6 +43,11 @@ export default async function authenticateSuperUserHandler(
throw unauthorized()
}

const SUPER_ADMIN_SCOPES = [
SCOPES.BYPASSRATELIMIT,
SCOPES.CONFIG_UPDATE_ALL
] satisfies Scope[]

const token = await createToken(
result.userId,
SUPER_ADMIN_SCOPES,
Expand Down
1 change: 0 additions & 1 deletion packages/auth/src/features/refresh/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ describe('authenticate handler receives a request', () => {
SCOPES.USER_CREATE,
SCOPES.USER_READ,
SCOPES.USER_UPDATE,
SCOPES.ORGANISATION_READ,
SCOPES.ORGANISATION_READ_LOCATIONS,
SCOPES.PERFORMANCE_READ,
SCOPES.PERFORMANCE_READ_DASHBOARDS,
Expand Down
1 change: 0 additions & 1 deletion packages/auth/src/features/verifyCode/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ describe('authenticate handler receives a request', () => {
SCOPES.USER_CREATE,
SCOPES.USER_READ,
SCOPES.USER_UPDATE,
SCOPES.ORGANISATION_READ,
SCOPES.ORGANISATION_READ_LOCATIONS,
SCOPES.PERFORMANCE_READ,
SCOPES.PERFORMANCE_READ_DASHBOARDS,
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"build": "NODE_OPTIONS=--max_old_space_size=8000 vite build",
"docker:build": "docker build ../../ -f ../../Dockerfile-register -t ocrvs-client",
"docker:run": "docker run -it --rm -p 5000:80 --name ocrvs-client ocrvs-client",
"test": "yarn test:compilation && NODE_OPTIONS=--max_old_space_size=8000 vitest run --allowOnly",
"test": "yarn test:compilation && NODE_OPTIONS=--max_old_space_size=8000 vitest run",
"test:watch": "vitest",
"open:cov": "yarn test && opener coverage/index.html",
"lint": "yarn lint:css && yarn lint:ts",
Expand Down
7 changes: 2 additions & 5 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ export function App(props: IAppProps) {
<ProtectedRoute
exact
scopes={[
SCOPES.RECORD_PRINT_RECORDS
SCOPES.RECORD_REGISTRATION_PRINT
]}
path={routes.VERIFY_COLLECTOR}
component={VerifyCollector}
Expand Down Expand Up @@ -509,10 +509,7 @@ export function App(props: IAppProps) {
/>
<ProtectedRoute
exact
scopes={[
SCOPES.PERFORMANCE_READ,
SCOPES.PERFORMANCE_READ_MY_OFFICE
]}
scopes={[SCOPES.PERFORMANCE_READ]}
path={routes.PERFORMANCE_HOME}
component={PerformanceHome}
/>
Expand Down
128 changes: 78 additions & 50 deletions packages/client/src/components/form/ReviewActionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import styled from 'styled-components'
import React, { useState } from 'react'
import { Button } from '@opencrvs/components/lib/Button'
import { Icon } from '@opencrvs/components/lib/Icon'
import ProtectedComponent from '@client/components/ProtectedComponent'
import { SCOPES } from '@client/utils/gateway'
import { usePermissions } from '@client/hooks/useAuthorization'

interface IReviewActionProps extends React.HTMLAttributes<HTMLDivElement> {
id?: string
Expand Down Expand Up @@ -89,12 +92,12 @@ const ActionContainer = styled.div`
flex-flow: row wrap;
align-items: center;
button:first-child {
margin-right: 16px;
}
button {
margin: 0 16px 8px 0;
& > button {
margin-bottom: 8px;
&:last-child {
margin-right: 0;
}
}
`

Expand Down Expand Up @@ -295,8 +298,6 @@ const ACTION_TO_CONTENT_MAP_SKELETON: (

const ReviewActionComponent = ({
id,
declarationToBeValidated,
declarationToBeRegistered,
alreadyRejectedDeclaration,
completeDeclaration,
totalFileSizeExceeded,
Expand All @@ -308,6 +309,13 @@ const ReviewActionComponent = ({
hasErrorsOnFields
}: IReviewActionProps & IntlShapeProps) => {
const [showSubmitModal, setShowSubmitModal] = useState(false)
const { hasAnyScope, hasScope } = usePermissions()

const declarationToBeRegistered = hasScope(SCOPES.RECORD_REGISTER)
const declarationToBeValidated = hasAnyScope([
SCOPES.RECORD_SUBMIT_FOR_APPROVAL,
SCOPES.RECORD_SUBMIT_FOR_UPDATES
])

const toggleSubmitModalOpen = () => {
setShowSubmitModal(!showSubmitModal)
Expand Down Expand Up @@ -336,6 +344,7 @@ const ReviewActionComponent = ({
String(draftDeclaration || alreadyRejectedDeclaration)
].completionStatus[String(completeDeclaration)]) ||
null

return !actionContent ? null : (
<Container id={id}>
<UnderLayBackground background={background} />
Expand All @@ -354,54 +363,73 @@ const ReviewActionComponent = ({
</Description>
<ActionContainer>
{declarationToBeRegistered ? (
<Button
type="positive"
size="large"
id="registerDeclarationBtn"
onClick={toggleSubmitModalOpen}
disabled={!completeDeclaration || totalFileSizeExceeded}
>
<Icon name="Check" />
{intl.formatMessage(buttonMessages.register)}
</Button>
<ProtectedComponent scopes={[SCOPES.RECORD_REGISTER]}>
<Button
type="positive"
size="large"
id="registerDeclarationBtn"
onClick={toggleSubmitModalOpen}
disabled={!completeDeclaration || totalFileSizeExceeded}
>
<Icon name="Check" />
{intl.formatMessage(buttonMessages.register)}
</Button>
</ProtectedComponent>
) : declarationToBeValidated ? (
<Button
type="positive"
size="large"
id="validateDeclarationBtn"
onClick={toggleSubmitModalOpen}
disabled={!completeDeclaration || totalFileSizeExceeded}
>
<Icon name="PaperPlaneTilt" />
{intl.formatMessage(buttonMessages.sendForApproval)}
</Button>
<ProtectedComponent scopes={[SCOPES.RECORD_SUBMIT_FOR_APPROVAL]}>
<Button
type="positive"
size="large"
id="validateDeclarationBtn"
onClick={toggleSubmitModalOpen}
disabled={!completeDeclaration || totalFileSizeExceeded}
>
<Icon name="PaperPlaneTilt" />
{intl.formatMessage(buttonMessages.sendForApproval)}
</Button>
</ProtectedComponent>
) : !completeDeclaration ? (
<ProtectedComponent scopes={[SCOPES.RECORD_SUBMIT_INCOMPLETE]}>
<Button
type="primary"
size="large"
id="submit_incomplete"
onClick={toggleSubmitModalOpen}
disabled={hasErrorsOnFields || totalFileSizeExceeded}
>
<Upload />
{intl.formatMessage(buttonMessages.sendIncomplete)}
</Button>
</ProtectedComponent>
) : (
<Button
type="primary"
size="large"
id="submit_form"
onClick={toggleSubmitModalOpen}
disabled={hasErrorsOnFields || totalFileSizeExceeded}
<ProtectedComponent
scopes={[SCOPES.RECORD_SUBMIT_FOR_REVIEW]}
denyScopes={[SCOPES.RECORD_SUBMIT_INCOMPLETE]}
>
<Upload />
{intl.formatMessage(
completeDeclaration
? buttonMessages.sendForReview
: buttonMessages.sendIncomplete
)}
</Button>
<Button
type="primary"
size="large"
id="submit_for_review"
onClick={toggleSubmitModalOpen}
disabled={hasErrorsOnFields || totalFileSizeExceeded}
>
<Upload />
{intl.formatMessage(buttonMessages.sendForReview)}
</Button>
</ProtectedComponent>
)}

{rejectDeclarationAction && !alreadyRejectedDeclaration && (
<Button
type="negative"
size="large"
id="rejectDeclarationBtn"
onClick={rejectDeclarationAction}
>
<Icon name="X" />
{intl.formatMessage(buttonMessages.reject)}
</Button>
<ProtectedComponent scopes={[SCOPES.RECORD_SUBMIT_FOR_UPDATES]}>
<Button
type="negative"
size="large"
id="rejectDeclarationBtn"
onClick={rejectDeclarationAction}
>
<Icon name="X" />
{intl.formatMessage(buttonMessages.reject)}
</Button>
</ProtectedComponent>
)}
</ActionContainer>
</Content>
Expand Down
68 changes: 35 additions & 33 deletions packages/client/src/components/interface/Navigation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ describe('Given a user with scopes views Navigation', () => {
describe('Requires update', async () => {
const id = `#navigation_${WORKQUEUE_TABS.requiresUpdate}`

const requiredScopes = [SCOPES.RECORD_DECLARATION_REVIEW] as Scope[]
const requiredScopes = [SCOPES.RECORD_SUBMIT_FOR_UPDATES] as Scope[]

const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
Expand All @@ -350,7 +350,10 @@ describe('Given a user with scopes views Navigation', () => {
describe('Ready for review', async () => {
const id = `#navigation_${WORKQUEUE_TABS.readyForReview}`

const requiredScopes = [SCOPES.RECORD_DECLARATION_REVIEW] as Scope[]
const requiredScopes = [
SCOPES.RECORD_SUBMIT_FOR_APPROVAL,
SCOPES.RECORD_SUBMIT_FOR_UPDATES
] as Scope[]

const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
Expand Down Expand Up @@ -446,15 +449,30 @@ describe('Given a user with scopes views Navigation', () => {
describe('Outbox', async () => {
const id = `#navigation_${WORKQUEUE_TABS.outbox}`

const excludedScopes = [SCOPES.SYSADMIN, SCOPES.NATLSYSADMIN] as Scope[]
const requiredScopes = [
SCOPES.RECORD_DECLARE_BIRTH,
SCOPES.RECORD_DECLARE_BIRTH_MY_JURISDICTION,
SCOPES.RECORD_DECLARE_DEATH,
SCOPES.RECORD_DECLARE_DEATH_MY_JURISDICTION,
SCOPES.RECORD_DECLARE_MARRIAGE,
SCOPES.RECORD_DECLARE_MARRIAGE_MY_JURISDICTION,
SCOPES.RECORD_SUBMIT_FOR_APPROVAL,
SCOPES.RECORD_SUBMIT_FOR_UPDATES,
SCOPES.RECORD_REVIEW_DUPLICATES,
SCOPES.RECORD_REGISTER,
SCOPES.RECORD_PRINT_ISSUE_CERTIFIED_COPIES,
SCOPES.RECORD_REGISTRATION_CORRECT,
SCOPES.RECORD_DECLARATION_ARCHIVE,
SCOPES.RECORD_DECLARATION_REINSTATE,
SCOPES.RECORD_REGISTRATION_REVOKE
] as Scope[]

const anyOtherScope = allScopes.filter(
(scope) => !excludedScopes.includes(scope)
const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
)
const tests = [
[[excludedScopes[0]], false],
[[excludedScopes[1]], false],
[anyOtherScope, true]
[requiredScopes, true],
[allOtherScopes, false]
]

tests.forEach(([scopes, exists]) => {
Expand All @@ -468,9 +486,9 @@ describe('Given a user with scopes views Navigation', () => {

describe('and user has organisation scopes', async () => {
const orgScopes = [
SCOPES.ORGANISATION_READ,
SCOPES.ORGANISATION_READ_LOCATIONS,
SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE
SCOPES.ORGANISATION_READ_LOCATIONS_MY_OFFICE,
SCOPES.ORGANISATION_READ_LOCATIONS_MY_JURISDICTION
] as Scope[]

describe('Performance', async () => {
Expand Down Expand Up @@ -506,7 +524,7 @@ describe('Given a user with scopes views Navigation', () => {
describe('Organisation', async () => {
const id = `#navigation_${WORKQUEUE_TABS.organisation}`

const requiredScopes = [SCOPES.ORGANISATION_READ] as Scope[]
const requiredScopes = [SCOPES.ORGANISATION_READ_LOCATIONS] as Scope[]

const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
Expand Down Expand Up @@ -556,20 +574,14 @@ describe('Given a user with scopes views Navigation', () => {
describe('Config', async () => {
const id = `#navigation_${WORKQUEUE_TABS.config}_main`

const requiredScopes = [SCOPES.SYSADMIN, SCOPES.NATLSYSADMIN] as Scope[]
const requiredScopes = [...orgScopes, SCOPES.CONFIG_UPDATE_ALL] as Scope[]

const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
)

const tests = [
[[requiredScopes[0], orgScopes[0]], true],
[[requiredScopes[0], orgScopes[1]], true],
[[requiredScopes[0], orgScopes[2]], true],
[[requiredScopes[1], orgScopes[0]], true],
[[requiredScopes[1], orgScopes[1]], true],
[[requiredScopes[1], orgScopes[2]], true],
[requiredScopes, false],
[requiredScopes, true],
[allOtherScopes, false]
]

Expand All @@ -585,9 +597,7 @@ describe('Given a user with scopes views Navigation', () => {
describe('Systems', async () => {
const id = `#navigation_${WORKQUEUE_TABS.systems}`

const requiredScopes = (
[SCOPES.SYSADMIN, SCOPES.NATLSYSADMIN] as Scope[]
).concat(orgScopes)
const requiredScopes = [...orgScopes, SCOPES.CONFIG_UPDATE_ALL] as Scope[]

const tests = [[requiredScopes, true]]

Expand All @@ -608,20 +618,14 @@ describe('Given a user with scopes views Navigation', () => {
describe('Communications', async () => {
const id = `#navigation_${WORKQUEUE_TABS.communications}_main`

const requiredScopes = [SCOPES.SYSADMIN, SCOPES.NATLSYSADMIN] as Scope[]
const requiredScopes = [...orgScopes, SCOPES.CONFIG_UPDATE_ALL] as Scope[]

const allOtherScopes = allScopes.filter(
(scope) => !requiredScopes.includes(scope)
)

const tests = [
[[requiredScopes[0], orgScopes[0]], true],
[[requiredScopes[0], orgScopes[1]], true],
[[requiredScopes[0], orgScopes[2]], true],
[[requiredScopes[1], orgScopes[0]], true],
[[requiredScopes[1], orgScopes[1]], true],
[[requiredScopes[1], orgScopes[2]], true],
[requiredScopes, false],
[requiredScopes, true],
[allOtherScopes, false]
]

Expand All @@ -637,9 +641,7 @@ describe('Given a user with scopes views Navigation', () => {
describe('Email all users', async () => {
const id = `#navigation_${WORKQUEUE_TABS.emailAllUsers}`

const requiredScopes = (
[SCOPES.SYSADMIN, SCOPES.NATLSYSADMIN] as Scope[]
).concat(orgScopes)
const requiredScopes = [...orgScopes, SCOPES.CONFIG_UPDATE_ALL] as Scope[]

const tests = [[requiredScopes, true]]

Expand Down
Loading

0 comments on commit a293994

Please sign in to comment.