diff --git a/src/docs/completed-routes.yaml b/src/docs/completed-routes.yaml index 9dabdf3..7271a09 100644 --- a/src/docs/completed-routes.yaml +++ b/src/docs/completed-routes.yaml @@ -363,12 +363,10 @@ components: module_id: { type: integer, example: 1 } actions: type: object - required: [view, create, edit, delete, approve, export] + required: [view, edit, approve, export] properties: view: { type: boolean, example: true } - create: { type: boolean, example: true } - edit: { type: boolean, example: true } - delete: { type: boolean, example: false } + edit: { type: boolean, example: true, description: 'Add & edit (grants create + edit)' } approve: { type: boolean, example: false } export: { type: boolean, example: true } @@ -1619,7 +1617,7 @@ paths: schema: { type: string } get: tags: [Roles] - summary: Permission matrix for role (modules x actions checkboxes) + summary: Permission matrix for role (modules x view/edit/approve/export; edit = add + edit) responses: "200": description: Matrix fetched diff --git a/src/modules/roles/roles.routes.js b/src/modules/roles/roles.routes.js index 2c6a25f..e752002 100644 --- a/src/modules/roles/roles.routes.js +++ b/src/modules/roles/roles.routes.js @@ -23,7 +23,7 @@ router.get( controller.list ); router.get('/:id', authorize('ROLES', 'view'), controller.getOne); -router.post('/', authorize('ROLES', 'create'), validate(createRoleSchema), controller.create); +router.post('/', authorize('ROLES', 'edit'), validate(createRoleSchema), controller.create); router.put('/:id', authorize('ROLES', 'edit'), validate(updateRoleSchema), controller.update); router.put( '/:id/permissions', @@ -38,6 +38,6 @@ router.put( validate(permissionMatrixSchema), controller.savePermissionMatrix ); -router.delete('/:id', authorize('ROLES', 'delete'), controller.remove); +router.delete('/:id', authorize('ROLES', 'edit'), controller.remove); module.exports = router; diff --git a/src/modules/roles/roles.service.js b/src/modules/roles/roles.service.js index 314b45a..497bb36 100644 --- a/src/modules/roles/roles.service.js +++ b/src/modules/roles/roles.service.js @@ -3,7 +3,8 @@ const ApiError = require('../../utils/ApiError'); const auditLog = require('../../utils/auditLog'); const { getPagination } = require('../../utils/pagination'); -const PERMISSION_ACTIONS = ['view', 'create', 'edit', 'delete', 'approve', 'export']; +const MATRIX_ACTIONS = ['view', 'edit', 'approve', 'export']; +const MERGED_EDIT_ACTIONS = ['create', 'edit']; const permissionSelect = { permissions: { @@ -293,7 +294,19 @@ const getPermissionMatrix = async (id) => { const matrix = modules.map((mod) => { const permissions = {}; - for (const action of PERMISSION_ACTIONS) { + for (const action of MATRIX_ACTIONS) { + if (action === 'edit') { + const createPerm = mod.permissions.find((p) => p.action === 'create'); + const editPerm = mod.permissions.find((p) => p.action === 'edit'); + const merged = [createPerm, editPerm].filter(Boolean); + permissions.edit = { + permission_id: editPerm?.id ?? createPerm?.id ?? null, + permission_ids: merged.map((p) => p.id), + granted: merged.some((p) => granted.has(p.id.toString())), + }; + continue; + } + const perm = mod.permissions.find((p) => p.action === action); permissions[action] = { permission_id: perm?.id ?? null, @@ -310,7 +323,7 @@ const getPermissionMatrix = async (id) => { return { role: { id: role.id, name: role.name }, - actions: PERMISSION_ACTIONS, + actions: MATRIX_ACTIONS, modules: matrix, }; }; @@ -327,8 +340,22 @@ const savePermissionMatrix = async (id, matrix, userId, requestId) => { const permissionIds = []; for (const row of matrix) { - for (const action of PERMISSION_ACTIONS) { + for (const action of MATRIX_ACTIONS) { if (!row.actions?.[action]) continue; + + if (action === 'edit') { + for (const dbAction of MERGED_EDIT_ACTIONS) { + const perm = catalog.find( + (p) => p.module_id.toString() === String(row.module_id) && p.action === dbAction + ); + if (!perm) { + throw new ApiError(422, `Permission not found for module ${row.module_id}:${dbAction}`); + } + permissionIds.push(perm.id); + } + continue; + } + const perm = catalog.find( (p) => p.module_id.toString() === String(row.module_id) && p.action === action ); diff --git a/src/modules/roles/roles.validation.js b/src/modules/roles/roles.validation.js index 1e8588b..30a941c 100644 --- a/src/modules/roles/roles.validation.js +++ b/src/modules/roles/roles.validation.js @@ -23,9 +23,7 @@ const permissionMatrixSchema = Joi.object({ module_id: Joi.number().integer().positive().required(), actions: Joi.object({ view: Joi.boolean().required(), - create: Joi.boolean().required(), edit: Joi.boolean().required(), - delete: Joi.boolean().required(), approve: Joi.boolean().required(), export: Joi.boolean().required(), }).required(),