From d27247e265d8704b61324f0aaaaecb8b61b632d2 Mon Sep 17 00:00:00 2001 From: Shweelan Samson Date: Tue, 4 Dec 2018 23:04:03 +0300 Subject: [PATCH] Implement CSV download for all parameters --- client/components/all-parameters.js | 9 ++++++ client/css/app.css | 2 +- server/api.js | 47 +++++++++++++++++++++++++++++ server/mongodb-functions.js | 5 ++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/client/components/all-parameters.js b/client/components/all-parameters.js index f06fb91..082306b 100644 --- a/client/components/all-parameters.js +++ b/client/components/all-parameters.js @@ -115,6 +115,15 @@ const component = { return m( ".all-parameters", + m( + "a.download-csv", + { + href: `/api/devices/${device["DeviceID.ID"].value[0]}.csv`, + download: "", + style: "float: right;" + }, + "Download" + ), search, m(".parameter-list", m("table", m("tbody", rows))) ); diff --git a/client/css/app.css b/client/css/app.css index a877a64..48e6c0f 100644 --- a/client/css/app.css +++ b/client/css/app.css @@ -528,7 +528,6 @@ span.na { } .all-parameters { - font-family: monospace; & > input { font-family: monospace; margin-bottom: 2px; @@ -537,6 +536,7 @@ span.na { } & > .parameter-list { + font-family: monospace; overflow-y: scroll; height: 200px; diff --git a/server/api.js b/server/api.js index 156506a..ead1dc9 100644 --- a/server/api.js +++ b/server/api.js @@ -37,6 +37,53 @@ const resources = { tasks: 0 }; +router.get(`/devices/:id.csv`, async ctx => { + const log = { + message: "Query device (CSV)", + context: ctx, + id: ctx.params.id + }; + + const filter = ["=", ["PARAM", RESOURCE_IDS.devices], ctx.params.id]; + + if (!ctx.state.authorizer.hasAccess("devices", 2)) { + logUnauthorizedWarning(log); + return void (ctx.status = 404); + } + + const res = await db.query("devices", filter); + if (!res[0]) return void (ctx.status = 404); + + ctx.type = "text/csv"; + ctx.attachment( + `device-${ctx.params.id}-${new Date() + .toISOString() + .replace(/[:.]/g, "")}.csv` + ); + + ctx.body = new stream.PassThrough(); + ctx.body.write( + "Parameter,Object,Object timestamp,Writable,Writable timestamp,Value,Value type,Value timestamp\n" + ); + + for (const k of Object.keys(res[0]).sort()) { + const p = res[0][k]; + const row = [ + k, + p.object, + p.objectTimestamp, + p.writable, + p.writableTimestamp, + p.value != null ? `"${p.value[0].toString().replace(/"/g, '""')}"` : "", + p.value != null ? p.value[1] : "", + p.valueTimestamp + ]; + ctx.body.write(row.map(r => (r != null ? r : "")).join(",") + "\n"); + } + ctx.body.end(); + logger.accessInfo(log); +}); + for (const [resource, flags] of Object.entries(resources)) { router.head(`/${resource}`, async (ctx, next) => { let filter = true; diff --git a/server/mongodb-functions.js b/server/mongodb-functions.js index d2a3404..10944c8 100644 --- a/server/mongodb-functions.js +++ b/server/mongodb-functions.js @@ -330,7 +330,10 @@ function flattenDevice(device) { const attrs = {}; if (tree["_value"] != null) { - attrs["value"] = [tree["_value"], tree["_type"]]; + attrs["value"] = [ + tree["_value"] instanceof Date ? +tree["_value"] : tree["_value"], + tree["_type"] + ]; attrs["valueTimestamp"] = +(tree["_timestamp"] || childrenTimestamp); attrs["object"] = false; attrs["objectTimestamp"] = childrenTimestamp;