diff --git a/Control/lib/api.js b/Control/lib/api.js index ae11d3399..a3af0458c 100644 --- a/Control/lib/api.js +++ b/Control/lib/api.js @@ -19,6 +19,8 @@ const config = require('./config/configProvider.js'); // middleware const {minimumRoleMiddleware} = require('./middleware/minimumRole.middleware.js'); +const {addDetectorIdMiddleware} = require('./middleware/addDetectorId.middleware.js'); +const {DetectorId} = require('./common/detectorId.enum.js'); const {lockOwnershipMiddleware} = require('./middleware/lockOwnership.middleware.js'); // controllers @@ -189,6 +191,13 @@ module.exports.setup = (http, ws) => { // Lock Service http.get('/locks', lockController.getLocksStateHandler.bind(lockController)); + + http.put(`/locks/:action/${DetectorId.ALL}`, + minimumRoleMiddleware(Role.GLOBAL), + addDetectorIdMiddleware(DetectorId.ALL), + lockController.actionLockHandler.bind(lockController) + ); + http.put('/locks/:action/:detectorId', minimumRoleMiddleware(Role.DETECTOR), lockController.actionLockHandler.bind(lockController) diff --git a/Control/lib/common/detectorId.enum.js b/Control/lib/common/detectorId.enum.js new file mode 100644 index 000000000..f8541d847 --- /dev/null +++ b/Control/lib/common/detectorId.enum.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2019-2024 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +/** + * Enum for detector IDs. + */ +const DetectorId = Object.freeze({ + ALL: 'ALL', +}); + +exports.DetectorId = DetectorId; diff --git a/Control/lib/middleware/addDetectorId.middleware.js b/Control/lib/middleware/addDetectorId.middleware.js new file mode 100644 index 000000000..9de7d3d68 --- /dev/null +++ b/Control/lib/middleware/addDetectorId.middleware.js @@ -0,0 +1,29 @@ +/** + * @license + * Copyright 2019-2024 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +/** + * Middleware function to add detectorID to the request object + * @param {Request} req - HTTP Request object + * @param {Next} next - HTTP Next object to use if checks pass + * @param {Response} res - HTTP Response object + * @return {void} + */ +const addDetectorIdMiddleware = (detectorId) => { + return async (req, res, next) => { + req.params.detectorId = detectorId; + next(); + }; +} + +exports.addDetectorIdMiddleware = addDetectorIdMiddleware diff --git a/Control/test/api/lock/api-put-locks.test.js b/Control/test/api/lock/api-put-locks.test.js index 75928354b..9f5767e7b 100644 --- a/Control/test/api/lock/api-put-locks.test.js +++ b/Control/test/api/lock/api-put-locks.test.js @@ -154,7 +154,7 @@ describe(`'API - PUT - /locks/:action/:detectorId' test suite`, () => { MID: { name: 'MID', state: 'FREE' }, DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, - }); + }); await request(`${TEST_URL}/api/locks`) .put(`/force/${DetectorLockAction.RELEASE}/ALL?token=${GLOBAL_TEST_TOKEN}`) @@ -164,4 +164,34 @@ describe(`'API - PUT - /locks/:action/:detectorId' test suite`, () => { ODC: { name: 'ODC', state: 'FREE' }, }); }); + + it('should successfully Take ALL locks when >=global ', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/ALL?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + }); + + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.RELEASE}/ALL?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' }, + }); + }); + + it('should fail taking ALL locks when <=global ', async () => { + + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/ALL?token=${GUEST_TEST_TOKEN}`) + .expect(403); + + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.RELEASE}/ALL?token=${GUEST_TEST_TOKEN}`) + .expect(403); + }); }); + diff --git a/Control/test/lib/middleware/mocha-addDetectorId.middleware.test.js b/Control/test/lib/middleware/mocha-addDetectorId.middleware.test.js new file mode 100644 index 000000000..e1d570980 --- /dev/null +++ b/Control/test/lib/middleware/mocha-addDetectorId.middleware.test.js @@ -0,0 +1,35 @@ +const assert = require('assert'); +const sinon = require('sinon'); + +// Import the middleware +const { addDetectorIdMiddleware } = require('../../../lib/middleware/addDetectorId.middleware'); + +describe('`addDetectorIdMiddleware` test suite', () => { + it('should add the specified detectorId to req.params and call next()', () => { + const detectorId = '1234'; + const req = { params: {} }; // Mock req object + const res = {}; // Mock res object + const next = sinon.stub(); // Mock next function + + addDetectorIdMiddleware(detectorId)(req, res, next); + + // Validate the detectorId is added + assert.strictEqual(req.params.detectorId, detectorId); + // Ensure next() is called + assert.ok(next.calledOnce); + }); + + it('should overwrite existing detectorId in req.params', () => { + const detectorId = '5678'; + const req = { params: { detectorId: 'original' } }; + const res = {}; + const next = sinon.stub(); + + addDetectorIdMiddleware(detectorId)(req, res, next); + + // Validate the detectorId is overwritten + assert.strictEqual(req.params.detectorId, detectorId); + assert.ok(next.calledOnce); + }); + +});