diff --git a/lib/www/server/api/middleware/plan/list/csv.js b/lib/www/server/api/middleware/plan/list/csv.js new file mode 100644 index 0000000..58933d1 --- /dev/null +++ b/lib/www/server/api/middleware/plan/list/csv.js @@ -0,0 +1,42 @@ +const { AsyncParser } = require('json2csv'); +const { plan } = require('../../../../lib/db'); + +const json = async function (req, res, next) { + try { + const response = await plan.list(req.params.project, req.query); + + if ("download" in req.query || "d" in req.query) { + const extension = "html"; + const filename = `${req.params.project.toUpperCase()}-Plan.${extension}`; + res.set("Content-Disposition", `attachment; filename="${filename}"`); + } + + const transforms = (i) => { + i.lon0 = Number(((i?.geometry?.coordinates||[])[0]||[])[0]).toFixed(6)*1; + i.lat0 = Number(((i?.geometry?.coordinates||[])[0]||[])[1]).toFixed(6)*1; + i.lon1 = Number(((i?.geometry?.coordinates||[])[1]||[])[0]).toFixed(6)*1; + i.lat1 = Number(((i?.geometry?.coordinates||[])[1]||[])[1]).toFixed(6)*1; + i.duration = i.duration?.hours*3600 + i.duration?.minutes*60 + i.duration?.seconds; + delete i.class; + delete i.geometry; + delete i.meta; + return i; + }; + + const csv = new AsyncParser({transforms}, {objectMode: true}); + csv.processor.on('error', (err) => { throw err; }); + csv.processor.on('end', () => { + res.end(); + next(); + }); + + res.status(200); + csv.processor.pipe(res); + response.forEach(row => csv.input.push(row)); + csv.input.push(null); + } catch (err) { + next(err); + } +}; + +module.exports = json; diff --git a/lib/www/server/api/middleware/plan/list/index.js b/lib/www/server/api/middleware/plan/list/index.js index 6f59b91..0a65174 100644 --- a/lib/www/server/api/middleware/plan/list/index.js +++ b/lib/www/server/api/middleware/plan/list/index.js @@ -2,12 +2,14 @@ const json = require('./json'); const geojson = require('./geojson'); const html = require('./html'); const pdf = require('./pdf'); +const csv = require('./csv'); module.exports = async function (req, res, next) { try { const handlers = { "application/json": json, "application/geo+json": geojson, + "text/csv": csv, "text/html": html, "application/pdf": pdf }; diff --git a/lib/www/server/package-lock.json b/lib/www/server/package-lock.json index c92c713..1e681a2 100644 --- a/lib/www/server/package-lock.json +++ b/lib/www/server/package-lock.json @@ -13,6 +13,7 @@ "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-jwt": "^6.0.0", + "json2csv": "^5.0.6", "jsonwebtoken": "^8.5.1", "leaflet-headless": "gitlab:aaltronav/contrib/leaflet-headless#devel", "marked": "^2.0.3", @@ -2406,6 +2407,39 @@ "node": ">= 4" } }, + "node_modules/json2csv": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.6.tgz", + "integrity": "sha512-0/4Lv6IenJV0qj2oBdgPIAmFiKKnh8qh7bmLFJ+/ZZHLjSeiL3fKKGX3UryvKPbxFbhV+JcYo9KUC19GJ/Z/4A==", + "dependencies": { + "commander": "^6.1.0", + "jsonparse": "^1.3.1", + "lodash.get": "^4.4.2" + }, + "bin": { + "json2csv": "bin/json2csv.js" + }, + "engines": { + "node": ">= 10", + "npm": ">= 6.13.0" + } + }, + "node_modules/json2csv/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "engines": [ + "node >= 0.2.0" + ] + }, "node_modules/jsonpointer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz", @@ -2556,6 +2590,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -6905,6 +6944,28 @@ "grapheme-splitter": "^1.0.4" } }, + "json2csv": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-5.0.6.tgz", + "integrity": "sha512-0/4Lv6IenJV0qj2oBdgPIAmFiKKnh8qh7bmLFJ+/ZZHLjSeiL3fKKGX3UryvKPbxFbhV+JcYo9KUC19GJ/Z/4A==", + "requires": { + "commander": "^6.1.0", + "jsonparse": "^1.3.1", + "lodash.get": "^4.4.2" + }, + "dependencies": { + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + } + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, "jsonpointer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz", @@ -7037,6 +7098,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", diff --git a/lib/www/server/package.json b/lib/www/server/package.json index 061eced..c44c2b0 100644 --- a/lib/www/server/package.json +++ b/lib/www/server/package.json @@ -13,6 +13,7 @@ "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-jwt": "^6.0.0", + "json2csv": "^5.0.6", "jsonwebtoken": "^8.5.1", "leaflet-headless": "gitlab:aaltronav/contrib/leaflet-headless#devel", "marked": "^2.0.3",