diff --git a/backend/src/middlewares/validatePermission.js b/backend/src/middlewares/validatePermission.js index 05f1ceb3..101ff4b3 100644 --- a/backend/src/middlewares/validatePermission.js +++ b/backend/src/middlewares/validatePermission.js @@ -3,12 +3,12 @@ const { getRoles } = require('../components/lookup') /** * Validates that the user has the specified permission. - * @param {*} permission + * @param {*} requiredPermissions * @returns */ -module.exports = function (permission) { +module.exports = function (...requiredPermissions) { return async function (req, res, next) { - log.verbose(`validating permission ${permission}`) + log.verbose(`validating permission ${requiredPermissions}`) const userRole = req.session?.passport?.user?.role @@ -18,9 +18,9 @@ module.exports = function (permission) { const roles = await getRoles() const matchingRole = roles.find((role) => role.data.roleId === userRole.ofm_portal_roleid) - const permissions = matchingRole ? matchingRole.data.permissions : [] + const permissions = matchingRole ? matchingRole.data.permissions?.map((p) => p.permissionName) : [] - const valid = permissions.some((p) => p.permissionName === permission) + const valid = requiredPermissions?.some((p) => permissions.includes(p)) valid ? next() : res.sendStatus(403) } diff --git a/backend/src/routes/facilities.js b/backend/src/routes/facilities.js index 77a8b250..a8e4ead6 100644 --- a/backend/src/routes/facilities.js +++ b/backend/src/routes/facilities.js @@ -19,7 +19,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.VIEW_ORG_FACILITY), - [param('facilityId', 'URL param: [facilityId] is required').not().isEmpty()], + [param('facilityId', 'URL param: [facilityId] is required').notEmpty().isUUID()], validateFacility(false), (req, res) => { validationResult(req).throw() @@ -35,7 +35,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.VIEW_ORG_FACILITY), - [param('facilityId', 'URL param: [facilityId] is required').not().isEmpty()], + [param('facilityId', 'URL param: [facilityId] is required').notEmpty().isUUID()], validateFacility(false), (req, res) => { validationResult(req).throw() @@ -50,8 +50,8 @@ router.patch( '/:facilityId', passport.authenticate('jwt', { session: false }), isValidBackendToken, - validatePermission(PERMISSIONS.UPDATE_ORG_FACILITY), - [param('facilityId', 'URL param: [facilityId] is required').not().isEmpty()], + validatePermission(PERMISSIONS.UPDATE_ORG_FACILITY, PERMISSIONS.APPLY_FOR_FUNDING), + [param('facilityId', 'URL param: [facilityId] is required').notEmpty().isUUID()], validateFacility(true), (req, res) => { validationResult(req).throw() @@ -67,7 +67,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.VIEW_ORG_FACILITY), - [param('facilityId', 'URL param: [facilityId] is required').not().isEmpty()], + [param('facilityId', 'URL param: [facilityId] is required').notEmpty().isUUID()], validateFacility(false), (req, res) => { validationResult(req).throw() diff --git a/backend/src/routes/organizations.js b/backend/src/routes/organizations.js index 52852b8f..d10bd39d 100644 --- a/backend/src/routes/organizations.js +++ b/backend/src/routes/organizations.js @@ -19,7 +19,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.VIEW_ORG_FACILITY), - [param('organizationId', 'URL param: [organizationId] is required').not().isEmpty()], + [param('organizationId', 'URL param: [organizationId] is required').notEmpty().isUUID()], validateOrganization(), (req, res) => { validationResult(req).throw() @@ -35,7 +35,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.VIEW_ORG_FACILITY), - [param('organizationId', 'URL param: [organizationId] is required').not().isEmpty()], + [param('organizationId', 'URL param: [organizationId] is required').notEmpty().isUUID()], validateOrganization(), (req, res) => { validationResult(req).throw() @@ -50,9 +50,9 @@ router.put( '/:organizationId', passport.authenticate('jwt', { session: false }), isValidBackendToken, - validatePermission(PERMISSIONS.UPDATE_ORG_FACILITY), + validatePermission(PERMISSIONS.UPDATE_ORG_FACILITY, PERMISSIONS.APPLY_FOR_FUNDING), validateOrganization(), - [param('organizationId', 'URL param: [organizationId] is required').not().isEmpty()], + [param('organizationId', 'URL param: [organizationId] is required').notEmpty().isUUID()], (req, res) => { validationResult(req).throw() return updateOrganization(req, res) @@ -67,7 +67,7 @@ router.get( passport.authenticate('jwt', { session: false }), isValidBackendToken, validatePermission(PERMISSIONS.MANAGE_USERS_EDIT), - [param('organizationId', 'URL param: [organizationId] is required').not().isEmpty()], + [param('organizationId', 'URL param: [organizationId] is required').notEmpty().isUUID()], validateOrganization(), (req, res) => { validationResult(req).throw() diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9ba5ca83..b43c61b2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,7 +40,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "^9.27.0", - "happy-dom": "^15.10.1", + "happy-dom": "^15.10.2", "prettier": "^3.3.3", "vite": "^4.5.5", "vitest": "^0.34.6" @@ -2603,9 +2603,9 @@ "peer": true }, "node_modules/happy-dom": { - "version": "15.10.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.10.1.tgz", - "integrity": "sha512-FuGnj/qIB4QnBL6fWmD7Wnh6STxevLgOVWB6+nopDGgWG1+t9CXkNB2ldZ+iqwD2UKxD2D0SU8el8A6AX6Q1+g==", + "version": "15.10.2", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.10.2.tgz", + "integrity": "sha512-NbA5XrSovenJIIcfixCREX3ZnV7yHP4phhbfuxxf4CPn+LZpz/jIM9EqJ2DrPwgVDSMoAKH3pZwQvkbsSiCrUw==", "dev": true, "dependencies": { "entities": "^4.5.0", @@ -6624,9 +6624,9 @@ "peer": true }, "happy-dom": { - "version": "15.10.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.10.1.tgz", - "integrity": "sha512-FuGnj/qIB4QnBL6fWmD7Wnh6STxevLgOVWB6+nopDGgWG1+t9CXkNB2ldZ+iqwD2UKxD2D0SU8el8A6AX6Q1+g==", + "version": "15.10.2", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.10.2.tgz", + "integrity": "sha512-NbA5XrSovenJIIcfixCREX3ZnV7yHP4phhbfuxxf4CPn+LZpz/jIM9EqJ2DrPwgVDSMoAKH3pZwQvkbsSiCrUw==", "dev": true, "requires": { "entities": "^4.5.0", diff --git a/frontend/package.json b/frontend/package.json index 6508789f..6decb4e4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,7 +46,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "^9.27.0", - "happy-dom": "^15.10.1", + "happy-dom": "^15.10.2", "prettier": "^3.3.3", "vite": "^4.5.5", "vitest": "^0.34.6" diff --git a/frontend/src/views/applications/FacilityDetailsView.vue b/frontend/src/views/applications/FacilityDetailsView.vue index 0c7daae5..9f1b77ba 100644 --- a/frontend/src/views/applications/FacilityDetailsView.vue +++ b/frontend/src/views/applications/FacilityDetailsView.vue @@ -33,6 +33,7 @@ v-model="primaryContact" :items="contacts" :disabled="readonly" + :hide-details="readonly" item-title="fullName" item-value="contactId" label="Select Primary Contact" @@ -62,6 +63,7 @@ v-model="secondaryContact" :items="availableSecondaryContacts" :disabled="readonly" + :hide-details="readonly" item-title="fullName" label="Select Secondary Contact" density="compact" @@ -90,6 +92,7 @@ v-model="expenseAuthority" :items="availableExpenseAuthorities" :disabled="readonly" + :hide-details="readonly" item-title="fullName" label="Select Expense Authority" :rules="rules.required"