diff --git a/app/application.js b/app/application.js index ed38382d7..fe5f18b15 100644 --- a/app/application.js +++ b/app/application.js @@ -24,6 +24,7 @@ const { databaseService } = require('./lib/database/DatabaseService.js'); // Server const { webUiServer } = require('./lib/server/WebUiServer.js'); +const { isInDevMode, isInTestMode } = require('./lib/utils/env-utils.js'); // Extract important const EP = config.public.endpoints; @@ -53,8 +54,8 @@ class RunConditionTableApplication { httpServer.post(EP.login, (req, res) => databaseService.loginSession(req, res)); httpServer.post(EP.logout, (req, res) => databaseService.logoutSession(req, res)); - httpServer.get(EP.rctData, (req, res) => databaseService.pgExecFetchData(req, res)); - httpServer.post(EP.insertData, (req, res) => databaseService.pgExecDataInsert(req, res)); + httpServer.get(EP.rctData, (req, res) => databaseService.pgExecFetchData(req, res), { public: isInDevMode() || isInTestMode() }); + httpServer.post(EP.insertData, (req, res) => databaseService.pgExecDataInsert(req, res), { public: isInDevMode() || isInTestMode() }); httpServer.get(EP.sync, async (_req, _res) => this.syncManager.syncAll()); } @@ -94,18 +95,6 @@ class RunConditionTableApplication { } } - static isInTestMode() { - return process.env.ENV_MODE === 'test'; - } - - static isInDevMode() { - return process.env.ENV_MODE === 'dev'; - } - - static getEnvMode() { - return process.env.ENV_MODE; - } - get httpServer() { return this.webUiServer.httpServer; } diff --git a/app/lib/database/DatabaseService.js b/app/lib/database/DatabaseService.js index 66063ec4e..de1452457 100644 --- a/app/lib/database/DatabaseService.js +++ b/app/lib/database/DatabaseService.js @@ -16,7 +16,7 @@ const { Log } = require('@aliceo2/web-ui'); const { Pool } = require('pg'); const { PGQueryBuilder } = require('./utilities'); const config = require('./../config/configProvider.js'); -const {distinct} = require('../utils') +const {distinct, isInDevMode, isInTestMode} = require('../utils') const DRP = config.public.dataReqParams; const DRF = config.public.dataResponseFields; @@ -106,13 +106,9 @@ class DatabaseService { } async pgExecFetchData(req, res) { - const userData = this.loggedUsers.tokenToUserData[req.query.token]; - if (!userData) { - const mess = 'SESSION_ERROR:: no user with such token'; - this.logger.error(mess, req.query); - this.responseWithStatus(res, 400, mess); + if (!this.checkToken(req, res)) { return; - } + }; const params = {...req.query, ...req.params} @@ -140,30 +136,32 @@ class DatabaseService { const dbResErrorHandler = (e) => { this.logger.error(e.message + ' :: ' + e.stack) - this.responseWithStatus(res, 500, e.code); + this.responseWithStatus(res, 400, e.message); } try { const query = PGQueryBuilder.buildSelect(params); await this.pgExec(query, connectErrorHandler, dbResponseHandler, dbResErrorHandler); } catch (e) { - this.logger.error(e.stack) - this.responseWithStatus(res, 400, e) + this.logger.error(e.message + " :: " + e.stack) + this.responseWithStatus(res, 500) } } async pgExecDataInsert(req, res) { - this.checkToken(req, res); + if (!this.checkToken(req, res)) { + return; + }; const dbResponseHandler = (dbRes) => { return res.json({data: dbRes}) } const dbResErrorHandler = (e) => { this.logger.error(e.message + ' :: ' + e.stack) - this.responseWithStatus(res, 500, e.code); + this.responseWithStatus(res, 400, e.message); } const connectErrorHandler = (connectErr) => { - this.logger.error('Error acquiring client:: ' + connectErr.stack) + this.logger.error('Error acquiring client:: ' + connectErr.message) this.responseWithStatus(res, 500, connectErr.message); } @@ -174,9 +172,20 @@ class DatabaseService { dbResponseHandler, dbResErrorHandler); } catch (e) { - this.logger.error(e.stack) - this.responseWithStatus(res, 400, e) + this.logger.error(e.message + ' :: ' + e.stack) + this.responseWithStatus(res, 400, e.message) + } + } + + checkToken(req, res) { + const userData = this.loggedUsers.tokenToUserData[req.query.token]; + if (!userData && !(isInDevMode() || isInTestMode())) { + const mess = 'SESSION_ERROR:: no user with such token'; + this.logger.error(mess, req.query); + this.responseWithStatus(res, 400, mess); + return false; } + return true; } responseWithStatus(res, status, message) { diff --git a/app/lib/database/utilities/PGQueryBuilder.js b/app/lib/database/utilities/PGQueryBuilder.js index a6f0ee0d0..a900a9662 100644 --- a/app/lib/database/utilities/PGQueryBuilder.js +++ b/app/lib/database/utilities/PGQueryBuilder.js @@ -29,6 +29,8 @@ pageToViewName[PN.anchoragePerDatapass] = 'anchorage_per_data_pass_view' pageToViewName[PN.mc] = 'mc_view' pageToViewName[PN.anchoredPerMC] = 'anchored_per_mc_view' pageToViewName[PN.flags] = 'flags_view' + +const DEFUALT_LIMIT=50; /** * Class responsible for parsing url params, payloads of client request to sql queries */ @@ -113,7 +115,7 @@ class PGQueryBuilder { static buildSelect(params) { const dataSubsetQueryPart = (params) => params[DRP.countRecords] === 'true' ? '' : - `LIMIT ${params[DRP.itemsPerPage]} OFFSET ${params[DRP.itemsPerPage] * (params[DRP.pageNumber] - 1)}`; + `LIMIT ${params[DRP.itemsPerPage] || DEFUALT_LIMIT} OFFSET ${params[DRP.itemsPerPage] * (params[DRP.pageNumber] - 1) || 1}`; const orderingPart = (params) => { if (!params['sorting']) { diff --git a/app/lib/server/routers/index.js b/app/lib/server/routers/index.js index af3722d43..d00e63564 100644 --- a/app/lib/server/routers/index.js +++ b/app/lib/server/routers/index.js @@ -19,6 +19,7 @@ const dataPassRouter = require('./dataPass.router.js'); const docsRouter = require('./docs.router.js'); const simulationPassRouter = require('./simulationPass.router.js'); const qualityControlRouter = require('./qualityControl.router.js'); +const { isInDevMode, isInTestMode } = require('../../utils'); const routeTrees = [ docsRouter, @@ -45,7 +46,7 @@ function buildRoute(controllerTree) { const { method, controller, description } = constrollerSubtree; if (constrollerSubtree.method && constrollerSubtree.controller) { - if (process.env.ENV_MODE === 'test' || process.env.ENV_MODE === 'dev') { + if (isInDevMode() || isInTestMode()) { args.public = true; } routesStack.push({ method, path, controller: controllerHandlerWrapper(controller), args, description }); diff --git a/app/lib/utils/env-utils.js b/app/lib/utils/env-utils.js new file mode 100644 index 000000000..d0c127f17 --- /dev/null +++ b/app/lib/utils/env-utils.js @@ -0,0 +1,42 @@ +/** + * + * @license + * Copyright 2019-2020 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. + */ + +function isInTestMode() { + return process.env.ENV_MODE === 'test'; +} + +function isInDevMode() { + return process.env.ENV_MODE === 'dev'; +} + +function getEnvMode() { + return process.env.ENV_MODE; +} + +function getRunningEnv() { + return process.env.RUNNING_ENV; +} + +function runsOnDocker() { + return getRunningEnv === 'DOCKER'; +} + +module.exports = { + isInDevMode, + isInTestMode, + getEnvMode, + getRunningEnv, + runsOnDocker, +}; diff --git a/app/lib/utils/index.js b/app/lib/utils/index.js index 283fbf81f..21ac9a94c 100644 --- a/app/lib/utils/index.js +++ b/app/lib/utils/index.js @@ -19,6 +19,7 @@ const sqlUtils = require('./sql-utils.js'); const errors = require('./errors.js'); const deepmerge = require('./deepmerge.js'); const adaptFindAndCountAllInService = require('./adaptFindAndCountAllInService.js'); +const envUtils = require('./env-utils.js'); module.exports = { ResProvider, @@ -29,4 +30,5 @@ module.exports = { ...errors, ...deepmerge, ...adaptFindAndCountAllInService, + ...envUtils, }; diff --git a/package.json b/package.json index b7d7a4e24..b16abc9ee 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "start:dev:local": "(export RCT_DB_HOST=${RCT_DB_HOST:-localhost}; bash -c 'set -o allexport && ls && source ./docker/dev.env && set +o allexport && npm run start:dev')", "deploy:db:local": "./database/setup-db.sh --env ./docker/dev.env", "dev": "./rctmake rm,run,app:attach,stop --target dev", - "idev": "node -e \"app = require('./app/application.js'); const { databaseManager: dbm, syncManager: scm } = app\" -i", + "idev": "node -e \"app = require('./app/application.js'); const { databaseManager: dbm, syncManager: scm } = app; const cfg = require('./app/config');\" -i", "node-dev-env": "(export RCT_DB_HOST=$(docker inspect o2rct_database-dev -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'); bash -c 'set -o allexport && ls && source ./docker/dev.env && set +o allexport && node')", "test": "./rctmake rm,run --target test", "rm": "./rctmake rm", diff --git a/test/lib/server/routes.test.js b/test/lib/server/routes.test.js index 43208df83..580d01d5c 100644 --- a/test/lib/server/routes.test.js +++ b/test/lib/server/routes.test.js @@ -26,6 +26,8 @@ const responseSchema = Joi.object({ data: Joi.array().required(), }); +const getSelfLink = () => `${config.http.tls ? 'https' : 'http'}://localhost:${config.http.port}`; + module.exports = () => { describe('WebUiServerSuite', () => { describe('Routes definitions', () => { @@ -44,7 +46,7 @@ module.exports = () => { describe('Endpoints for fetching data', () => { routes.filter(({ method }) => method === 'get').map(async ({ path }) => { // eslint-disable-next-line max-len - const url = new URL(`${config.http.tls ? 'https' : 'http'}://localhost:${config.http.port}/api${replaceAll(path, /:[^/]+/, '0')}`); + const url = new URL(`${getSelfLink()}/api${replaceAll(path, /:[^/]+/, '0')}`); it(`should fetch from ${path} <${url}> without errors`, async () => { await assert.doesNotReject(makeHttpRequestForJSON(url)); }); @@ -62,5 +64,26 @@ module.exports = () => { } }); }); + + describe('Legacy endpoints for fetching data', () => { + const params = { + periods: {}, + dataPasses: { index: 'LHC22o' }, + mc: { index: 'LHC22o' }, + anchoredPerMC: { index: 'LHC22h1c2' }, + anchoragePerDatapass: { index: 'LHC22t_apass4' }, + runsPerPeriod: { index: 'LHC22t' }, + runsPerDataPass: { index: 'LHC22t_apass4' }, + flags: { run_numbers: 123456, detector: 'CPV', data_pass_name: 'LHC22t_apass4' }, + }; + Object.entries(params).map(([pageKey, seachQueryParams]) => { + const url = new URL(`${getSelfLink()}/api${config.public.endpoints.rctData}?page=${config.public.pageNames[pageKey]}`); + Object.entries(seachQueryParams).forEach(([k, v]) => url.searchParams.set(k, v)); + + it(`should fetch from legacy endpoint ${url} without errors`, async () => { + await assert.doesNotReject(makeHttpRequestForJSON(url)); + }); + }); + }); }); };