From bce5afad7e7a30d0f988d5457149f9db596e5ef8 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Thu, 20 Aug 2026 19:35:15 +0100 Subject: [PATCH] Implement caching and permission checks for user permissions This commit introduces a caching mechanism for user permissions using Redis, enhancing performance by reducing database queries. The `permissions.js` file has been updated to include functions for saving and retrieving user permissions from Redis, as well as middleware for checking permissions in various routes. Additionally, tests have been added to ensure the correctness of the permission logic and caching behavior, improving the overall security and efficiency of the application. --- src/database/__tests__/permissions.test.js | 122 +++++++++++++++++- src/database/permissions.js | 61 +++++++++ .../schemas/management/user.schema.js | 2 + src/routes/finance/invoices.js | 80 ++++++++---- src/routes/finance/payments.js | 17 +-- src/routes/finance/taxrecords.js | 7 +- src/routes/inventory/filamentstocks.js | 9 +- src/routes/inventory/orderitems.js | 32 ++++- src/routes/inventory/partstocks.js | 9 +- src/routes/inventory/productstocks.js | 11 +- src/routes/inventory/purchaseorders.js | 15 ++- src/routes/inventory/shipments.js | 80 +++++++++--- src/routes/inventory/stockaudits.js | 7 +- src/routes/inventory/stockevents.js | 9 +- src/routes/inventory/stocklocations.js | 9 +- src/routes/inventory/stocktransfers.js | 11 +- src/routes/management/apppasswords.js | 7 +- src/routes/management/courier.js | 5 +- src/routes/management/courierservice.js | 5 +- src/routes/management/documentjobs.js | 5 +- src/routes/management/documentprinters.js | 5 +- src/routes/management/documentsizes.js | 5 +- src/routes/management/documenttemplates.js | 11 +- src/routes/management/filaments.js | 7 +- src/routes/management/filamentskus.js | 5 +- src/routes/management/files.js | 5 +- src/routes/management/hosts.js | 5 +- src/routes/management/materials.js | 5 +- src/routes/management/notetypes.js | 5 +- src/routes/management/parts.js | 33 ++++- src/routes/management/partskus.js | 5 +- src/routes/management/permissionsetting.js | 5 +- src/routes/management/productcategories.js | 5 +- src/routes/management/products.js | 5 +- src/routes/management/productskus.js | 5 +- src/routes/management/taxrates.js | 5 +- src/routes/management/usergroups.js | 5 +- src/routes/management/users.js | 5 +- src/routes/management/vendors.js | 5 +- src/routes/production/filamentprofiles.js | 51 ++++++-- src/routes/production/gcodefiles.js | 7 +- src/routes/production/jobs.js | 7 +- src/routes/production/printerprofiles.js | 7 +- src/routes/production/printers.js | 7 +- src/routes/production/subjobs.js | 3 +- src/routes/sales/clients.js | 7 +- src/routes/sales/listings.js | 11 +- src/routes/sales/listingvarients.js | 11 +- src/routes/sales/marketplaces.js | 27 +++- src/routes/sales/salesorders.js | 15 ++- 50 files changed, 583 insertions(+), 204 deletions(-) diff --git a/src/database/__tests__/permissions.test.js b/src/database/__tests__/permissions.test.js index 61e1471..efbad66 100644 --- a/src/database/__tests__/permissions.test.js +++ b/src/database/__tests__/permissions.test.js @@ -1,4 +1,32 @@ -import { applyPermissionSettingsList } from '../permissions.js'; +import { jest } from '@jest/globals'; + +const redisMock = { + getKey: jest.fn(), + setKey: jest.fn(), +}; + +const lean = jest.fn(); +const select = jest.fn(() => ({ lean })); +const findById = jest.fn(() => ({ select })); +const userModel = { findById }; + +jest.unstable_mockModule('../redis.js', () => ({ + redisServer: redisMock, +})); + +jest.unstable_mockModule('mongoose', () => ({ + default: { + model: jest.fn(() => userModel), + }, +})); + +const { + applyPermissionSettingsList, + checkPermissions, + hasPermission, + getUserPermissionsCacheKey, + saveUserPermissionsToRedis, +} = await import('../permissions.js'); describe('applyPermissionSettingsList', () => { it('applies permission settings in order and inherits intermediate values', () => { @@ -54,3 +82,95 @@ describe('applyPermissionSettingsList', () => { }); }); }); + +describe('saveUserPermissionsToRedis', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('saves permissions under permissions:userID', async () => { + const permissions = { user: { info: true } }; + + await saveUserPermissionsToRedis('user-1', permissions); + + expect(redisMock.setKey).toHaveBeenCalledWith('permissions:user-1', permissions); + }); +}); + +describe('hasPermission', () => { + beforeEach(() => { + jest.clearAllMocks(); + redisMock.getKey.mockResolvedValue(null); + redisMock.setKey.mockResolvedValue(undefined); + lean.mockResolvedValue(null); + }); + + it('returns true when the cached permission is allowed', async () => { + redisMock.getKey.mockResolvedValue({ printer: { edit: true } }); + + await expect(hasPermission({ _id: 'user-1' }, 'printer', 'edit')).resolves.toBe(true); + expect(redisMock.getKey).toHaveBeenCalledWith(getUserPermissionsCacheKey('user-1')); + expect(findById).not.toHaveBeenCalled(); + }); + + it('returns false when the cached permission is denied or missing', async () => { + redisMock.getKey.mockResolvedValue({ printer: { edit: false } }); + + await expect(hasPermission('user-1', 'printer', 'edit')).resolves.toBe(false); + await expect(hasPermission('user-1', 'printer', 'delete')).resolves.toBe(false); + }); + + it('loads permissions from mongodb when redis is empty and caches them', async () => { + lean.mockResolvedValue({ + permissions: { job: { info: true, edit: false } }, + }); + + await expect(hasPermission('user-2', 'job', 'info')).resolves.toBe(true); + expect(findById).toHaveBeenCalledWith('user-2'); + expect(select).toHaveBeenCalledWith('permissions'); + expect(redisMock.setKey).toHaveBeenCalledWith('permissions:user-2', { + job: { info: true, edit: false }, + }); + }); + + it('returns false when the user or action cannot be resolved', async () => { + await expect(hasPermission(null, 'job', 'info')).resolves.toBe(false); + await expect(hasPermission('user-1', '', 'info')).resolves.toBe(false); + expect(redisMock.getKey).not.toHaveBeenCalled(); + }); +}); + +describe('checkPermissions middleware', () => { + const json = jest.fn(); + const status = jest.fn(() => ({ json })); + const next = jest.fn(); + const res = { status }; + + beforeEach(() => { + jest.clearAllMocks(); + redisMock.getKey.mockResolvedValue(null); + redisMock.setKey.mockResolvedValue(undefined); + lean.mockResolvedValue(null); + }); + + it('calls next when the user is allowed', async () => { + redisMock.getKey.mockResolvedValue({ part: { edit: true } }); + const req = { user: { _id: 'user-1' } }; + + await checkPermissions('part', 'edit')(req, res, next); + + expect(next).toHaveBeenCalledWith(); + expect(status).not.toHaveBeenCalled(); + }); + + it('returns 403 when the user is not allowed', async () => { + redisMock.getKey.mockResolvedValue({ part: { edit: false } }); + const req = { user: { _id: 'user-1' } }; + + await checkPermissions('part', 'edit')(req, res, next); + + expect(status).toHaveBeenCalledWith(403); + expect(json).toHaveBeenCalledWith({ error: 'Forbidden', code: 'FORBIDDEN' }); + expect(next).not.toHaveBeenCalled(); + }); +}); diff --git a/src/database/permissions.js b/src/database/permissions.js index 45f30e1..4a5b60d 100644 --- a/src/database/permissions.js +++ b/src/database/permissions.js @@ -1,4 +1,65 @@ import mongoose from 'mongoose'; +import { redisServer } from './redis.js'; + +import config from '../config.js'; +import log4js from 'log4js'; + +const logger = log4js.getLogger('Permissions'); +logger.level = config.server.logLevel; + +export const getUserPermissionsCacheKey = (userId) => `permissions:${userId}`; + +export const saveUserPermissionsToRedis = async (userId, permissions = {}) => { + if (!userId) { + return; + } + + await redisServer.setKey(getUserPermissionsCacheKey(userId), permissions || {}); +}; + +const getUserId = (user) => { + if (!user) return null; + if (typeof user === 'string') return user; + if (user._id) return user._id._id || user._id; + return user; +}; + +const loadPermissionsFromMongo = async (userId) => { + const userDoc = await mongoose.model('user').findById(userId).select('permissions').lean(); + + return userDoc?.permissions || {}; +}; + +export const hasPermission = async (user, objectType, action) => { + const userId = getUserId(user); + if (!userId || !objectType || !action) { + return false; + } + + logger.debug(`Checking permission: ${userId}, ${objectType}, ${action}`); + + const cacheKey = getUserPermissionsCacheKey(userId); + let permissions = await redisServer.getKey(cacheKey); + + if (permissions == null) { + permissions = await loadPermissionsFromMongo(userId); + await saveUserPermissionsToRedis(userId, permissions); + } + + return permissions?.[objectType]?.[action] === true; +}; + +export const checkPermissions = (objectType, action) => async (req, res, next) => { + try { + const allowed = await hasPermission(req.user, objectType, action); + if (!allowed) { + return res.status(403).json({ error: 'Forbidden', code: 'FORBIDDEN' }); + } + return next(); + } catch (err) { + return next(err); + } +}; export const applyPermissionSettingsList = (settingsList = []) => { const permissions = {}; diff --git a/src/database/schemas/management/user.schema.js b/src/database/schemas/management/user.schema.js index 0112da3..8233075 100644 --- a/src/database/schemas/management/user.schema.js +++ b/src/database/schemas/management/user.schema.js @@ -4,6 +4,7 @@ import { applyPermissionSettingsList, resolvePermissionSettings, resolveReferencedDocs, + saveUserPermissionsToRedis, } from '../../permissions.js'; const { Schema } = mongoose; @@ -47,6 +48,7 @@ userSchema.statics.recalculate = async function (user, actingUser) { if (user && typeof user === 'object' && !user._bsontype) { user.permissions = permissions; } + await saveUserPermissionsToRedis(userId, permissions); const { editObject } = await import('../../database.js'); await editObject({ diff --git a/src/routes/finance/invoices.js b/src/routes/finance/invoices.js index fe0a99e..15d81ec 100644 --- a/src/routes/finance/invoices.js +++ b/src/routes/finance/invoices.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions, hasPermission } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -19,15 +20,15 @@ const listAllowedFilters = [ ]; const listAllowedSorters = ['createdAt', 'state', 'updatedAt', 'invoiceDate', 'dueDate']; const propertiesAllowedFilters = [ - 'vendor', - 'client', - 'orderType', - 'order', - 'state.type', - 'value', - 'vendor._id', - 'client._id', - ]; + 'vendor', + 'client', + 'orderType', + 'order', + 'state.type', + 'value', + 'vendor._id', + 'client._id', +]; import { listInvoicesRouteHandler, getInvoiceRouteHandler, @@ -43,15 +44,24 @@ import { postInvoiceRouteHandler, searchInvoicesRouteHandler, getInvoicePropertyValuesRouteHandler, - - getInvoiceNeighborsRouteHandler + getInvoiceNeighborsRouteHandler, } from '../../services/finance/invoices.js'; // list of invoices router.get('/', isAuthenticated, async (req, res) => { const { page, limit, property, search, sort, order } = req.query; - const filter = await getFilter(req.query, listAllowedFilters); - listInvoicesRouteHandler(req, res, page, limit, property, filter, search, getSort(sort, listAllowedSorters), order); + const filter = await getFilter(req.query, listAllowedFilters); + listInvoicesRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order + ); }); router.get('/properties', isAuthenticated, async (req, res) => { @@ -73,8 +83,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchInvoicesRouteHandler(req, res, search); }); - -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('invoice', 'new'), async (req, res) => { newInvoiceRouteHandler(req, res); }); @@ -91,19 +100,28 @@ router.get('/history', isAuthenticated, async (req, res) => { router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sort, order, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getInvoiceNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); + getInvoiceNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order, + id + ); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('invoice', 'info'), async (req, res) => { getInvoiceRouteHandler(req, res); }); // update multiple invoices -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('invoice', 'edit'), async (req, res) => { editMultipleInvoicesRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('invoice', 'edit'), async (req, res) => { editInvoiceRouteHandler(req, res); }); @@ -111,16 +129,26 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deleteInvoiceRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('invoice', 'post'), async (req, res) => { postInvoiceRouteHandler(req, res); }); -router.post('/:id/acknowledge', isAuthenticated, async (req, res) => { - acknowledgeInvoiceRouteHandler(req, res); -}); +router.post( + '/:id/acknowledge', + isAuthenticated, + checkPermissions('invoice', 'acknowledge'), + async (req, res) => { + acknowledgeInvoiceRouteHandler(req, res); + } +); -router.post('/:id/cancel', isAuthenticated, async (req, res) => { - cancelInvoiceRouteHandler(req, res); -}); +router.post( + '/:id/cancel', + isAuthenticated, + checkPermissions('invoice', 'cancel'), + async (req, res) => { + cancelInvoiceRouteHandler(req, res); + } +); export default router; diff --git a/src/routes/finance/payments.js b/src/routes/finance/payments.js index 0611e37..36c3fbc 100644 --- a/src/routes/finance/payments.js +++ b/src/routes/finance/payments.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -74,7 +75,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('invoice', 'newPayment'), async (req, res) => { newPaymentRouteHandler(req, res); }); @@ -94,16 +95,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getPaymentNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('payment', 'info'), async (req, res) => { getPaymentRouteHandler(req, res); }); // update multiple payments -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('payment', 'edit'), async (req, res) => { editMultiplePaymentsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('payment', 'edit'), async (req, res) => { editPaymentRouteHandler(req, res); }); @@ -111,19 +112,19 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deletePaymentRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('payment', 'post'), async (req, res) => { postPaymentRouteHandler(req, res); }); -router.post('/:id/authorise', isAuthenticated, async (req, res) => { +router.post('/:id/authorise', isAuthenticated, checkPermissions('payment', 'authorise'), async (req, res) => { authorisePaymentRouteHandler(req, res); }); -router.post('/:id/decline', isAuthenticated, async (req, res) => { +router.post('/:id/decline', isAuthenticated, checkPermissions('payment', 'decline'), async (req, res) => { declinePaymentRouteHandler(req, res); }); -router.post('/:id/cancel', isAuthenticated, async (req, res) => { +router.post('/:id/cancel', isAuthenticated, checkPermissions('payment', 'cancel'), async (req, res) => { cancelPaymentRouteHandler(req, res); }); diff --git a/src/routes/finance/taxrecords.js b/src/routes/finance/taxrecords.js index 81ea634..1c56332 100644 --- a/src/routes/finance/taxrecords.js +++ b/src/routes/finance/taxrecords.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -59,7 +60,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('taxRecord', 'new'), async (req, res) => { newTaxRecordRouteHandler(req, res); }); @@ -79,11 +80,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getTaxRecordNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('taxRecord', 'info'), async (req, res) => { getTaxRecordRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('taxRecord', 'edit'), async (req, res) => { editTaxRecordRouteHandler(req, res); }); diff --git a/src/routes/inventory/filamentstocks.js b/src/routes/inventory/filamentstocks.js index ca928d0..e7dfd56 100644 --- a/src/routes/inventory/filamentstocks.js +++ b/src/routes/inventory/filamentstocks.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -69,7 +70,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('filamentStock', 'new'), async (req, res) => { newFilamentStockRouteHandler(req, res); }); @@ -89,16 +90,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getFilamentStockNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('filamentStock', 'info'), async (req, res) => { getFilamentStockRouteHandler(req, res); }); // update multiple filament stocks -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('filamentStock', 'edit'), async (req, res) => { editMultipleFilamentStocksRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('filamentStock', 'edit'), async (req, res) => { editFilamentStockRouteHandler(req, res); }); diff --git a/src/routes/inventory/orderitems.js b/src/routes/inventory/orderitems.js index e50a786..fc9a82d 100644 --- a/src/routes/inventory/orderitems.js +++ b/src/routes/inventory/orderitems.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -50,7 +51,17 @@ import { router.get('/', isAuthenticated, async (req, res) => { const { page, limit, property, search, sort, order } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - listOrderItemsRouteHandler(req, res, page, limit, property, filter, search, getSort(sort, listAllowedSorters), order); + listOrderItemsRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order + ); }); router.get('/properties', isAuthenticated, async (req, res) => { @@ -72,7 +83,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchOrderItemsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('orderItem', 'new'), async (req, res) => { newOrderItemRouteHandler(req, res); }); @@ -89,19 +100,28 @@ router.get('/history', isAuthenticated, async (req, res) => { router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sort, order, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getOrderItemNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); + getOrderItemNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order, + id + ); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('orderItem', 'info'), async (req, res) => { getOrderItemRouteHandler(req, res); }); // update multiple order items -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('orderItem', 'edit'), async (req, res) => { editMultipleOrderItemsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('orderItem', 'edit'), async (req, res) => { editOrderItemRouteHandler(req, res); }); diff --git a/src/routes/inventory/partstocks.js b/src/routes/inventory/partstocks.js index a006667..570fc68 100644 --- a/src/routes/inventory/partstocks.js +++ b/src/routes/inventory/partstocks.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -61,7 +62,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('partStock', 'new'), async (req, res) => { newPartStockRouteHandler(req, res); }); @@ -81,16 +82,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getPartStockNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('partStock', 'info'), async (req, res) => { getPartStockRouteHandler(req, res); }); // update multiple part stocks -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('partStock', 'edit'), async (req, res) => { editMultiplePartStocksRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('partStock', 'edit'), async (req, res) => { editPartStockRouteHandler(req, res); }); diff --git a/src/routes/inventory/productstocks.js b/src/routes/inventory/productstocks.js index e14a2fc..42044b4 100644 --- a/src/routes/inventory/productstocks.js +++ b/src/routes/inventory/productstocks.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -60,7 +61,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('productStock', 'new'), async (req, res) => { newProductStockRouteHandler(req, res); }); @@ -78,15 +79,15 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getProductStockNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('productStock', 'info'), async (req, res) => { getProductStockRouteHandler(req, res); }); -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('productStock', 'edit'), async (req, res) => { editMultipleProductStocksRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('productStock', 'edit'), async (req, res) => { editProductStockRouteHandler(req, res); }); @@ -94,7 +95,7 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deleteProductStockRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('productStock', 'post'), async (req, res) => { postProductStockRouteHandler(req, res); }); diff --git a/src/routes/inventory/purchaseorders.js b/src/routes/inventory/purchaseorders.js index 26dd5d2..b1ea5cc 100644 --- a/src/routes/inventory/purchaseorders.js +++ b/src/routes/inventory/purchaseorders.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -86,7 +87,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchPurchaseOrdersRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('purchaseOrder', 'new'), async (req, res) => { newPurchaseOrderRouteHandler(req, res); }); @@ -106,16 +107,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getPurchaseOrderNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('purchaseOrder', 'info'), async (req, res) => { getPurchaseOrderRouteHandler(req, res); }); // update multiple purchase orders -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('purchaseOrder', 'edit'), async (req, res) => { editMultiplePurchaseOrdersRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('purchaseOrder', 'edit'), async (req, res) => { editPurchaseOrderRouteHandler(req, res); }); @@ -123,15 +124,15 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deletePurchaseOrderRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('purchaseOrder', 'post'), async (req, res) => { postPurchaseOrderRouteHandler(req, res); }); -router.post('/:id/acknowledge', isAuthenticated, async (req, res) => { +router.post('/:id/acknowledge', isAuthenticated, checkPermissions('purchaseOrder', 'acknowledge'), async (req, res) => { acknowledgePurchaseOrderRouteHandler(req, res); }); -router.post('/:id/cancel', isAuthenticated, async (req, res) => { +router.post('/:id/cancel', isAuthenticated, checkPermissions('purchaseOrder', 'cancel'), async (req, res) => { cancelPurchaseOrderRouteHandler(req, res); }); diff --git a/src/routes/inventory/shipments.js b/src/routes/inventory/shipments.js index b8ed463..2542302 100644 --- a/src/routes/inventory/shipments.js +++ b/src/routes/inventory/shipments.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -17,7 +18,14 @@ const listAllowedFilters = [ 'updatedAt', '_reference', ]; -const listAllowedSorters = ['createdAt', 'state', 'updatedAt', 'shippedAt', 'expectedAt', 'deliveredAt']; +const listAllowedSorters = [ + 'createdAt', + 'state', + 'updatedAt', + 'shippedAt', + 'expectedAt', + 'deliveredAt', +]; const propertiesAllowedFilters = [ 'orderType', 'order', @@ -48,7 +56,17 @@ import { router.get('/', isAuthenticated, async (req, res) => { const { page, limit, property, search, sort, order } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - listShipmentsRouteHandler(req, res, page, limit, property, filter, search, getSort(sort, listAllowedSorters), order); + listShipmentsRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order + ); }); router.get('/properties', isAuthenticated, async (req, res) => { @@ -56,7 +74,11 @@ router.get('/properties', isAuthenticated, async (req, res) => { const filter = await getFilter(req.query, propertiesAllowedFilters, false); var masterFilter = {}; if (req.query.masterFilter) { - masterFilter = await getFilter(JSON.parse(req.query.masterFilter), propertiesAllowedFilters, true); + masterFilter = await getFilter( + JSON.parse(req.query.masterFilter), + propertiesAllowedFilters, + true + ); } listShipmentsByPropertiesRouteHandler(req, res, properties, filter, masterFilter); }); @@ -70,7 +92,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchShipmentsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('shipment', 'new'), async (req, res) => { newShipmentRouteHandler(req, res); }); @@ -87,19 +109,28 @@ router.get('/history', isAuthenticated, async (req, res) => { router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sort, order, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getShipmentNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); + getShipmentNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order, + id + ); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('shipment', 'info'), async (req, res) => { getShipmentRouteHandler(req, res); }); // update multiple shipments -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('shipment', 'edit'), async (req, res) => { editMultipleShipmentsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('shipment', 'edit'), async (req, res) => { editShipmentRouteHandler(req, res); }); @@ -107,16 +138,31 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deleteShipmentRouteHandler(req, res); }); -router.post('/:id/ship', isAuthenticated, async (req, res) => { - shipShipmentRouteHandler(req, res); -}); +router.post( + '/:id/ship', + isAuthenticated, + checkPermissions('shipment', 'ship'), + async (req, res) => { + shipShipmentRouteHandler(req, res); + } +); -router.post('/:id/receive', isAuthenticated, async (req, res) => { - receiveShipmentRouteHandler(req, res); -}); +router.post( + '/:id/receive', + isAuthenticated, + checkPermissions('shipment', 'receive'), + async (req, res) => { + receiveShipmentRouteHandler(req, res); + } +); -router.post('/:id/cancel', isAuthenticated, async (req, res) => { - cancelShipmentRouteHandler(req, res); -}); +router.post( + '/:id/cancel', + isAuthenticated, + checkPermissions('shipment', 'cancel'), + async (req, res) => { + cancelShipmentRouteHandler(req, res); + } +); export default router; diff --git a/src/routes/inventory/stockaudits.js b/src/routes/inventory/stockaudits.js index 9b5b855..a1a94bd 100644 --- a/src/routes/inventory/stockaudits.js +++ b/src/routes/inventory/stockaudits.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { parseFilter, getFilter, getSort } from '../../utils.js'; const router = express.Router(); @@ -45,7 +46,7 @@ router.get('/', isAuthenticated, async (req, res) => { }); // Create new stock audit -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('stockAudit', 'new'), async (req, res) => { newStockAuditRouteHandler(req, res); }); @@ -71,12 +72,12 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { }); // Get specific stock audit -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('stockAudit', 'info'), async (req, res) => { getStockAuditRouteHandler(req, res); }); // Update stock audit -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('stockAudit', 'edit'), async (req, res) => { updateStockAuditRouteHandler(req, res); }); diff --git a/src/routes/inventory/stockevents.js b/src/routes/inventory/stockevents.js index a2df923..4bfd7f3 100644 --- a/src/routes/inventory/stockevents.js +++ b/src/routes/inventory/stockevents.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -50,7 +51,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('stockEvent', 'new'), async (req, res) => { newStockEventRouteHandler(req, res); }); @@ -70,16 +71,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getStockEventNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('stockEvent', 'info'), async (req, res) => { getStockEventRouteHandler(req, res); }); // update multiple stock events -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('stockEvent', 'edit'), async (req, res) => { editMultipleStockEventsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('stockEvent', 'edit'), async (req, res) => { editStockEventRouteHandler(req, res); }); diff --git a/src/routes/inventory/stocklocations.js b/src/routes/inventory/stocklocations.js index 1cf90ff..04c21fd 100644 --- a/src/routes/inventory/stocklocations.js +++ b/src/routes/inventory/stocklocations.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -49,7 +50,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('stockLocation', 'new'), async (req, res) => { newStockLocationRouteHandler(req, res); }); @@ -67,15 +68,15 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getStockLocationNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('stockLocation', 'info'), async (req, res) => { getStockLocationRouteHandler(req, res); }); -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('stockLocation', 'edit'), async (req, res) => { editMultipleStockLocationsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('stockLocation', 'edit'), async (req, res) => { editStockLocationRouteHandler(req, res); }); diff --git a/src/routes/inventory/stocktransfers.js b/src/routes/inventory/stocktransfers.js index 440b29a..69b1961 100644 --- a/src/routes/inventory/stocktransfers.js +++ b/src/routes/inventory/stocktransfers.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -58,7 +59,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('stockTransfer', 'new'), async (req, res) => { newStockTransferRouteHandler(req, res); }); @@ -76,15 +77,15 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getStockTransferNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('stockTransfer', 'info'), async (req, res) => { getStockTransferRouteHandler(req, res); }); -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('stockTransfer', 'edit'), async (req, res) => { editMultipleStockTransfersRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('stockTransfer', 'edit'), async (req, res) => { editStockTransferRouteHandler(req, res); }); @@ -92,7 +93,7 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deleteStockTransferRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('stockTransfer', 'post'), async (req, res) => { postStockTransferRouteHandler(req, res); }); diff --git a/src/routes/management/apppasswords.js b/src/routes/management/apppasswords.js index 09f49eb..8b663a1 100644 --- a/src/routes/management/apppasswords.js +++ b/src/routes/management/apppasswords.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -55,7 +56,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchAppPasswordsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('user', 'newAppPassword'), async (req, res) => { newAppPasswordRouteHandler(req, res); }); @@ -67,7 +68,7 @@ router.get('/history', isAuthenticated, async (req, res) => { getAppPasswordHistoryRouteHandler(req, res); }); -router.post('/:id/regenerateSecret', isAuthenticated, async (req, res) => { +router.post('/:id/regenerateSecret', isAuthenticated, checkPermissions('appPassword', 'regenerateSecret'), async (req, res) => { regenerateSecretRouteHandler(req, res); }); @@ -81,7 +82,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getAppPasswordRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('appPassword', 'edit'), async (req, res) => { editAppPasswordRouteHandler(req, res); }); diff --git a/src/routes/management/courier.js b/src/routes/management/courier.js index e7b313f..bda0809 100644 --- a/src/routes/management/courier.js +++ b/src/routes/management/courier.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -59,7 +60,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchCouriersRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('courier', 'new'), async (req, res) => { newCourierRouteHandler(req, res); }); @@ -83,7 +84,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getCourierRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('courier', 'edit'), async (req, res) => { editCourierRouteHandler(req, res); }); diff --git a/src/routes/management/courierservice.js b/src/routes/management/courierservice.js index d0e2bf5..646aad5 100644 --- a/src/routes/management/courierservice.js +++ b/src/routes/management/courierservice.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -83,7 +84,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchCourierServicesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('courierService', 'new'), async (req, res) => { newCourierServiceRouteHandler(req, res); }); @@ -107,7 +108,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getCourierServiceRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('courierService', 'edit'), async (req, res) => { editCourierServiceRouteHandler(req, res); }); diff --git a/src/routes/management/documentjobs.js b/src/routes/management/documentjobs.js index 9b8f171..c5f557f 100644 --- a/src/routes/management/documentjobs.js +++ b/src/routes/management/documentjobs.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchDocumentJobsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('documentJob', 'new'), async (req, res) => { newDocumentJobRouteHandler(req, res); }); @@ -81,7 +82,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getDocumentJobRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('documentJob', 'edit'), async (req, res) => { editDocumentJobRouteHandler(req, res); }); diff --git a/src/routes/management/documentprinters.js b/src/routes/management/documentprinters.js index 8371da2..246e0db 100644 --- a/src/routes/management/documentprinters.js +++ b/src/routes/management/documentprinters.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -58,7 +59,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchDocumentPrintersRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('documentPrinter', 'new'), async (req, res) => { newDocumentPrinterRouteHandler(req, res); }); @@ -82,7 +83,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getDocumentPrinterRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('documentPrinter', 'edit'), async (req, res) => { editDocumentPrinterRouteHandler(req, res); }); diff --git a/src/routes/management/documentsizes.js b/src/routes/management/documentsizes.js index cf5b5b9..5985eca 100644 --- a/src/routes/management/documentsizes.js +++ b/src/routes/management/documentsizes.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -49,7 +50,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchDocumentSizesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('documentSize', 'new'), async (req, res) => { newDocumentSizeRouteHandler(req, res); }); @@ -73,7 +74,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getDocumentSizeRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('documentSize', 'edit'), async (req, res) => { editDocumentSizeRouteHandler(req, res); }); diff --git a/src/routes/management/documenttemplates.js b/src/routes/management/documenttemplates.js index 7a73bb0..e94ab07 100644 --- a/src/routes/management/documenttemplates.js +++ b/src/routes/management/documenttemplates.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -73,11 +74,11 @@ router.get('/search', isAuthenticated, async (req, res) => { searchDocumentTemplatesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('documentTemplate', 'new'), async (req, res) => { newDocumentTemplateRouteHandler(req, res); }); -router.post('/format', isAuthenticated, async (req, res) => { +router.post('/format', isAuthenticated, checkPermissions('documentTemplate', 'design'), async (req, res) => { formatDocumentTemplateRouteHandler(req, res); }); @@ -97,11 +98,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getDocumentTemplateNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.post('/:id/preview', isAuthenticated, async (req, res) => { +router.post('/:id/preview', isAuthenticated, checkPermissions('documentTemplate', 'design'), async (req, res) => { previewDocumentTemplateRouteHandler(req, res); }); -router.post('/:id/download', isAuthenticated, async (req, res) => { +router.post('/:id/download', isAuthenticated, checkPermissions('documentTemplate', 'design'), async (req, res) => { downloadDocumentTemplateRouteHandler(req, res); }); @@ -109,7 +110,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getDocumentTemplateRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('documentTemplate', 'edit'), async (req, res) => { editDocumentTemplateRouteHandler(req, res); }); diff --git a/src/routes/management/filaments.js b/src/routes/management/filaments.js index 077f286..7cfb490 100644 --- a/src/routes/management/filaments.js +++ b/src/routes/management/filaments.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, parseFilter, getSort } from '../../utils.js'; const router = express.Router(); @@ -79,7 +80,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchFilamentsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('filament', 'new'), async (req, res) => { newFilamentRouteHandler(req, res); }); @@ -104,12 +105,12 @@ router.get('/:id', isAuthenticated, async (req, res) => { }); // update filaments info -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('filament', 'edit'), async (req, res) => { editMultipleFilamentsRouteHandler(req, res); }); // update filament info -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('filament', 'edit'), async (req, res) => { editFilamentRouteHandler(req, res); }); diff --git a/src/routes/management/filamentskus.js b/src/routes/management/filamentskus.js index b9a981c..3b34e6c 100644 --- a/src/routes/management/filamentskus.js +++ b/src/routes/management/filamentskus.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -67,7 +68,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchFilamentSkusRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('filament', 'newFilamentSku'), async (req, res) => { newFilamentSkuRouteHandler(req, res); }); @@ -89,7 +90,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getFilamentSkuRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('filamentSku', 'edit'), async (req, res) => { editFilamentSkuRouteHandler(req, res); }); diff --git a/src/routes/management/files.js b/src/routes/management/files.js index c6c039c..b6fb0de 100644 --- a/src/routes/management/files.js +++ b/src/routes/management/files.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -61,7 +62,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchFilesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('file', 'new'), async (req, res) => { newFileRouteHandler(req, res); }); @@ -97,7 +98,7 @@ router.get('/:id/thumbnail', isAuthenticated, async (req, res) => { getFileThumbnailRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('file', 'edit'), async (req, res) => { editFileRouteHandler(req, res); }); diff --git a/src/routes/management/hosts.js b/src/routes/management/hosts.js index 78a7da7..9b8ef4e 100644 --- a/src/routes/management/hosts.js +++ b/src/routes/management/hosts.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchHostsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('host', 'new'), async (req, res) => { newHostRouteHandler(req, res); }); @@ -81,7 +82,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getHostRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('host', 'edit'), async (req, res) => { editHostRouteHandler(req, res); }); diff --git a/src/routes/management/materials.js b/src/routes/management/materials.js index 5ea85bc..4afaf2b 100644 --- a/src/routes/management/materials.js +++ b/src/routes/management/materials.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, parseFilter, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchMaterialsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('material', 'new'), async (req, res) => { newMaterialRouteHandler(req, res); }); @@ -82,7 +83,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { }); // update material info -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('material', 'edit'), async (req, res) => { editMaterialRouteHandler(req, res); }); diff --git a/src/routes/management/notetypes.js b/src/routes/management/notetypes.js index d6b99c6..9a54aa2 100644 --- a/src/routes/management/notetypes.js +++ b/src/routes/management/notetypes.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('noteType', 'new'), async (req, res) => { newNoteTypeRouteHandler(req, res); }); @@ -81,7 +82,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getNoteTypeRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('noteType', 'edit'), async (req, res) => { editNoteTypeRouteHandler(req, res); }); diff --git a/src/routes/management/parts.js b/src/routes/management/parts.js index f82341e..510886a 100644 --- a/src/routes/management/parts.js +++ b/src/routes/management/parts.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -28,15 +29,24 @@ import { getPartHistoryRouteHandler, searchPartsRouteHandler, getPartPropertyValuesRouteHandler, - - getPartNeighborsRouteHandler + getPartNeighborsRouteHandler, } from '../../services/management/parts.js'; // list of parts router.get('/', isAuthenticated, async (req, res) => { const { page, limit, property, search, sort, order } = req.query; - const filter = await getFilter(req.query, listAllowedFilters); - listPartsRouteHandler(req, res, page, limit, property, filter, search, getSort(sort, listAllowedSorters), order); + const filter = await getFilter(req.query, listAllowedFilters); + listPartsRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order + ); }); router.get('/properties', isAuthenticated, async (req, res) => { @@ -59,7 +69,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchPartsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('part', 'new'), async (req, res) => { newPartRouteHandler(req, res); }); @@ -76,14 +86,23 @@ router.get('/history', isAuthenticated, async (req, res) => { router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sort, order, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getPartNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); + getPartNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order, + id + ); }); router.get('/:id', isAuthenticated, async (req, res) => { getPartRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('part', 'edit'), async (req, res) => { editPartRouteHandler(req, res); }); diff --git a/src/routes/management/partskus.js b/src/routes/management/partskus.js index 63e9c32..6a8365f 100644 --- a/src/routes/management/partskus.js +++ b/src/routes/management/partskus.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -69,7 +70,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('part', 'newPartSku'), async (req, res) => { newPartSkuRouteHandler(req, res); }); @@ -91,7 +92,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getPartSkuRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('partSku', 'edit'), async (req, res) => { editPartSkuRouteHandler(req, res); }); diff --git a/src/routes/management/permissionsetting.js b/src/routes/management/permissionsetting.js index 1aafa10..7badae4 100644 --- a/src/routes/management/permissionsetting.js +++ b/src/routes/management/permissionsetting.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchPermissionSettingsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('permissionSetting', 'new'), async (req, res) => { newPermissionSettingsRouteHandler(req, res); }); @@ -88,7 +89,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getPermissionSettingsRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('permissionSetting', 'edit'), async (req, res) => { editPermissionSettingsRouteHandler(req, res); }); diff --git a/src/routes/management/productcategories.js b/src/routes/management/productcategories.js index 5001bda..c5e5051 100644 --- a/src/routes/management/productcategories.js +++ b/src/routes/management/productcategories.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, getSort } from '../../utils.js'; import { deleteProductCategoryRouteHandler, @@ -48,7 +49,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchProductCategoriesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('productCategory', 'new'), async (req, res) => { newProductCategoryRouteHandler(req, res); }); @@ -70,7 +71,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getProductCategoryRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('productCategory', 'edit'), async (req, res) => { editProductCategoryRouteHandler(req, res); }); diff --git a/src/routes/management/products.js b/src/routes/management/products.js index 490b9c4..b48f81f 100644 --- a/src/routes/management/products.js +++ b/src/routes/management/products.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -69,7 +70,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchProductsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('product', 'new'), async (req, res) => { newProductRouteHandler(req, res); }); @@ -93,7 +94,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getProductRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('product', 'edit'), async (req, res) => { editProductRouteHandler(req, res); }); diff --git a/src/routes/management/productskus.js b/src/routes/management/productskus.js index 2a1abba..d479fcc 100644 --- a/src/routes/management/productskus.js +++ b/src/routes/management/productskus.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -69,7 +70,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('product', 'newProductSku'), async (req, res) => { newProductSkuRouteHandler(req, res); }); @@ -91,7 +92,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getProductSkuRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('productSku', 'edit'), async (req, res) => { editProductSkuRouteHandler(req, res); }); diff --git a/src/routes/management/taxrates.js b/src/routes/management/taxrates.js index 0607077..5ee2fe8 100644 --- a/src/routes/management/taxrates.js +++ b/src/routes/management/taxrates.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -67,7 +68,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchTaxRatesRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('taxRate', 'new'), async (req, res) => { newTaxRateRouteHandler(req, res); }); @@ -91,7 +92,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getTaxRateRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('taxRate', 'edit'), async (req, res) => { editTaxRateRouteHandler(req, res); }); diff --git a/src/routes/management/usergroups.js b/src/routes/management/usergroups.js index 135c864..4df45a8 100644 --- a/src/routes/management/usergroups.js +++ b/src/routes/management/usergroups.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchUserGroupsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('userGroup', 'new'), async (req, res) => { newUserGroupRouteHandler(req, res); }); @@ -88,7 +89,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getUserGroupRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('userGroup', 'edit'), async (req, res) => { editUserGroupRouteHandler(req, res); }); diff --git a/src/routes/management/users.js b/src/routes/management/users.js index 58f941e..684d6ed 100644 --- a/src/routes/management/users.js +++ b/src/routes/management/users.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, getSort } from '../../utils.js'; const router = express.Router(); @@ -80,11 +81,11 @@ router.get('/:id', isAuthenticated, async (req, res) => { }); // update user info -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('user', 'edit'), async (req, res) => { editUserRouteHandler(req, res); }); -router.post('/:id/setAppPassword', isAuthenticated, async (req, res) => { +router.post('/:id/setAppPassword', isAuthenticated, checkPermissions('user', 'newAppPassword'), async (req, res) => { setAppPasswordRouteHandler(req, res); }); diff --git a/src/routes/management/vendors.js b/src/routes/management/vendors.js index 9e1adf0..eae759e 100644 --- a/src/routes/management/vendors.js +++ b/src/routes/management/vendors.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -57,7 +58,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchVendorsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('vendor', 'new'), async (req, res) => { newVendorRouteHandler(req, res); }); @@ -81,7 +82,7 @@ router.get('/:id', isAuthenticated, async (req, res) => { getVendorRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('vendor', 'edit'), async (req, res) => { editVendorRouteHandler(req, res); }); diff --git a/src/routes/production/filamentprofiles.js b/src/routes/production/filamentprofiles.js index 8fb6a8c..bbe67ef 100644 --- a/src/routes/production/filamentprofiles.js +++ b/src/routes/production/filamentprofiles.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, getSort } from '../../utils.js'; import { deleteFilamentProfileRouteHandler, @@ -10,8 +11,7 @@ import { newFilamentProfileRouteHandler, searchFilamentProfilesRouteHandler, getFilamentProfilePropertyValuesRouteHandler, - - getFilamentProfileNeighborsRouteHandler + getFilamentProfileNeighborsRouteHandler, } from '../../services/production/filamentprofiles.js'; const router = express.Router(); @@ -23,7 +23,17 @@ const propertiesAllowedFilters = ['name']; router.get('/', isAuthenticated, async (req, res) => { const { page, limit, property, search, sort, order } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - listFilamentProfilesRouteHandler(req, res, page, limit, property, filter, search, getSort(sort, listAllowedSorters), order); + listFilamentProfilesRouteHandler( + req, + res, + page, + limit, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order + ); }); router.get('/properties', isAuthenticated, async (req, res) => { @@ -45,23 +55,42 @@ router.get('/search', isAuthenticated, async (req, res) => { searchFilamentProfilesRouteHandler(req, res, req.query.search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('filamentProfile', 'new'), async (req, res) => { newFilamentProfileRouteHandler(req, res); }); router.get('/neighbors', isAuthenticated, async (req, res) => { const { property, search, sort, order, id } = req.query; const filter = await getFilter(req.query, listAllowedFilters); - getFilamentProfileNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); + getFilamentProfileNeighborsRouteHandler( + req, + res, + property, + filter, + search, + getSort(sort, listAllowedSorters), + order, + id + ); }); -router.get('/:id', isAuthenticated, async (req, res) => { - getFilamentProfileRouteHandler(req, res); -}); +router.get( + '/:id', + isAuthenticated, + checkPermissions('filamentProfile', 'info'), + async (req, res) => { + getFilamentProfileRouteHandler(req, res); + } +); -router.put('/:id', isAuthenticated, async (req, res) => { - editFilamentProfileRouteHandler(req, res); -}); +router.put( + '/:id', + isAuthenticated, + checkPermissions('filamentProfile', 'edit'), + async (req, res) => { + editFilamentProfileRouteHandler(req, res); + } +); router.delete('/:id', isAuthenticated, async (req, res) => { deleteFilamentProfileRouteHandler(req, res); diff --git a/src/routes/production/gcodefiles.js b/src/routes/production/gcodefiles.js index cfff7fb..88f5da9 100644 --- a/src/routes/production/gcodefiles.js +++ b/src/routes/production/gcodefiles.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; const router = express.Router(); @@ -59,7 +60,7 @@ router.get('/search', isAuthenticated, async (req, res) => { // create new gcodeFile -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('gcodeFile', 'new'), async (req, res) => { newGCodeFileRouteHandler(req, res); }); @@ -74,7 +75,7 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getGCodeFileNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('gcodeFile', 'info'), async (req, res) => { getGCodeFileRouteHandler(req, res); }); @@ -83,7 +84,7 @@ router.get('/:id/content', isAuthenticated, async (req, res) => { }); // update gcodeFile info -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('gcodeFile', 'edit'), async (req, res) => { editGCodeFileRouteHandler(req, res); }); diff --git a/src/routes/production/jobs.js b/src/routes/production/jobs.js index f2cef2b..71bafe2 100644 --- a/src/routes/production/jobs.js +++ b/src/routes/production/jobs.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; const router = express.Router(); @@ -66,7 +67,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchJobsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('job', 'new'), async (req, res) => { newJobRouteHandler(req, res); }); @@ -86,11 +87,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getJobNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('job', 'info'), async (req, res) => { getJobRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('job', 'edit'), async (req, res) => { editJobRouteHandler(req, res); }); diff --git a/src/routes/production/printerprofiles.js b/src/routes/production/printerprofiles.js index a4f78ab..d7b2be6 100644 --- a/src/routes/production/printerprofiles.js +++ b/src/routes/production/printerprofiles.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { convertPropertiesString, getFilter, getSort } from '../../utils.js'; import { deletePrinterProfileRouteHandler, @@ -53,7 +54,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchPrinterProfilesRouteHandler(req, res, req.query.search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('printer', 'newPrinterProfile'), async (req, res) => { newPrinterProfileRouteHandler(req, res); }); @@ -63,11 +64,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getPrinterProfileNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('printerProfile', 'info'), async (req, res) => { getPrinterProfileRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('printerProfile', 'edit'), async (req, res) => { editPrinterProfileRouteHandler(req, res); }); diff --git a/src/routes/production/printers.js b/src/routes/production/printers.js index 87265a3..9608719 100644 --- a/src/routes/production/printers.js +++ b/src/routes/production/printers.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; const router = express.Router(); import { @@ -58,7 +59,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); // create new printer -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('printer', 'new'), async (req, res) => { newPrinterRouteHandler(req, res); }); @@ -78,12 +79,12 @@ router.get('/stats', isAuthenticated, async (req, res) => { getPrinterStatsRouteHandler(req, res); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('printer', 'info'), async (req, res) => { getPrinterRouteHandler(req, res); }); // update printer info -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('printer', 'edit'), async (req, res) => { editPrinterRouteHandler(req, res); }); diff --git a/src/routes/production/subjobs.js b/src/routes/production/subjobs.js index 515c6db..889cc44 100644 --- a/src/routes/production/subjobs.js +++ b/src/routes/production/subjobs.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; const router = express.Router(); @@ -80,7 +81,7 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getSubJobNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('subJob', 'info'), async (req, res) => { getSubJobRouteHandler(req, res); }); diff --git a/src/routes/sales/clients.js b/src/routes/sales/clients.js index 17ac72e..8b9b74d 100644 --- a/src/routes/sales/clients.js +++ b/src/routes/sales/clients.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -58,7 +59,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('client', 'new'), async (req, res) => { newClientRouteHandler(req, res); }); @@ -78,11 +79,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getClientNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('client', 'info'), async (req, res) => { getClientRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('client', 'edit'), async (req, res) => { editClientRouteHandler(req, res); }); diff --git a/src/routes/sales/listings.js b/src/routes/sales/listings.js index 199f745..4e38281 100644 --- a/src/routes/sales/listings.js +++ b/src/routes/sales/listings.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -83,7 +84,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchListingsRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('listing', 'new'), async (req, res) => { newListingRouteHandler(req, res); }); @@ -95,11 +96,11 @@ router.get('/history', isAuthenticated, async (req, res) => { getListingHistoryRouteHandler(req, res); }); -router.post('/:id/publish', isAuthenticated, async (req, res) => { +router.post('/:id/publish', isAuthenticated, checkPermissions('listing', 'publish'), async (req, res) => { publishListingRouteHandler(req, res); }); -router.post('/:id/unpublish', isAuthenticated, async (req, res) => { +router.post('/:id/unpublish', isAuthenticated, checkPermissions('listing', 'unpublish'), async (req, res) => { unpublishListingRouteHandler(req, res); }); @@ -109,11 +110,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getListingNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('listing', 'info'), async (req, res) => { getListingRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('listing', 'edit'), async (req, res) => { editListingRouteHandler(req, res); }); diff --git a/src/routes/sales/listingvarients.js b/src/routes/sales/listingvarients.js index 9c01904..4a58c7e 100644 --- a/src/routes/sales/listingvarients.js +++ b/src/routes/sales/listingvarients.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -71,7 +72,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('listing', 'newListingVarient'), async (req, res) => { newListingVarientRouteHandler(req, res); }); @@ -83,11 +84,11 @@ router.get('/history', isAuthenticated, async (req, res) => { getListingVarientHistoryRouteHandler(req, res); }); -router.post('/:id/publish', isAuthenticated, async (req, res) => { +router.post('/:id/publish', isAuthenticated, checkPermissions('listingVarient', 'publish'), async (req, res) => { publishListingVarientRouteHandler(req, res); }); -router.post('/:id/unpublish', isAuthenticated, async (req, res) => { +router.post('/:id/unpublish', isAuthenticated, checkPermissions('listingVarient', 'unpublish'), async (req, res) => { unpublishListingVarientRouteHandler(req, res); }); @@ -97,11 +98,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getListingVarientNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('listingVarient', 'info'), async (req, res) => { getListingVarientRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('listingVarient', 'edit'), async (req, res) => { editListingVarientRouteHandler(req, res); }); diff --git a/src/routes/sales/marketplaces.js b/src/routes/sales/marketplaces.js index 90fecb1..67ecc78 100644 --- a/src/routes/sales/marketplaces.js +++ b/src/routes/sales/marketplaces.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions, hasPermission } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -73,7 +74,7 @@ router.get('/search', isAuthenticated, async (req, res) => { }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('marketplace', 'new'), async (req, res) => { newMarketplaceRouteHandler(req, res); }); @@ -89,19 +90,31 @@ router.get('/:id/auth/url', isAuthenticated, async (req, res) => { getMarketplaceAuthUrlRouteHandler(req, res); }); -router.post('/:id/auth/exchange', isAuthenticated, async (req, res) => { +router.post('/:id/auth/exchange', isAuthenticated, async (req, res, next) => { + try { + const allowed = + (await hasPermission(req.user, 'marketplace', 'connect')) || + (await hasPermission(req.user, 'marketplace', 'reconnect')); + if (!allowed) { + return res.status(403).json({ error: 'Forbidden', code: 'FORBIDDEN' }); + } + return next(); + } catch (err) { + return next(err); + } +}, async (req, res) => { exchangeMarketplaceAuthCodeRouteHandler(req, res); }); -router.post('/:id/auth/refresh', isAuthenticated, async (req, res) => { +router.post('/:id/auth/refresh', isAuthenticated, checkPermissions('marketplace', 'refreshToken'), async (req, res) => { refreshMarketplaceAuthRouteHandler(req, res); }); -router.post('/:id/sync/items', isAuthenticated, async (req, res) => { +router.post('/:id/sync/items', isAuthenticated, checkPermissions('marketplace', 'syncListings'), async (req, res) => { syncMarketplaceItemsRouteHandler(req, res); }); -router.post('/:id/sync/orders', isAuthenticated, async (req, res) => { +router.post('/:id/sync/orders', isAuthenticated, checkPermissions('marketplace', 'syncOrders'), async (req, res) => { syncMarketplaceOrdersRouteHandler(req, res); }); @@ -116,11 +129,11 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getMarketplaceNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('marketplace', 'info'), async (req, res) => { getMarketplaceRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('marketplace', 'edit'), async (req, res) => { editMarketplaceRouteHandler(req, res); }); diff --git a/src/routes/sales/salesorders.js b/src/routes/sales/salesorders.js index df1f9c2..d6637d2 100644 --- a/src/routes/sales/salesorders.js +++ b/src/routes/sales/salesorders.js @@ -1,5 +1,6 @@ import express from 'express'; import { isAuthenticated } from '../../keycloak.js'; +import { checkPermissions } from '../../database/permissions.js'; import { getFilter, convertPropertiesString, getSort } from '../../utils.js'; const router = express.Router(); @@ -59,7 +60,7 @@ router.get('/search', isAuthenticated, async (req, res) => { searchSalesOrdersRouteHandler(req, res, search); }); -router.post('/', isAuthenticated, async (req, res) => { +router.post('/', isAuthenticated, checkPermissions('salesOrder', 'new'), async (req, res) => { newSalesOrderRouteHandler(req, res); }); @@ -79,16 +80,16 @@ router.get('/neighbors', isAuthenticated, async (req, res) => { getSalesOrderNeighborsRouteHandler(req, res, property, filter, search, getSort(sort, listAllowedSorters), order, id); }); -router.get('/:id', isAuthenticated, async (req, res) => { +router.get('/:id', isAuthenticated, checkPermissions('salesOrder', 'info'), async (req, res) => { getSalesOrderRouteHandler(req, res); }); // update multiple sales orders -router.put('/', isAuthenticated, async (req, res) => { +router.put('/', isAuthenticated, checkPermissions('salesOrder', 'edit'), async (req, res) => { editMultipleSalesOrdersRouteHandler(req, res); }); -router.put('/:id', isAuthenticated, async (req, res) => { +router.put('/:id', isAuthenticated, checkPermissions('salesOrder', 'edit'), async (req, res) => { editSalesOrderRouteHandler(req, res); }); @@ -96,15 +97,15 @@ router.delete('/:id', isAuthenticated, async (req, res) => { deleteSalesOrderRouteHandler(req, res); }); -router.post('/:id/post', isAuthenticated, async (req, res) => { +router.post('/:id/post', isAuthenticated, checkPermissions('salesOrder', 'post'), async (req, res) => { postSalesOrderRouteHandler(req, res); }); -router.post('/:id/confirm', isAuthenticated, async (req, res) => { +router.post('/:id/confirm', isAuthenticated, checkPermissions('salesOrder', 'confirm'), async (req, res) => { confirmSalesOrderRouteHandler(req, res); }); -router.post('/:id/cancel', isAuthenticated, async (req, res) => { +router.post('/:id/cancel', isAuthenticated, checkPermissions('salesOrder', 'cancel'), async (req, res) => { cancelSalesOrderRouteHandler(req, res); });