Skip to content

Commit

Permalink
UIIN-3124 cautiously evaluate subpermissions
Browse files Browse the repository at this point in the history
Use optional chaining when evaluating subpermissions to avoid potential
NPEs if a permission does not have any subpermissions.

Refs UIIN-3124
  • Loading branch information
zburke committed Nov 12, 2024
1 parent 317969f commit a432b40
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Run `history.replace` once during component mount and update to avoid URL rewriting. Refs UIIN-3099.
* ECS | "FOLIO/MARC-shared" source is displayed in manually shared instance record. Fixes UIIN-3115.
* Allow user to move item to another holdings associated with another instance. Fixes UIIN-3102.
* Cautiously evaluate tenant permissions to avoid NPEs. Refs UIIN-3124.

## [12.0.0](https://github.com/folio-org/ui-inventory/tree/v12.0.0) (2024-10-31)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v11.0.5...v12.0.0)
Expand Down
21 changes: 20 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -749,13 +749,32 @@ export const isUserInConsortiumMode = stripes => stripes.hasInterface('consortia

export const isInstanceShadowCopy = (source) => [`${CONSORTIUM_PREFIX}FOLIO`, `${CONSORTIUM_PREFIX}MARC`].includes(source);

/**
* hasMemberTenantPermission
* return true if permissionName is present in the array of permissions for
* the given tenant. permissionName may match a top-level permissionName or a
* permission's subPermissions.
*
* @param {string} permissionName
* @param {string} tenantId
* @param {array} permissions array of objects shaped like
* {
* permissionNames: [{
* permissionName: 'string',
* subPermissions: ['string'],
* }],
* tenantId: 'string'
* }
*
* @returns true if permissions contains a value matching the given permissionName and tenant
*/
export const hasMemberTenantPermission = (permissionName, tenantId, permissions = []) => {
const tenantPermissions = permissions?.find(permission => permission?.tenantId === tenantId)?.permissionNames || [];

const hasPermission = tenantPermissions?.some(tenantPermission => tenantPermission?.permissionName === permissionName);

if (!hasPermission) {
return tenantPermissions.some(tenantPermission => tenantPermission.subPermissions.includes(permissionName));
return tenantPermissions.some(tenantPermission => tenantPermission.subPermissions?.includes(permissionName));
}

return hasPermission;
Expand Down
45 changes: 45 additions & 0 deletions src/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { OKAPI_TENANT_HEADER } from '@folio/stripes-inventory-components';
import buildStripes from '../test/jest/__mock__/stripesCore.mock';

import {
hasMemberTenantPermission,
validateRequiredField,
validateFieldLength,
validateNumericField,
Expand Down Expand Up @@ -445,3 +446,47 @@ describe('marshalInstance', () => {
});
});
});

describe('hasMemberTenantPermission', () => {
it('returns false without permissions', () => {
expect(hasMemberTenantPermission('foo', 'tenant')).toBe(false);
});

it('returns false with empty permissions', () => {
expect(hasMemberTenantPermission('foo', 'tenant', [])).toBe(false);
});

it('returns false if tenant does not match', () => {
expect(hasMemberTenantPermission(
'foo',
'tenant',
[{ permissionNames: [{ permissionName: 'foo' }], tenantId: 'asdf' }]
)).toBe(false);
});

describe('when tenant matches', () => {
it('returns true if matching permissionName is present', () => {
expect(hasMemberTenantPermission(
'foo',
'tenant',
[{ permissionNames: [{ permissionName: 'foo' }], tenantId: 'tenant' }]
)).toBe(true);
});

it('returns true if matching subPermissions entry is present', () => {
expect(hasMemberTenantPermission(
'foo',
'tenant',
[{ permissionNames: [{ permissionName: 'bar', subPermissions: ['foo'] }], tenantId: 'tenant' }]
)).toBe(true);
});

it('returns false if no matching permissions entry is present', () => {
expect(hasMemberTenantPermission(
'foo',
'tenant',
[{ permissionNames: [{ permissionName: 'bar' }], tenantId: 'tenant' }]
)).toBe(false);
});
});
});

0 comments on commit a432b40

Please sign in to comment.