-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' of https://github.com/AliceO2Group/WebUi into feat…
…ure/OGUI-1054/status-routes-convention
- Loading branch information
Showing
19 changed files
with
918 additions
and
60 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* @license | ||
* Copyright CERN and copyright holders of ALICE O2. This software is | ||
* distributed under the terms of the GNU General Public License v3 (GPL | ||
* Version 3), copied verbatim in the file "COPYING". | ||
* | ||
* See http://alice-o2.web.cern.ch/license for full licensing information. | ||
* | ||
* 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. | ||
*/ | ||
|
||
/** | ||
* @typedef {string|number|null|boolean} QueryParameterValue | ||
*/ | ||
|
||
const { parseUrlParameters } = require('./parseUrlParameters.js'); | ||
|
||
/** | ||
* Build a URL from a base URL (that may already have query parameters) and a list of query parameters | ||
* | ||
* @param {string} baseURL the base URL to which parameters should be added | ||
* @param {object} parameters the query parameters | ||
* @return {string} URL the built URL | ||
*/ | ||
exports.buildUrl = (baseURL, parameters) => { | ||
if (!parameters) { | ||
parameters = {}; | ||
} | ||
|
||
const [url, existingParameters] = baseURL.split('?'); | ||
|
||
parseUrlParameters(new URLSearchParams(existingParameters), parameters); | ||
|
||
const serializedQueryParameters = []; | ||
|
||
if (Object.keys(parameters).length === 0) { | ||
return url; | ||
} | ||
|
||
/** | ||
* Sanitize a value to be used as URL parameter key or value | ||
* | ||
* @param {string} value the value to sanitize | ||
* @return {string} the sanitized value | ||
*/ | ||
const sanitize = (value) => encodeURIComponent(decodeURIComponent(value)); | ||
|
||
/** | ||
* Stringify a query parameter to be used in a URL and push it in the serialized query parameters list | ||
* | ||
* @param {string} key the parameter's key | ||
* @param {QueryParameterValue} value the parameter's value | ||
* @return {void} | ||
*/ | ||
const formatAndPushQueryParameter = (key, value) => { | ||
if (value === undefined) { | ||
return; | ||
} | ||
|
||
if (Array.isArray(value)) { | ||
for (const subValue of value) { | ||
formatAndPushQueryParameter(`${key}[]`, subValue); | ||
} | ||
return; | ||
} | ||
|
||
if (typeof value === 'object' && value !== null) { | ||
for (const [subKey, subValue] of Object.entries(value)) { | ||
formatAndPushQueryParameter(`${key}[${sanitize(subKey)}]`, subValue); | ||
} | ||
return; | ||
} | ||
|
||
serializedQueryParameters.push(`${key}=${sanitize(value)}`); | ||
}; | ||
|
||
for (const [key, parameter] of Object.entries(parameters)) { | ||
formatAndPushQueryParameter(sanitize(key), parameter); | ||
} | ||
|
||
return `${url}?${serializedQueryParameters.join('&')}`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/** | ||
* @license | ||
* Copyright CERN and copyright holders of ALICE O2. This software is | ||
* distributed under the terms of the GNU General Public License v3 (GPL | ||
* Version 3), copied verbatim in the file "COPYING". | ||
* | ||
* See http://alice-o2.web.cern.ch/license for full licensing information. | ||
* | ||
* 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. | ||
*/ | ||
|
||
/** | ||
* Concatenate the given parameters key path to form proper URL query param key | ||
* | ||
* @param {string[]} parametersKeysPath the keys path to concatenate | ||
* @return {string} the concatenated keys path | ||
*/ | ||
const concatenateParametersKeyPath = (parametersKeysPath) => { | ||
if (parametersKeysPath.length === 0) { | ||
return 'no parameters keys'; | ||
} | ||
|
||
const [mainKey, ...otherKeys] = parametersKeysPath; | ||
return `${mainKey}${otherKeys.map((key) => `[${key}]`).join('')}`; | ||
}; | ||
|
||
/** | ||
* Error to be used when building parameters tree from keys path | ||
*/ | ||
class ParameterBuildingError extends Error { | ||
/** | ||
* Constructor | ||
* | ||
* @param {string} message the global error message | ||
* @param {string[]} parametersKeysPath the parameters keys path where the error occurred | ||
*/ | ||
constructor(message, parametersKeysPath) { | ||
super(`${message} - ${concatenateParametersKeyPath(parametersKeysPath)}`); | ||
|
||
this._originalMessage = message; | ||
this._parametersKeysPath = parametersKeysPath; | ||
} | ||
|
||
/** | ||
* Return the orignal message of the error, without concatenated parameters key path | ||
* | ||
* @return {string} the original message | ||
*/ | ||
get originalMessage() { | ||
return this._originalMessage; | ||
} | ||
|
||
/** | ||
* Return the parameters keys path of the error | ||
* | ||
* @return {string[]} the parameters keys path | ||
*/ | ||
get parametersKeyPath() { | ||
return this._parametersKeysPath; | ||
} | ||
} | ||
|
||
/** | ||
* Build a parameter object or array from a parameters keys path | ||
* | ||
* For example, a parameter `key1[key2][]=value` translates to keys path ['key1', 'key2', ''] and will lead to {key1: {key2: [value]}} | ||
* | ||
* @param {object|array} parentParameter the parameter's object or array up to the current key | ||
* @param {array} nestedKeys the keys path to build from the current point | ||
* @param {string} value the value of the parameter represented by the key path | ||
* @return {void} | ||
*/ | ||
const buildParameterFromNestedKeys = (parentParameter, nestedKeys, value) => { | ||
const currentKey = nestedKeys.shift(); | ||
|
||
/* | ||
* Protect against prototype polluting assignment | ||
* https://codeql.github.com/codeql-query-help/javascript/js-prototype-polluting-assignment/ | ||
*/ | ||
if (currentKey === '__proto__' || currentKey === 'constructor' || currentKey === 'prototype') { | ||
throw new Error(`Unauthorized parameters key ${currentKey}`); | ||
} | ||
|
||
if (currentKey === '') { | ||
// Parameter must be an array and the value is a new item in that array | ||
if (!Array.isArray(parentParameter)) { | ||
throw new ParameterBuildingError('Expected node in parameters tree to be an array', [currentKey]); | ||
} | ||
|
||
parentParameter.push(value); | ||
} else if (currentKey) { | ||
// Parameter must be an object and the value is a property in that array | ||
if (Array.isArray(parentParameter) || typeof parentParameter !== 'object' || parentParameter === null) { | ||
throw new ParameterBuildingError('Expected node in parameters tree to be an object', [currentKey]); | ||
} | ||
|
||
if (nestedKeys.length > 0) { | ||
// We still have nested keys to fill | ||
if (!(currentKey in parentParameter)) { | ||
parentParameter[currentKey] = nestedKeys[0] === '' ? [] : {}; | ||
} | ||
|
||
try { | ||
buildParameterFromNestedKeys(parentParameter[currentKey], nestedKeys, value); | ||
} catch (e) { | ||
if (e instanceof ParameterBuildingError) { | ||
throw new ParameterBuildingError(e.originalMessage, [currentKey, ...e.parametersKeyPath]); | ||
} | ||
throw e; | ||
} | ||
} else { | ||
if (Array.isArray(parentParameter[currentKey])) { | ||
throw new ParameterBuildingError('Node in parameters tree is an array but no more nested keys', [currentKey]); | ||
} else if (typeof parentParameter[currentKey] === 'object' && parentParameter[currentKey] !== null) { | ||
throw new ParameterBuildingError('Node in parameters tree is an object but no more nested keys', [currentKey]); | ||
} | ||
parentParameter[currentKey] = value; | ||
} | ||
} | ||
}; | ||
|
||
/** | ||
* Extract the parameters tree from the given URL parameters (any value after the "&" in a URL) | ||
* | ||
* @param {URLSearchParams} urlSearchParams the URL search parameters string | ||
* @param {object} [parameters] the existing parameters tree object (will be modified in place) | ||
* @return {object} the parameter tree | ||
*/ | ||
exports.parseUrlParameters = (urlSearchParams, parameters) => { | ||
if (urlSearchParams.size === 0) { | ||
return {}; | ||
} | ||
|
||
if (!parameters) { | ||
parameters = {}; | ||
} | ||
|
||
for (const [key, value] of urlSearchParams.entries()) { | ||
const [firstKey, ...dirtyKeys] = key.split('['); | ||
const nestedKeys = [firstKey, ...dirtyKeys.map((key) => key.slice(0, -1))]; | ||
|
||
buildParameterFromNestedKeys(parameters, nestedKeys, value); | ||
} | ||
|
||
return parameters; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.