Skip to content

Commit

Permalink
(User roles) fix search scope bugs (#8267)
Browse files Browse the repository at this point in the history
* fix: amend active tab id of advance search

* fix: hide advance searching based on scopes

* fix: remove marriage scope from advance search component permission scope

* chore: refactor advance search section to receive param

* chore: refactor advance search section creator with user office id

* chore: add filter location function

* fix: add comment for additional props

* fix: refactor variable name

* fix: amend accordion state function with office id

* fix: update advance search test with user details
  • Loading branch information
Nil20 authored Jan 9, 2025
1 parent bf6b219 commit a533093
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 95 deletions.
4 changes: 1 addition & 3 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,7 @@ export const routesConfig = [
SCOPES.SEARCH_BIRTH,
SCOPES.SEARCH_BIRTH_MY_JURISDICTION,
SCOPES.SEARCH_DEATH,
SCOPES.SEARCH_DEATH_MY_JURISDICTION,
SCOPES.SEARCH_MARRIAGE,
SCOPES.SEARCH_MARRIAGE_MY_JURISDICTION
SCOPES.SEARCH_DEATH_MY_JURISDICTION
]}
>
<AdvancedSearchConfig />
Expand Down
13 changes: 10 additions & 3 deletions packages/client/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@ const HeaderComponent = (props: IFullProps) => {
changeTeamLocation
} = props

const { canCreateUser, canSearchRecords } = usePermissions()
const {
canCreateUser,
canSearchRecords,
canSearchBirthRecords,
canSearchDeathRecords
} = usePermissions()

const canDoAdvanceSearch = canSearchBirthRecords || canSearchDeathRecords

const getMobileHeaderActionProps = (activeMenuItem: ACTIVE_MENU_ITEM) => {
const locationId = parse(router.location.search).locationId as string
Expand Down Expand Up @@ -303,7 +310,7 @@ const HeaderComponent = (props: IFullProps) => {
})
}

const navigationList: INavigationType[] = [
const advancedSearchNavigationList: INavigationType[] = [
{
label: intl.formatMessage(messages.advancedSearch),
id: ADVANCED_SEARCH_TEXT,
Expand All @@ -324,7 +331,7 @@ const HeaderComponent = (props: IFullProps) => {
}
searchTypeList={searchTypeList}
// @TODO: How to hide the navigation list from field agents? Ask JPF
navigationList={navigationList}
navigationList={canDoAdvanceSearch ? advancedSearchNavigationList : []}
searchHandler={(text, type) =>
props.router.navigate(
{
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/components/form/FormFieldGenerator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,8 @@ class FormSectionComponent extends React.Component<Props> {
}
}, {}),
intl,
(location) => field.searchableType.includes(location.type)
(location) => field.searchableType.includes(location.type),
field.userOfficeId
)
}
: field
Expand Down
23 changes: 18 additions & 5 deletions packages/client/src/forms/advancedSearch/fieldDefinitions/Birth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ import { formMessageDescriptors } from '@client/i18n/messages'
import { messages as advancedSearchForm } from '@client/i18n/messages/views/advancedSearchForm'
import { isValidDate } from '@client/search/advancedSearch/validators'
import { TIME_PERIOD } from './utils'
import { UUID } from '@opencrvs/commons'

const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
const createBirthSearchRegistrationSection = (
hasBirthSearchJurisdictionScope?: boolean,
userOfficeId?: UUID
): IFormSectionGroup => ({
id: 'BirthRegistrationDetails',
title: advancedSearchForm.registrationDetails,
fields: [
Expand All @@ -29,6 +33,9 @@ const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
initialValue: '',
searchableResource: ['locations', 'offices'],
searchableType: ['CRVS_OFFICE', 'ADMIN_STRUCTURE'],
...(hasBirthSearchJurisdictionScope && {
userOfficeId
}),
validator: []
},
{
Expand Down Expand Up @@ -115,7 +122,7 @@ const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
]
}
]
}
})

const advancedSearchBirthSectionChildDetails: IFormSectionGroup = {
id: 'BirthChildDetails',
Expand Down Expand Up @@ -420,11 +427,17 @@ const advancedSearchBirthSectionInformantDetails: IFormSectionGroup = {
]
}

