diff --git a/etc/default/templates/plan.html.njk b/etc/default/templates/plan.html.njk new file mode 100644 index 0000000..80050e7 --- /dev/null +++ b/etc/default/templates/plan.html.njk @@ -0,0 +1,245 @@ + + + + + {{projectId}} Lookahead plan + + + + + +
+ +
+

{{projectId |upper}} – Lookahead

+ {% if lines.length %} +

From {{ lines |get("ts0") |sort |first |timestamp("min") }} + until {{ lines |get("ts0") |sort |last |timestamp("min") }}

+ {% endif %} +
+
+ +
+

Havila Charisma

+ +
+

Planned sequences

+ +{% if lines.length %} + + + + + + + + + + + + + + + + + {% for line in lines %} + + + + + + + + + + + + + {% endfor %} + +
SequenceLineFSPLSPStartEndLengthAzimuthRemarks
{{ line.sequence }}{{ line.line }}{{ line.fsp }}{{ line.lsp }}{{ line.ts0 |timestamp("minutes") }}{{ line.ts1 |timestamp("minutes") }}{{ (line.length/1000) |round(1) }} km{{ line.azimuth }}°{{ line.remarks |markdownInline }}
+{% else %} +(No plan) +{% endif %} +
+ +
+

Comments

+ +
+{% if info.remarks %} + {{ info.remarks |markdown }} +{% else %} +(nil) +{% endif %} +
+
+ +
+

Situation map

+ +
+ +
+ +
+ + + + diff --git a/lib/www/server/api/middleware/plan/list/html.js b/lib/www/server/api/middleware/plan/list/html.js new file mode 100644 index 0000000..015f5f4 --- /dev/null +++ b/lib/www/server/api/middleware/plan/list/html.js @@ -0,0 +1,83 @@ +// const { configuration } = require('../../../../lib/db'); +const { plan, gis, info } = require('../../../../lib/db'); +const leafletMap = require('../../../../lib/map'); +const render = require('../../../../lib/render'); + +// FIXME Refactor when able +const defaultTemplatePath = require('path').resolve(__dirname, "../../../../../../../etc/default/templates/plan.html.njk"); + +const html = async function (req, res, next) { + try { + const planInfo = await info.get(req.params.project, "plan", req.query); + const lines = await plan.list(req.params.project, req.query); + const preplotGeoJSON = await gis.project.preplot.lines(req.params.project, {class: "V", ...req.query}); + const linesGeoJSON = lines.filter(plan => plan.geometry).map(plan => { + const feature = { + type: "Feature", + geometry: plan.geometry, + properties: plan + }; + delete feature.properties.geometry; + return feature; + }); + +// const template = (await configuration.get(req.params.project, "sse/templates/0/template")) || defaultTemplatePath; + const template = defaultTemplatePath; + + const mapConfig = { + size: { width: 500, height: 500 }, + layers: [ + { + features: preplotGeoJSON, + options: { + style (feature) { + return { + opacity: feature.properties.ntba ? 0.2 : 0.5, + color: "gray", + weight: 1 + } + } + } + }, + { + features: linesGeoJSON, + options: { + style (feature) { + return { + color: "magenta", + weight: 2 + } + } + } + } + ] + } + + const map = leafletMap(mapConfig); + + const data = { + projectId: req.params.project, + info: planInfo, + lines, + map: await map.getImageData() + } + + const response = await render(data, template); + + 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}"`); + } + res.status(200).send(response); + next(); + } catch (err) { + if (err.message.startsWith("template")) { + next({message: err.message}); + } else { + next(err); + } + } +}; + +module.exports = html; diff --git a/lib/www/server/api/middleware/plan/list/index.js b/lib/www/server/api/middleware/plan/list/index.js index bdf0bbc..6f59b91 100644 --- a/lib/www/server/api/middleware/plan/list/index.js +++ b/lib/www/server/api/middleware/plan/list/index.js @@ -1,11 +1,15 @@ const json = require('./json'); const geojson = require('./geojson'); +const html = require('./html'); +const pdf = require('./pdf'); module.exports = async function (req, res, next) { try { const handlers = { "application/json": json, "application/geo+json": geojson, + "text/html": html, + "application/pdf": pdf }; const mimetype = (handlers[req.query.mime] && req.query.mime) || req.accepts(Object.keys(handlers)); diff --git a/lib/www/server/api/middleware/plan/list/pdf.js b/lib/www/server/api/middleware/plan/list/pdf.js new file mode 100644 index 0000000..b4e1735 --- /dev/null +++ b/lib/www/server/api/middleware/plan/list/pdf.js @@ -0,0 +1,97 @@ +const fs = require('fs/promises'); +const Path = require('path'); +const crypto = require('crypto'); +const { configuration } = require('../../../../lib/db'); +const { plan, gis, info } = require('../../../../lib/db'); +const leafletMap = require('../../../../lib/map'); +const render = require('../../../../lib/render'); +const { url2pdf } = require('../../../../lib/selenium'); + +// FIXME Refactor when able +const defaultTemplatePath = require('path').resolve(__dirname, "../../../../../../../etc/default/templates/plan.html.njk"); + +function tmpname (tmpdir="/dev/shm") { + return Path.join(tmpdir, crypto.randomBytes(16).toString('hex')+".tmp"); +} + +const pdf = async function (req, res, next) { + const fname = tmpname(); + try { + const planInfo = await info.get(req.params.project, "plan", req.query); + const lines = await plan.list(req.params.project, req.query); + const preplotGeoJSON = await gis.project.preplot.lines(req.params.project, {class: "V", ...req.query}); + const linesGeoJSON = lines.filter(plan => plan.geometry).map(plan => { + const feature = { + type: "Feature", + geometry: plan.geometry, + properties: plan + }; + delete feature.properties.geometry; + return feature; + }); +// const template = (await configuration.get(req.params.project, "sse/templates/0/template")) || defaultTemplatePath; + const template = defaultTemplatePath; + + + const mapConfig = { + size: { width: 500, height: 500 }, + layers: [ + { + features: preplotGeoJSON, + options: { + style (feature) { + return { + opacity: feature.properties.ntba ? 0.2 : 0.5, + color: "gray", + weight: 1 + } + } + } + }, + { + features: linesGeoJSON, + options: { + style (feature) { + return { + color: "magenta", + weight: 2 + } + } + } + } + ] + } + + const map = leafletMap(mapConfig); + + const data = { + projectId: req.params.project, + info: planInfo, + lines, + map: await map.getImageData() + } + + const html = await render(data, template); + + await fs.writeFile(fname, html); + const pdf = Buffer.from(await url2pdf("file://"+fname), "base64"); + + if ("download" in req.query || "d" in req.query) { + const extension = "pdf"; + const filename = `${req.params.project.toUpperCase()}-Plan.${extension}`; + res.set("Content-Disposition", `attachment; filename="${filename}"`); + } + res.status(200).send(pdf); + next(); + } catch (err) { + if (err.message.startsWith("template")) { + next({message: err.message}); + } else { + next(err); + } + } finally { + await fs.unlink(fname); + } +}; + +module.exports = pdf;