Skip to content

Commit

Permalink
Changed overnight calendar staff permissions
Browse files Browse the repository at this point in the history
Unit admin and superuser can skip min period rule. Other staff checks use unit manager or higher rules
  • Loading branch information
SanttuA committed May 3, 2024
1 parent 2000b19 commit 8c29ae1
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 17 deletions.
27 changes: 17 additions & 10 deletions app/shared/overnight-calendar/OvernightCalendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ import { hasMaxReservations } from '../../utils/resourceUtils';
import OvernightHiddenHeading from './OvernightHiddenHeading';

function OvernightCalendar({
currentLanguage, resource, t, selected, actions, isStaff,
currentLanguage, resource, t, selected, actions,
history, isLoggedIn, isStrongAuthSatisfied, isMaintenanceModeOn,
reservationId, onEditCancel, onEditConfirm, handleDateChange, selectedDate,
isSuperuser,
isSuperuser, isResourceAdmin, isResourceManager,
}) {
if (!resource || !resource.reservations) {
return null;
Expand Down Expand Up @@ -70,10 +70,11 @@ function OvernightCalendar({
overnightStartTime, overnightEndTime, maxPeriod, minPeriod
} = resource;

const hasAdminBypass = isSuperuser || isStaff;
const isUnitAdminOrHigher = isSuperuser || isResourceAdmin;
const isUnitManagerOrHigher = isSuperuser || isResourceAdmin || isResourceManager;

useEffect(() => {
if (!hasAdminBypass && startDate && endDate && !datesSameAsInitial) {
if (!isUnitAdminOrHigher && startDate && endDate && !datesSameAsInitial) {
const selectedDuration = getSelectedDuration(
startDate, endDate, overnightStartTime, overnightEndTime);
const isDurBelowMin = isDurationBelowMin(selectedDuration, minPeriod);
Expand All @@ -98,7 +99,11 @@ function OvernightCalendar({

const now = moment();
const reservingIsAllowed = isReservingAllowed({
isLoggedIn, isStrongAuthSatisfied, isMaintenanceModeOn, resource, hasAdminBypass
isLoggedIn,
isStrongAuthSatisfied,
isMaintenanceModeOn,
resource,
hasAdminBypass: isUnitManagerOrHigher
});

const validateAndSelect = (day, { booked, nextBooked, nextClosed }) => {
Expand All @@ -116,7 +121,7 @@ function OvernightCalendar({
minPeriod,
overnightEndTime,
overnightStartTime,
hasAdminBypass,
hasAdminBypass: isUnitManagerOrHigher,
});

if (!reservingIsAllowed) {
Expand Down Expand Up @@ -155,7 +160,7 @@ function OvernightCalendar({
const isEditing = !!initialStart;

const handleSelectDatetimes = () => {
if (!hasAdminBypass && hasMaxReservations(resource) && !isEditing) {
if (!isUnitManagerOrHigher && hasMaxReservations(resource) && !isEditing) {
actions.addNotification({
message: t('TimeSlots.maxReservationsPerUser'),
type: 'error',
Expand All @@ -176,7 +181,8 @@ function OvernightCalendar({

const selectedDuration = getSelectedDuration(
startDate, endDate, overnightStartTime, overnightEndTime);
const isDurBelowMin = hasAdminBypass ? false : isDurationBelowMin(selectedDuration, minPeriod);
const isDurBelowMin = isUnitAdminOrHigher ? false
: isDurationBelowMin(selectedDuration, minPeriod);

return (
<div className="overnight-calendar">
Expand All @@ -199,7 +205,7 @@ function OvernightCalendar({
minPeriod,
overnightEndTime,
overnightStartTime,
hasAdminBypass,
hasAdminBypass: isUnitManagerOrHigher,
})}
enableOutsideDays
firstDayOfWeek={1}
Expand Down Expand Up @@ -271,7 +277,8 @@ OvernightCalendar.propTypes = {
selected: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
isStaff: PropTypes.bool.isRequired,
isResourceAdmin: PropTypes.bool.isRequired,
isResourceManager: PropTypes.bool.isRequired,
isSuperuser: PropTypes.bool.isRequired,
isLoggedIn: PropTypes.bool.isRequired,
isStrongAuthSatisfied: PropTypes.bool.isRequired,
Expand Down
6 changes: 4 additions & 2 deletions app/shared/overnight-calendar/OvernightCalendarSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { createStructuredSelector } from 'reselect';
import { currentLanguageSelector } from 'state/selectors/translationSelectors';
import {
isLoggedInSelector, isSuperUserSelector,
createIsAdminForResourceSelector
createIsAdminForResourceSelector,
createIsManagerForResourceSelector
} from 'state/selectors/authSelectors';
import { createResourceSelector, createStrongAuthSatisfiedSelector } from 'state/selectors/dataSelectors';

Expand All @@ -18,7 +19,8 @@ const OvernightCalendarSelector = createStructuredSelector({
isStrongAuthSatisfied: createStrongAuthSatisfiedSelector(resourceSelector),
currentLanguage: currentLanguageSelector,
isLoggedIn: isLoggedInSelector,
isStaff: createIsAdminForResourceSelector(resourceSelector),
isResourceAdmin: createIsAdminForResourceSelector(resourceSelector),
isResourceManager: createIsManagerForResourceSelector(resourceSelector),
isSuperuser: isSuperUserSelector,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ describe('app/shared/overnight-calendar/OvernightCalendar', () => {
addNotification: () => {},
},
history: {},
isStaff: false,
isResourceAdmin: false,
isResourceManager: false,
isSuperuser: false,
isLoggedIn: false,
isStrongAuthSatisfied: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ describe('app/shared/overnight-calendar/OvernightCalendarSelector', () => {
expect(getSelected().currentLanguage).toBeDefined();
});

test('returns isStaff', () => {
expect(getSelected().isStaff).toBeDefined();
test('returns isResourceAdmin', () => {
expect(getSelected().isResourceAdmin).toBeDefined();
});

test('returns isResourceManager', () => {
expect(getSelected().isResourceManager).toBeDefined();
});

test('returns isSuperUserSelector', () => {
Expand Down
10 changes: 9 additions & 1 deletion app/state/selectors/authSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import forIn from 'lodash/forIn';
import includes from 'lodash/includes';
import { createSelector } from 'reselect';

import { isStaffForResource, isAdminForResource } from 'utils/resourceUtils';
import { isStaffForResource, isAdminForResource, isManagerForResource } from 'utils/resourceUtils';

const authUserSelector = state => state.auth.user;
const usersSelector = state => state.data.users;
Expand Down Expand Up @@ -90,6 +90,13 @@ function createIsAdminForResourceSelector(resourceSelector) {
);
}

function createIsManagerForResourceSelector(resourceSelector) {
return createSelector(
resourceSelector,
(resource) => isManagerForResource(resource)
);
}

const authUserAmrSelector = createSelector(
authUserSelector,
(user) => {
Expand All @@ -114,4 +121,5 @@ export {
isManagerForSelector,
hasStrongAuthSelector,
createIsAdminForResourceSelector,
createIsManagerForResourceSelector,
};
29 changes: 29 additions & 0 deletions app/state/selectors/authSelectors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
hasStrongAuthSelector,
authUserAmrSelector,
createIsAdminForResourceSelector,
createIsManagerForResourceSelector,
} from './authSelectors';
import Resource from '../../utils/fixtures/Resource';

Expand Down Expand Up @@ -315,6 +316,34 @@ describe('state/selectors/authSelectors', () => {
});
});

describe('createIsManagerForResourceSelector', () => {
test('returns true if user has unit manager perm for resource', () => {
const resource = Resource.build({
userPermissions: {
isManager: true,
},
});
const resourceSelector = () => resource;
const state = getState({
'data.resources': { [resource.id]: resource }
});
expect(createIsManagerForResourceSelector(resourceSelector)(state)).toEqual(true);
});

test('returns false if user doesnt not have unit manager perm for resource', () => {
const resource = Resource.build({
userPermissions: {
isManager: false,
},
});
const resourceSelector = () => resource;
const state = getState({
'data.resources': { [resource.id]: resource }
});
expect(createIsManagerForResourceSelector(resourceSelector)(state)).toEqual(false);
});
});

describe('authUserAmrSelector', () => {
test('returns user profile amr value if it exists', () => {
const amr = 'test-amr-1';
Expand Down
15 changes: 14 additions & 1 deletion app/utils/__tests__/resourceUtils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
getEquipment,
isStaffForResource,
isStrongAuthSatisfied,
isAdminForResource
isAdminForResource,
isManagerForResource
} from 'utils/resourceUtils';
import { getPrettifiedPeriodUnits } from '../timeUtils';
import Product from '../fixtures/Product';
Expand Down Expand Up @@ -1162,6 +1163,18 @@ describe('Utils: resourceUtils', () => {
});
});

describe('isManagerForResource', () => {
test('returns true when userPermissions is admin is true', () => {
const resource = Resource.build({ userPermissions: { isManager: true } });
expect(isManagerForResource(resource)).toBe(true);
});

test('returns false when userPermissions is admin is false', () => {
const resource = Resource.build({ userPermissions: { isManager: false } });
expect(isManagerForResource(resource)).toBe(false);
});
});

describe('isStrongAuthSatisfied', () => {
describe('when resource requires strong auth', () => {
const resource = Resource.build({ authentication: 'strong' });
Expand Down
16 changes: 16 additions & 0 deletions app/utils/resourceUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,21 @@ function isAdminForResource(resource) {
return false;
}

/**
* Check whether current user is manager for given resource.
* @param {Object} resource
* @returns {boolean} true when user is manager for given resource, false if not.
*/
function isManagerForResource(resource) {
if (resource.userPermissions) {
const perms = resource.userPermissions;
if (perms.isManager) {
return true;
}
}
return false;
}

/**
* Checks whether strong auth requirement is satisfied with given resource and
* strong auth status.
Expand Down Expand Up @@ -357,4 +372,5 @@ export {
isStaffForResource,
isStrongAuthSatisfied,
isAdminForResource,
isManagerForResource,
};

0 comments on commit 8c29ae1

Please sign in to comment.