export const advancedSearchBirthSections = {
birthSearchRegistrationSection: advancedSearchBirthSectionRegistrationDetails,
export const createAdvancedSearchBirthSections = (
hasBirthSearchJurisdictionScope?: boolean,
userOfficeId?: UUID
) => ({
birthSearchRegistrationSection: createBirthSearchRegistrationSection(
hasBirthSearchJurisdictionScope,
userOfficeId
),
birthSearchChildSection: advancedSearchBirthSectionChildDetails,
birthSearchEventSection: advancedSearchBirthSectionEventDetails,
birthSearchMotherSection: advancedSearchBirthSectionMotherDetails,
birthSearchFatherSection: advancedSearchBirthSectionFatherDetails,
birthSearchInformantSection: advancedSearchBirthSectionInformantDetails
}
})
23 changes: 18 additions & 5 deletions packages/client/src/forms/advancedSearch/fieldDefinitions/Death.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ import { formMessageDescriptors } from '@client/i18n/messages'
import { messages as advancedSearchForm } from '@client/i18n/messages/views/advancedSearchForm'
import { isValidDate } from '@client/search/advancedSearch/validators'
import { TIME_PERIOD } from './utils'
import { UUID } from '@opencrvs/commons'

const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
const createDeathSearchRegistrationSection = (
hasDeathSearchJurisdictionScope?: boolean,
userOfficeId?: UUID
): IFormSectionGroup => ({
id: 'DeathRegistrationDetails',
title: advancedSearchForm.registrationDetails,
fields: [
Expand All @@ -29,6 +33,9 @@ const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
initialValue: '',
searchableResource: ['locations', 'offices'],
searchableType: ['CRVS_OFFICE', 'ADMIN_STRUCTURE'],
...(hasDeathSearchJurisdictionScope && {
userOfficeId
}),
validator: []
},
{
Expand Down Expand Up @@ -115,7 +122,7 @@ const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
]
}
]
}
})

const advancedSearchDeathSectiondeceasedDetails: IFormSectionGroup = {
id: 'DeathdeceasedDetails',
Expand Down Expand Up @@ -352,9 +359,15 @@ const advancedSearchDeathSectionInformantDetails: IFormSectionGroup = {
]
}

export const advancedSearchDeathSections = {
deathSearchRegistrationSection: advancedSearchDeathSectionRegistrationDetails,
export const createAdvancedSearchDeathSections = (
hasDeathSearchJurisdictionScope?: boolean,
userOfficeId?: UUID
) => ({
deathSearchRegistrationSection: createDeathSearchRegistrationSection(
hasDeathSearchJurisdictionScope,
userOfficeId
),
deathSearchDeceasedSection: advancedSearchDeathSectiondeceasedDetails,
deathSearchEventSection: advancedSearchDeathSectionEventDetails,
deathSearchInformantSection: advancedSearchDeathSectionInformantDetails
}
})
2 changes: 2 additions & 0 deletions packages/client/src/forms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
NATIONAL_ID
} from '@client/utils/constants'
import { IconProps } from '@opencrvs/components/lib'
import { UUID } from '@opencrvs/commons'

export const TEXT = 'TEXT'
export const TEL = 'TEL'
Expand Down Expand Up @@ -652,6 +653,7 @@ interface ILocationSearchInputFormField extends IFormFieldBase {
locationList?: ISearchLocation[]
searchableType: string[]
dispatchOptions?: IDispatchOptions
userOfficeId?: UUID // added to filter searchable location
dynamicOptions?: IDynamicOptions
}

Expand Down
20 changes: 15 additions & 5 deletions packages/client/src/hooks/useAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
isReviewableDeclaration,
isUpdatableDeclaration
} from '@client/declarations/utils'
import { isUnderJurisdiction } from '@client/utils/locationUtils'
import { isOfficeUnderJurisdiction } from '@client/utils/locationUtils'
import { getOfflineData } from '@client/offline/selectors'
import { IStoreState } from '@client/store'

