From 8f5e21f7df05ebdec726e11ea496b7d63c8a233b Mon Sep 17 00:00:00 2001 From: Simon Leech Date: Wed, 25 Oct 2023 10:40:02 +0100 Subject: [PATCH 1/2] Encode Values returned from DB --- lib/ui/elements/dropdown.mjs | 2 +- lib/ui/layers/filters.mjs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/ui/elements/dropdown.mjs b/lib/ui/elements/dropdown.mjs index 39c5a2551..294feff2a 100644 --- a/lib/ui/elements/dropdown.mjs +++ b/lib/ui/elements/dropdown.mjs @@ -31,7 +31,7 @@ export default (params) => { // Set btn text to reflect selection or show placeholder. btn.querySelector('[data-id=header-span]') - .textContent = params.selectedTitles.size && Array.from(params.selectedTitles).map(v => decodeURIComponent(v)).join(', ') + .textContent = params.selectedTitles.size && Array.from(params.selectedTitles).map(v => decodeURIComponent(encodeURIComponent(v))).join(', ') || params.span || params.placeholder // Execute callback method and pass array of current selection. diff --git a/lib/ui/layers/filters.mjs b/lib/ui/layers/filters.mjs index d32de5b12..388496f9f 100644 --- a/lib/ui/layers/filters.mjs +++ b/lib/ui/layers/filters.mjs @@ -182,10 +182,13 @@ async function filter_in(layer, filter) { if (filter.dropdown) { + // Encode values for dropdown. + const encoded = filter[filter.type].map(val => encodeURIComponent(val)); + return mapp.ui.elements.dropdown({ multi: true, placeholder: 'Select Multiple', - entries: filter[filter.type].map(val => ({ + entries: encoded.map(val => ({ title: decodeURIComponent(val), option: encodeURIComponent(val), selected: chkSet.has(val) From 4913f9b574ee0b6178c89e44b4fb85a56a8c95a4 Mon Sep 17 00:00:00 2001 From: Simon Leech Date: Fri, 27 Oct 2023 12:11:29 +0100 Subject: [PATCH 2/2] Testing layer filter, style filter and filter current --- api/api.js | 2 +- mod/query.js | 35 ++++++++++++++++++++++------------- mod/utils/sqlFilter.js | 6 +++--- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/api/api.js b/api/api.js index 58e24a793..5c006d8c4 100644 --- a/api/api.js +++ b/api/api.js @@ -115,7 +115,7 @@ module.exports = async (req, res) => { Object.entries(req.params) .filter(entry => typeof entry[1] === 'string') .forEach(entry => { - req.params[entry[0]] = decodeURIComponent(entry[1]) + req.params[entry[0]] = decodeURIComponent(encodeURIComponent(entry[1])) }) // Short circuit login view or post request. diff --git a/mod/query.js b/mod/query.js index f2cc7f671..84aedd3d6 100644 --- a/mod/query.js +++ b/mod/query.js @@ -44,13 +44,22 @@ module.exports = async (req, res) => { // Get array of role filter from layer configuration. const roles = Roles.filter(layer, req.params.user?.roles) - // Create params filter string from roleFilter filter params. - req.params.filter = - ` ${layer.filter?.default && 'AND ' + layer.filter?.default || ''} - ${req.params.filter && `AND ${sqlFilter(JSON.parse(req.params.filter), SQLparams)}` || ''} - ${roles && Object.values(roles).some(r => !!r) - ? `AND ${sqlFilter(Object.values(roles).filter(r => !!r), SQLparams)}` - : ''}` + // Create a params filter string from roleFilter filter params. + // Include 'AND' followed by layer.filter?.default if it exists. + const layerFilterPart = layer.filter?.default ? `AND ${layer.filter.default}` : ''; + console.log('layerFilterPart', layerFilterPart); + // Include 'AND' followed by the result of sqlFilter if req.params.filter is provided. + console.log('Filter', req.params.filter); + const reqFilterPart = req.params.filter ? `AND ${sqlFilter(JSON.parse(req.params.filter), SQLparams)}` : ''; + console.log('reqFilterPart', reqFilterPart); + // Include 'AND' followed by the result of sqlFilter applied to roles with truthy values. + const rolesFilterPart = roles && Object.values(roles).some(r => !!r) + ? `AND ${sqlFilter(Object.values(roles).filter(r => !!r), SQLparams)}` + : ''; + console.log('rolesFilterPart', rolesFilterPart); + // Combine the parts into a single filter string with spaces. + req.params.filter = `${layerFilterPart} ${reqFilterPart} ${rolesFilterPart}`; + console.log('req.params.filter', req.params.filter); // Split viewport param. const viewport = req.params.viewport?.split(',') @@ -176,9 +185,9 @@ module.exports = async (req, res) => { } let rows = await dbs(query, SQLparams, req.params.statement_timeout || template.statement_timeout); - + if (rows instanceof Error) { - + return res.status(500).send('Failed to query PostGIS table.'); } @@ -191,17 +200,17 @@ module.exports = async (req, res) => { // Check whether any row of the rows array is empty. if (rows.length && !rows.some(row => checkEmptyRow(row)) - + // Check whether a single rows is empty. || !checkEmptyRow(rows)) { - + return res.status(202).send('No rows returned from table.') } if (req.params.reduced || req.params.template?.reduce) { - + // Reduce row values to an values array. - return res.send(rows.map(row=>Object.values(row))) + return res.send(rows.map(row => Object.values(row))) } // Send the infoj object with values back to the client. diff --git a/mod/utils/sqlFilter.js b/mod/utils/sqlFilter.js index 9f1d10373..7090f33be 100644 --- a/mod/utils/sqlFilter.js +++ b/mod/utils/sqlFilter.js @@ -30,11 +30,11 @@ const filterTypes = { let SQLparams function addValues(val, skip) { - +console.log('addValues',val); SQLparams.push(Array.isArray(val) - && val[0].map(v=>decodeURIComponent(v)) + && val[0].map(v=>decodeURIComponent(encodeURIComponent(v))) || skip && val - || decodeURIComponent(val)) + || decodeURIComponent(encodeURIComponent(val))) return SQLparams.length }