#!/usr/bin/env node require('dotenv').config(); const express = require('express'); var https = require('https'); var bodyParser = require('body-parser'); const server = express(); const pg = require('pg'); //---------read sql files into variables---------------- var fs = require('fs'); //------------------------------------------------------- var options = { key: fs.readFileSync(process.env.wd + 'key.pem'), cert: fs.readFileSync(process.env.wd + 'cert.pem'), passprase: [] }; https.createServer(options, server).listen(process.env.nodeport, () => { console.log(`${new Date().toISOString()}: Web service started on port ${process.env.nodeport}`) }); var Postgres = new pg.Client({ user: process.env.user, password: process.env.password, host: process.env.host, port: process.env.port, database: process.env.database, ssl: false, application_name: "osm_api" }); Postgres.connect(); Postgres.FirstRow = function(inSQL, inResponse) { console.log(`${new Date().toISOString()}: Running query:\n${inSQL}`); Postgres.query(inSQL, [], (err, res) => { if (err === null) { console.log(`${new Date().toISOString()}: Received reponse: ${JSON.stringify(res.rows[0]).slice(0,100)}…`); inResponse.json(res.rows[0]); return; } console.log(`${new Date().toISOString()}: ${JSON.stringify(err.stack)}`); inResponse.json(err.stack); }); }; server.get('/', function(_, res) { console.log(`${new Date().toISOString()}: GET / (Test if server is up.)… SQL: n/a ${"-._.".repeat(20)}`); res.send('node.js express is up and running'); }); server.get('/login', (_, res) => res.sendFile(process.env.wd + 'msauth.html')) server.get('/logs', (_, res) => res.sendFile(process.env.wd + 'changes.log')) server.get('/pgbadger', (_, res) => res.sendFile(process.env.wd + 'logs.html')) server.get('/totals', (_, res) => res.sendFile(process.env.wd + 'totals.log')) server.get('/test_sql', function(_, res) { var path = './route_meta/scenario_package.sql' var callback = function(arg) { res.send(arg) }; fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { res.send('Failed to read needed SQL file.'); } }); }); server.get('/get_pool', bodyParser.json(), function(req, res) { var path = './route_sql/get_pool.sql'; console.log(`${new Date().toISOString()}: GET /get_pool (Get all data for one DSM.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { if (req.body.quota_rep) { // ensure backward compatibility console.log(`${new Date().toISOString()}:Converting old format… ${JSON.stringify(req.body)}`); req.body = {'scenario':{'quota_rep_descr':req.body.quota_rep}}; } var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where); Postgres.FirstRow(sql, res) }; fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.get('/scenario_package', bodyParser.json(), function(req, res) { var path = './route_sql/scenario_package.sql'; console.log(`${new Date().toISOString()}: GET /scenario_package (Get all data for a given scenario)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where) Postgres.FirstRow(sql, res) }; }) server.get('/swap_fit', bodyParser.json(), function(req, res) { var path = './route_sql/swap_fit.sql'; console.log(`${new Date().toISOString()}: GET /swap_fit (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("replace_new_mold", 'g'), req.body.new_mold); Postgres.FirstRow(sql, res) }; }) server.post('/swap', bodyParser.json(), function(req, res) { var path = './route_sql/swap_post.sql'; console.log(`${new Date().toISOString()}: POST /swap (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("swap_doc", 'g'), JSON.stringify(req.body.swap)); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) }; }) server.post('/cust_swap', bodyParser.json(), function(req, res) { var path = './route_sql/swap_cust.sql'; console.log(`${new Date().toISOString()}: POST /cust_swap (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("swap_doc", 'g'), JSON.stringify(req.body.swap)); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) }; }) server.get('/list_changes', bodyParser.json(), function(req, res) { var path = './route_sql/list_changes.sql'; console.log(`${new Date().toISOString()}: GET /list_changes (Get a list of adjustments made to DSM's pool.)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } var sql = arg.replace(new RegExp("where_clause", 'g'), where); Postgres.FirstRow(sql, res) }; }) server.get('/undo_change', bodyParser.json(), function(req, res) { var path = './route_sql/undo.sql'; console.log(`${new Date().toISOString()}: GET /undo_change (Remove an adjustment from the DSM's pool.)… SQL: ${path} ${"-._.".repeat(20)}`) fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var sql = arg.replace(new RegExp("replace_id", 'g'), JSON.stringify(req.body.logid)) Postgres.FirstRow(sql, res) }; }) //deprecating this route, just use _vp for volume and prive /* server.post('/addmonth_v', bodyParser.json(), function(req, res) { var path = './route_sql/addmonth_vd.sql'; console.log(`${new Date().toISOString()}: POST /add_month_v (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`); fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("scenario = target_scenario", 'g'), where); sql = sql.replace(new RegExp("target_increment", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_month", 'g'), req.body.month); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } }) */ server.post('/addmonth_vp', bodyParser.json(), function(req, res) { var path = './route_sql/addmonth_vupd.sql'; console.log(`${new Date().toISOString()}: POST /add_month_vp (Add volume and pricing for a new month in the forecast.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_volume", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_price", 'g'), req.body.amount); sql = sql.replace(new RegExp("target_month", 'g'), req.body.month); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/scale_v', bodyParser.json(), function(req, res) { var path = './route_sql/scale_vd.sql'; console.log(`${new Date().toISOString()}: POST /scale_v (Scale the volume for the given scenario.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("incr_qty", 'g'), req.body.qty); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/scale_p', bodyParser.json(), function(req, res) { var path = './route_sql/scale_pd.sql'; console.log(`${new Date().toISOString()}: POST /scale_p (Scale price for the given scenario.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_increment", 'g'), req.body.amount); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/scale_vp', bodyParser.json(), function(req, res) { var path = './route_sql/scale_vupd.sql'; console.log(`${new Date().toISOString()}: POST /scale_vp (Scale volume and price for the given scenario.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_vol", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_prc", 'g'), req.body.amount); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/scale_vp_sales', bodyParser.json(), function(req, res) { var path = './route_sql/scale_vupd.sql'; console.log(`${new Date().toISOString()}: POST /scale_vp_sales (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_vol", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_prc", 'g'), req.body.amount); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/new_part', bodyParser.json(), function(req, res) { var path = './route_sql/new_part.sql'; console.log(`${new Date().toISOString()}: POST /new_part (Obsolete.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_vol", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_prc", 'g'), req.body.amount); sql = sql.replace(new RegExp("replace_request", 'g'), JSON.stringify(req.body)); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) server.post('/new_basket', bodyParser.json(), function(req, res) { var path = './route_sql/new_basket.sql'; console.log(`${new Date().toISOString()}: POST /new_basket (Add new part and/or customer.)… SQL: ${path} ${"-._.".repeat(20)}`); var callback = function(arg) { req.body.scenario.iter.push("adj volume"); //intercept the request body and force in a "adj volume" at position 1, only a "copy" iteration is being used var where = build_where(req); if (where === '') { res.send("no body was sent"); return; } req.body.stamp = new Date().toISOString() var sql = arg.replace(new RegExp("where_clause", 'g'), where); sql = sql.replace(new RegExp("target_vol", 'g'), req.body.qty); sql = sql.replace(new RegExp("target_prc", 'g'), req.body.amount); sql = sql.replace(new RegExp("replace_request", 'g'), JSON.stringify(req.body)); sql = sql.replace(new RegExp("replace_version", 'g'), req.body.scenario.version); sql = sql.replace(new RegExp("replace_source", 'g'), req.body.source); sql = sql.replace(new RegExp("replace_iterdef", 'g'), JSON.stringify(req.body)); Postgres.FirstRow(sql, res) } fs.readFile(path, 'utf8', function(err, data) { if (!err) { callback(data); } else { console.log(`${new Date().toISOString()}: error reading sql file: ${JSON.stringify(err)}`); res.send('Failed to read needed SQL file.'); } }); }) function build_where(req) { console.log(`${new Date().toISOString()}: Building WHERE from ${JSON.stringify(req.body)}`); var where = ''; var clauseCount = 1; for (var i in req.body.scenario) { if (clauseCount > 1) { where = where + ` AND `; } if (Array.isArray(req.body.scenario[i])) { //if the scenario key has a value that is an array of items, push it into an `IN` statement //iter = [stage1, stage2] --> SQL --> iter IN ('stag1', stage2') var listCount = 1; where = where + i + " IN ("; for (var j in req.body.scenario[i]) { if (listCount > 1) { where = where + ","; } where = where + "'" + req.body.scenario[i][j] + "'"; listCount = listCount + 1; } where = where + ")"; } else { where = where + i + " = '" + req.body.scenario[i] + "'"; } clauseCount = clauseCount + 1; }; //if the request has a stamp, then it's an adjustment //prevent making adjustment to actual history by limiting to current stamp and beyond if (req.body.stamp) { where = where + ` AND order_date >= least('` + req.body.stamp + "'::date,'2021-06-01')"; } console.log(`${new Date().toISOString()}: Returning ${where}`); return where; }