From 8ecc87dbdd24563235554a67a98707e66baabf99 Mon Sep 17 00:00:00 2001 From: Ha Minh Chien Date: Tue, 20 Feb 2024 17:24:47 +0700 Subject: [PATCH] update auth --- .../layout/AppDrawer/drawer-items.tsx | 30 +++++++++------- .../src/components/layout/AppDrawer/hooks.tsx | 2 ++ .../src/components/layout/AppDrawer/utils.ts | 36 +++++++++++++++++++ apps/hcdc-web-app/src/features/auth/slice.ts | 4 +-- libs/hcdc/src/auth/utils.ts | 23 ++++++++++-- 5 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 apps/hcdc-web-app/src/components/layout/AppDrawer/utils.ts diff --git a/apps/hcdc-web-app/src/components/layout/AppDrawer/drawer-items.tsx b/apps/hcdc-web-app/src/components/layout/AppDrawer/drawer-items.tsx index bcd87009..8aec0690 100644 --- a/apps/hcdc-web-app/src/components/layout/AppDrawer/drawer-items.tsx +++ b/apps/hcdc-web-app/src/components/layout/AppDrawer/drawer-items.tsx @@ -1,5 +1,4 @@ -import { ReactElement } from 'react' -import { To } from 'react-router-dom' +import { AuthSubject, PatientAction, SampleAction } from '@diut/hcdc' import AccountBoxIcon from '@mui/icons-material/AccountBoxOutlined' import HomeIcon from '@mui/icons-material/HomeOutlined' import VaccinesIcon from '@mui/icons-material/VaccinesOutlined' @@ -21,16 +20,7 @@ import PersonSearchIcon from '@mui/icons-material/PersonSearch' import FileDownloadIcon from '@mui/icons-material/FileDownload' import MapsHomeWorkIcon from '@mui/icons-material/MapsHomeWork' -export interface MenuItem { - icon: ReactElement - label: string - destination: To -} - -export interface DrawerItem { - title: string - children: MenuItem[] -} +import { DrawerItem, authOneOf } from './utils' export const drawerItems: DrawerItem[] = [ { @@ -45,21 +35,34 @@ export const drawerItems: DrawerItem[] = [ icon: , label: 'Nhập TT', destination: 'info', + isAuthorized: authOneOf([ + { subject: AuthSubject.Sample, action: SampleAction.UpdateInfo }, + ]), }, { icon: , label: 'Xác nhận TT', destination: 'info/confirm', + isAuthorized: authOneOf([ + { subject: AuthSubject.Sample, action: SampleAction.UpdateInfo }, + ]), }, { icon: , label: 'Nhập KQ', destination: 'result', + isAuthorized: authOneOf([ + { subject: AuthSubject.Sample, action: SampleAction.UpdateResult }, + ]), }, { icon: , label: 'In KQ', destination: 'result/print', + isAuthorized: authOneOf([ + { subject: AuthSubject.Sample, action: SampleAction.UpdateResult }, + { subject: AuthSubject.Sample, action: SampleAction.PrintResult }, + ]), }, { icon: , @@ -70,6 +73,9 @@ export const drawerItems: DrawerItem[] = [ icon: , label: 'Tìm kiếm', destination: 'patient/search', + isAuthorized: authOneOf([ + { subject: AuthSubject.Patient, action: PatientAction.Read }, + ]), }, { icon: , diff --git a/apps/hcdc-web-app/src/components/layout/AppDrawer/hooks.tsx b/apps/hcdc-web-app/src/components/layout/AppDrawer/hooks.tsx index 9a1db15c..e47c9c21 100644 --- a/apps/hcdc-web-app/src/components/layout/AppDrawer/hooks.tsx +++ b/apps/hcdc-web-app/src/components/layout/AppDrawer/hooks.tsx @@ -1,6 +1,8 @@ import { checkPermission } from '@diut/hcdc' import { useTypedSelector } from 'src/infra/redux' +import { drawerItems } from './drawer-items' +import { selectUserPermissions } from 'src/features/auth' export function useDrawerItems() { const userPermissions = useTypedSelector(selectUserPermissions) diff --git a/apps/hcdc-web-app/src/components/layout/AppDrawer/utils.ts b/apps/hcdc-web-app/src/components/layout/AppDrawer/utils.ts new file mode 100644 index 00000000..f01f707a --- /dev/null +++ b/apps/hcdc-web-app/src/components/layout/AppDrawer/utils.ts @@ -0,0 +1,36 @@ +import { PermissionRule, isAuthorizedOneOf } from '@diut/hcdc' +import { ReactElement } from 'react' +import { To } from 'react-router-dom' + +export interface MenuItem { + icon: ReactElement + label: string + destination: To + isAuthorized?: ( + userPermissions: PermissionRule[], + branchId: string, + ) => boolean +} + +export interface DrawerItem { + title: string + children: MenuItem[] +} + +export function authOneOf( + authDetails: Parameters[1], +) { + return (userPermissions: PermissionRule[], branchId: string) => { + if (branchId) { + return isAuthorizedOneOf( + userPermissions, + authDetails.map(({ filterObj: originalFilterObj, ...details }) => ({ + ...details, + filterObj: { ...(originalFilterObj ?? {}), branchId }, + })), + ) + } + + return isAuthorizedOneOf(userPermissions, authDetails) + } +} diff --git a/apps/hcdc-web-app/src/features/auth/slice.ts b/apps/hcdc-web-app/src/features/auth/slice.ts index 0f1ffdfa..1158da33 100644 --- a/apps/hcdc-web-app/src/features/auth/slice.ts +++ b/apps/hcdc-web-app/src/features/auth/slice.ts @@ -7,6 +7,7 @@ import { import { persistReducer } from 'redux-persist' import storage from 'redux-persist/lib/storage' import { toast } from 'react-toastify' +import { PermissionRule } from '@diut/hcdc' import { authApi } from 'src/infra/api/access-service/auth' import { RootState } from 'src/infra/redux' @@ -14,8 +15,7 @@ import { RootState } from 'src/infra/redux' interface AuthState { id?: string name?: string - accessToken?: string - permissions?: Permission[] + permissions?: PermissionRule[] } // Reset store state on user logout or token expiration diff --git a/libs/hcdc/src/auth/utils.ts b/libs/hcdc/src/auth/utils.ts index 1f72a545..fcce3824 100644 --- a/libs/hcdc/src/auth/utils.ts +++ b/libs/hcdc/src/auth/utils.ts @@ -6,8 +6,12 @@ import { } from '@casl/ability' import { $or, or } from '@ucast/mongo2js' -import { AuthAction } from './action' -import { AuthSubject, SubjectEntityMapping } from './subject' +import { AuthAction, AuthActionUnionType } from './action' +import { + AuthSubject, + AuthSubjectUnionType, + SubjectEntityMapping, +} from './subject' import { AUTH_ACTION_ALL, AUTH_SUBJECT_ALL } from './constants' import { PermissionRule } from '../entity' @@ -29,3 +33,18 @@ export function checkPermission( return ability.can(action, subject) } + +export function isAuthorizedOneOf( + userPermissions: PermissionRule[], + authDetails: { + subject: AuthSubjectUnionType + action: AuthActionUnionType + filterObj?: unknown + }[], +): boolean { + const ability = createAbility(userPermissions) + + return authDetails.some(({ subject, action, filterObj }) => + checkPermission(ability, subject, action, filterObj), + ) +}