Expand Down Expand Up @@ -90,6 +90,14 @@ export function usePermissions() {

const canSearchRecords = hasAnyScope(RECORD_SEARCH_SCOPES)

const hasBirthSearchJurisdictionScope = hasScope(
SCOPES.SEARCH_BIRTH_MY_JURISDICTION
)

const hasDeathSearchJurisdictionScope = hasScope(
SCOPES.SEARCH_DEATH_MY_JURISDICTION
)

const canDeclareRecords = hasAnyScope(RECORD_DECLARE_SCOPES)

const canReadUser = (user: Pick<User, 'id' | 'primaryOffice'>) => {
Expand All @@ -103,7 +111,7 @@ export function usePermissions() {
return user.primaryOffice.id === userPrimaryOffice?.id
}
if (hasScope(SCOPES.USER_READ_MY_JURISDICTION)) {
return isUnderJurisdiction(
return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
user.primaryOffice.id,
locations,
Expand All @@ -130,7 +138,7 @@ export function usePermissions() {
if (roleScopes(user.role.id).includes(SCOPES.USER_UPDATE)) {
return false
}
return isUnderJurisdiction(
return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
user.primaryOffice.id,
locations,
Expand Down Expand Up @@ -158,7 +166,7 @@ export function usePermissions() {
}

if (hasScope(SCOPES.ORGANISATION_READ_LOCATIONS_MY_JURISDICTION)) {
return isUnderJurisdiction(
return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
office.id,
locations,
Expand All @@ -176,7 +184,7 @@ export function usePermissions() {
return true
}
if (hasScope(SCOPES.USER_CREATE_MY_JURISDICTION)) {
return isUnderJurisdiction(
return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
office.id,
locations,
Expand Down Expand Up @@ -242,6 +250,8 @@ export function usePermissions() {
canEditUser,
canCreateUser,
canAccessOffice,
hasBirthSearchJurisdictionScope,
hasDeathSearchJurisdictionScope,
canAddOfficeUsers,
canUpdateRecord,
canReviewRecord,
Expand Down
49 changes: 31 additions & 18 deletions packages/client/src/search/advancedSearch/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { IAdvancedSearchParamState } from '@client/search/advancedSearch/reducer'
import { advancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
import { advancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
import { createAdvancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
import { createAdvancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
import { IDateRangePickerValue } from '@client/forms'
import { IAdvancedSearchResultMessages } from '@client/i18n/messages/views/advancedSearchResult'
import { constantsMessages, formMessages } from '@client/i18n/messages'
Expand All @@ -33,6 +33,7 @@ import {
isInvalidDate,
TIME_PERIOD
} from '@client/forms/advancedSearch/fieldDefinitions/utils'
import { UUID } from '@opencrvs/commons'

export type advancedSearchPillKey = Exclude<
keyof IAdvancedSearchResultMessages,
Expand All @@ -43,21 +44,6 @@ type pillKeyValueMap = {
[key in advancedSearchPillKey]: string | undefined
}

const {
birthSearchRegistrationSection,
birthSearchChildSection,
birthSearchMotherSection,
birthSearchFatherSection,
birthSearchEventSection,
birthSearchInformantSection
} = advancedSearchBirthSections
const {
deathSearchRegistrationSection,
deathSearchDeceasedSection,
deathSearchEventSection,
deathSearchInformantSection
} = advancedSearchDeathSections

const baseKeysSameAsStore = [
'event',
'registrationStatuses',
Expand Down Expand Up @@ -405,8 +391,35 @@ export const transformStoreDataToAdvancedSearchLocalState = (
}

export const getAccordionActiveStateMap = (
storeState: IAdvancedSearchParamState
storeState: IAdvancedSearchParamState,
hasBirthSearchJurisdictionScope?: boolean,
hasDeathSearchJurisdictionScope?: boolean,
officeId?: UUID
): Record<string, boolean> => {
const advancedSearchBirthSections = createAdvancedSearchBirthSections(
hasBirthSearchJurisdictionScope,
officeId
)
const advancedSearchDeathSections = createAdvancedSearchDeathSections(
hasDeathSearchJurisdictionScope,
officeId
)
const {
birthSearchRegistrationSection,
birthSearchChildSection,
birthSearchMotherSection,
birthSearchFatherSection,
birthSearchEventSection,
birthSearchInformantSection
} = advancedSearchBirthSections

const {
deathSearchRegistrationSection,
deathSearchDeceasedSection,
deathSearchEventSection,
deathSearchInformantSection
} = advancedSearchDeathSections

return {
[birthSearchRegistrationSection.id]: Boolean(
storeState.declarationLocationId ||
Expand Down
8 changes: 4 additions & 4 deletions packages/client/src/utils/locationUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
filterLocations,
generateLocationName,
getJurisidictionType,
isUnderJurisdiction,
isOfficeUnderJurisdiction,
getLocationNameMapOfFacility
} from '@client/utils/locationUtils'
import { createIntl } from 'react-intl'
Expand Down Expand Up @@ -181,13 +181,13 @@ describe('locationUtil tests', () => {
})
})

describe('isUnderJurisdiction', () => {
describe('isOfficeUnderJurisdiction', () => {
it('returns true if the other office is under jurisdiction of the given office', () => {
const officeId = '213ec5f3-e306-4f95-8058-f37893dbfbb6' // office in Chittagong
const otherOfficeId = '0d8474da-0361-4d32-979e-af91f012340a' // office in Chittagong -> Chandpur

expect(
isUnderJurisdiction(
isOfficeUnderJurisdiction(
officeId,
otherOfficeId,
mockOfflineData.locations,
Expand All @@ -201,7 +201,7 @@ describe('isUnderJurisdiction', () => {
const otherOfficeId = '93259d69-71af-488f-8ada-32d06678df17' // office in Dhaka

expect(
isUnderJurisdiction(
isOfficeUnderJurisdiction(
officeId,
otherOfficeId,
mockOfflineData.locations,
Expand Down
Loading

0 comments on commit a533093

Please sign in to comment.