Refactored codebase & auth bug fix
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
const Database = require("better-sqlite3");
|
||||||
|
const logger = require("../utils/logger.util");
|
||||||
|
const db_conf = require("../config/db.conf");
|
||||||
|
|
||||||
|
var db;
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.info("Connecting to Database...");
|
||||||
|
db = new Database(db_conf.path, { fileMustExist: true });
|
||||||
|
logger.info("Connected to Database.");
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = db;
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
const db = require("../database/sqlite.database.js");
|
||||||
|
const logger = require("../utils/logger.util.js");
|
||||||
|
const Database = require("better-sqlite3");
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const app_conf = require("../config/app.conf.js");
|
||||||
|
const db_conf = require("../config/db.conf.js");
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
function errorPageRenderer(res, emoji, message) {
|
||||||
|
res.render("error", {
|
||||||
|
page_title: app_conf.name,
|
||||||
|
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
|
||||||
|
error_emoji: emoji,
|
||||||
|
error_message: message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
router.delete("/remove", async (req, res) => {
|
||||||
|
if (req.query["element"]) {
|
||||||
|
try {
|
||||||
|
const remove = db.prepare(`DELETE FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
|
||||||
|
if (remove.run()["changes"]) {
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
res.status(404).send();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send();
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/upload", async (req, res) => {
|
||||||
|
if (!req.files || !req.files.file) {
|
||||||
|
res.status(422).send();
|
||||||
|
} else {
|
||||||
|
const uploadedFile = req.files.file;
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
fs.copyFile(uploadedFile.tempFilePath, db_conf.path, (error) => {
|
||||||
|
if (error) {
|
||||||
|
logger.error(error);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
db = new Database(db_conf.path, { fileMustExist: true });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
shutting_down = true;
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res.status(201).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/download", async (req, res) => {
|
||||||
|
res.download(db_conf.path);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/add", async (req, res) => {
|
||||||
|
if (req.query["element"] && req.body) {
|
||||||
|
try {
|
||||||
|
let keys = Object.keys(req.body);
|
||||||
|
let values = `'${req.query["element"]}',`;
|
||||||
|
|
||||||
|
for (const k of keys) {
|
||||||
|
if (req.body[k] === "null") {
|
||||||
|
values += `NULL,`
|
||||||
|
} else {
|
||||||
|
values += `'${req.body[k]}',`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values) {
|
||||||
|
values = values.slice(0, -1);
|
||||||
|
const update = db.prepare(`INSERT INTO ${db_conf.table_name} VALUES (${values});`);
|
||||||
|
update.run();
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send();
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/edit", async (req, res) => {
|
||||||
|
if (req.query["element"] && req.body) {
|
||||||
|
try {
|
||||||
|
let keys = Object.keys(req.body);
|
||||||
|
let values = "";
|
||||||
|
|
||||||
|
for (const k of keys) {
|
||||||
|
if (req.body[k] === "null") {
|
||||||
|
values += `${k}=NULL,`
|
||||||
|
} else {
|
||||||
|
values += `${k}='${req.body[k]}',`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values) {
|
||||||
|
values = values.slice(0, -1);
|
||||||
|
const update = db.prepare(`UPDATE ${db_conf.table_name} SET ${values} WHERE Name='${req.query["element"]}'`);
|
||||||
|
update.run();
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send();
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/add", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const select_get = db.prepare(`SELECT * FROM ${db_conf.table_name};`);
|
||||||
|
const row = select_get.get();
|
||||||
|
|
||||||
|
const sql_header = Object.keys(row);
|
||||||
|
var table_header = `<th>${sql_header[0]}</th>\n`;
|
||||||
|
sql_header.splice(0, 1);
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
var column_options = {};
|
||||||
|
for (const key of sql_header) {
|
||||||
|
table_header += `<th>${key}</th>\n`;
|
||||||
|
|
||||||
|
const select_distinct = db.prepare(`
|
||||||
|
SELECT DISTINCT ${key}
|
||||||
|
FROM ${db_conf.table_name};
|
||||||
|
`);
|
||||||
|
values = select_distinct.all();
|
||||||
|
|
||||||
|
for (v of values) {
|
||||||
|
if (column_options[key] == null) {
|
||||||
|
column_options[key] = Object.values(v);
|
||||||
|
} else {
|
||||||
|
column_options[key] = column_options[key].concat(Object.values(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var table_data = "";
|
||||||
|
const sql_row_values = Object.values(row);
|
||||||
|
|
||||||
|
table_data += `<tr><td><input type="text" placeholder="Sensor name"></td>\n`;
|
||||||
|
for (let i = 1; i < sql_row_values.length; i++) {
|
||||||
|
table_data += `<td><select></select></td>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
table_data += "</tr>";
|
||||||
|
res.render("add", {
|
||||||
|
page_title: app_conf.name,
|
||||||
|
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
|
||||||
|
js_path: path.join(app_conf.paths.js.web, "add.js"),
|
||||||
|
column_options: JSON.stringify(column_options),
|
||||||
|
table_header: table_header,
|
||||||
|
table_data: table_data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorPageRenderer(res, "❓", "The database is empty.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/edit", async (req, res) => {
|
||||||
|
if (req.query["element"]) {
|
||||||
|
try {
|
||||||
|
const select_get = db.prepare(`SELECT * FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
|
||||||
|
const row = select_get.get();
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
const sql_header = Object.keys(row);
|
||||||
|
var table_header = `<th>${sql_header[0]}</th>\n`;
|
||||||
|
sql_header.splice(0, 1);
|
||||||
|
|
||||||
|
var column_options = {};
|
||||||
|
for (const key of sql_header) {
|
||||||
|
table_header += `<th>${key}</th>\n`;
|
||||||
|
|
||||||
|
const select_distinct = db.prepare(`
|
||||||
|
SELECT DISTINCT ${key}
|
||||||
|
FROM ${db_conf.table_name}
|
||||||
|
WHERE ${key} IS NOT NULL
|
||||||
|
AND ${key} NOT IN (
|
||||||
|
SELECT ${key}
|
||||||
|
FROM ${db_conf.table_name}
|
||||||
|
WHERE Name='${req.query["element"]}'
|
||||||
|
AND ${key} IS NOT NULL);
|
||||||
|
`);
|
||||||
|
values = select_distinct.all();
|
||||||
|
|
||||||
|
for (v of values) {
|
||||||
|
if (column_options[key] == null) {
|
||||||
|
column_options[key] = Object.values(v);
|
||||||
|
} else {
|
||||||
|
column_options[key] = column_options[key].concat(Object.values(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var table_data = "";
|
||||||
|
const sql_row_values = Object.values(row);
|
||||||
|
table_data += `<tr><td>${sql_row_values[0]}</td>\n`;
|
||||||
|
sql_row_values.splice(0, 1);
|
||||||
|
|
||||||
|
for (const v of sql_row_values) {
|
||||||
|
table_data += `<td><select><option selected="selected">${v}</option></select></td>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
table_data += "</tr>";
|
||||||
|
|
||||||
|
res.render("edit", {
|
||||||
|
page_title: app_conf.name,
|
||||||
|
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
|
||||||
|
js_path: path.join(app_conf.paths.js.web, "edit.js"),
|
||||||
|
column_options: JSON.stringify(column_options),
|
||||||
|
table_header: table_header,
|
||||||
|
table_data: table_data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorPageRenderer(res, "🔍❌", "Not found.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorPageRenderer(res, "✋⛔", "Bad request.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("", async (req, res) => {
|
||||||
|
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const select = db.prepare(`SELECT * FROM ${db_conf.table_name}`);
|
||||||
|
const rows = select.all();
|
||||||
|
|
||||||
|
if (rows[0]) {
|
||||||
|
const sql_header = Object.keys(rows[0]);
|
||||||
|
|
||||||
|
var table_header = "";
|
||||||
|
for (const key of sql_header) {
|
||||||
|
table_header += `<th>${key}</th>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
var table_data = "";
|
||||||
|
for (const row of rows) {
|
||||||
|
const sql_row_values = Object.values(row);
|
||||||
|
table_data += "<tr>";
|
||||||
|
|
||||||
|
for (const v of sql_row_values) {
|
||||||
|
table_data += `<td>${v}</td>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
table_data += "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
res.render("index", {
|
||||||
|
page_title: app_conf.name,
|
||||||
|
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
|
||||||
|
js_path: path.join(app_conf.paths.js.web, "index.js"),
|
||||||
|
table_header: table_header,
|
||||||
|
table_data: table_data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorPageRenderer(res, "❓", "The database is empty.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
errorPageRenderer(res, "🌋💥", "Internal server error. Check logs for more information.");
|
||||||
|
logger.error(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const app_conf = require("../config/app.conf.js");
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.use(app_conf.paths.css.web, express.static(path.join(path.dirname(require.main.filename), app_conf.paths.css.src)));
|
||||||
|
router.use(app_conf.paths.js.web, express.static(path.join(path.dirname(require.main.filename), app_conf.paths.js.src)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main endpoint - might implement authentication step here...
|
||||||
|
*/
|
||||||
|
router.get("/", (req, res) => {
|
||||||
|
res.render("auth", {
|
||||||
|
page_title: app_conf.name,
|
||||||
|
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
|
||||||
|
protocol: app_conf.protocol,
|
||||||
|
host: app_conf.host
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: "CRTelemetry",
|
|
||||||
port: 80,
|
|
||||||
username: "admin",
|
|
||||||
password: "password",
|
|
||||||
logger: {
|
|
||||||
level: "info",
|
|
||||||
error_path: "/app/logs/error.log",
|
|
||||||
full_path: "/app/logs/combined.log"
|
|
||||||
},
|
|
||||||
timestamp_format: "HH:mm:ss DD-MM-YYYY",
|
|
||||||
views_directory: "/app/views/",
|
|
||||||
temp_directory: "/app/temp/",
|
|
||||||
web_paths: {
|
|
||||||
css: "/app/src/css",
|
|
||||||
js: "/app/src/javascript"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const winston = require("winston");
|
||||||
|
const app_conf = require("../config/app.conf");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize console and file logger
|
||||||
|
*/
|
||||||
|
const logger = winston.createLogger({
|
||||||
|
levels: winston.config.syslog.levels,
|
||||||
|
level: process.env.LOG_LEVEL || app_conf.logger.level,
|
||||||
|
format: winston.format.combine(
|
||||||
|
winston.format.timestamp({
|
||||||
|
format: app_conf.timestamp_format,
|
||||||
|
}),
|
||||||
|
winston.format.printf((info) => `[${info.timestamp}][${info.level}]: ${info.message}`)
|
||||||
|
),
|
||||||
|
transports: [
|
||||||
|
new winston.transports.File({ filename: path.join(path.dirname(require.main.filename), app_conf.logger.error_path), level: "error", }),
|
||||||
|
new winston.transports.File({ filename: path.join(path.dirname(require.main.filename), app_conf.logger.full_path) }),
|
||||||
|
new winston.transports.Console()
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = logger;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
<%= page_title %>
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"
|
||||||
|
rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="<%= css_path %>">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="control_div">
|
||||||
|
<label
|
||||||
|
style='font-family: "Ubuntu", sans-serif; font-weight: 500; font-style: normal; font-size: 200%;'>Centaurus
|
||||||
|
Racing Team</label>
|
||||||
|
</div>
|
||||||
|
<div class="main_div" style="display: flex; flex-direction: column; justify-content: space-between;">
|
||||||
|
<div style="display: flex; flex-direction: row; justify-content: space-evenly;">
|
||||||
|
<label>CRTelemetry SQLite3</label>
|
||||||
|
<a href="<%= protocol %>://<%= host %>/app">Enter</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: "CRTelemetry",
|
||||||
|
host: "localhost",
|
||||||
|
protocol: "http",
|
||||||
|
port: 80,
|
||||||
|
username: "admin",
|
||||||
|
password: "password",
|
||||||
|
token_ttl: 1800,
|
||||||
|
logger: {
|
||||||
|
level: "info",
|
||||||
|
error_path: "/app/logs/error.log",
|
||||||
|
full_path: "/app/logs/combined.log"
|
||||||
|
},
|
||||||
|
timestamp_format: "HH:mm:ss DD-MM-YYYY",
|
||||||
|
views_directory: "/app/views",
|
||||||
|
temp_directory: "/app/temp",
|
||||||
|
paths: {
|
||||||
|
css: {
|
||||||
|
web: "/css",
|
||||||
|
src: "/src/css"
|
||||||
|
},
|
||||||
|
js: {
|
||||||
|
web: "/javascript",
|
||||||
|
src: "/src/javascript"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,346 +1,37 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const Database = require("better-sqlite3");
|
|
||||||
const winston = require("winston");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fileUpload = require("express-fileupload");
|
const fileUpload = require("express-fileupload");
|
||||||
const basicAuth = require("express-basic-auth");
|
const basicAuth = require("express-basic-auth");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const app_conf = require("./app/config/app.conf.js");
|
const app_conf = require("./app/config/app.conf.js");
|
||||||
const db_conf = require("./app/config/db.conf.js");
|
|
||||||
|
const public_routes = require('./app/routes/public_routes');
|
||||||
|
const private_routes = require('./app/routes/private_routes');
|
||||||
|
|
||||||
|
const logger = require("./app/utils/logger.util.js");
|
||||||
|
const db = require("./app/database/sqlite.database.js");
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
var db;
|
|
||||||
var shutting_down = false;
|
var shutting_down = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Static middleware - serve css and js files to public
|
* Static middleware - serve css and js files to public
|
||||||
*/
|
*/
|
||||||
app.use(app_conf.web_paths.css, express.static(path.join(__dirname, app_conf.web_paths.css)));
|
|
||||||
app.use(app_conf.web_paths.js, express.static(path.join(__dirname, app_conf.web_paths.js)));
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(fileUpload({
|
app.use(fileUpload({
|
||||||
limits: { fileSize: 102400 },
|
limits: { fileSize: 102400 },
|
||||||
useTempFiles: true,
|
useTempFiles: true,
|
||||||
tempFileDir: path.join(__dirname, app_conf.temp_directory)
|
tempFileDir: path.join(__dirname, app_conf.temp_directory)
|
||||||
}));
|
}));
|
||||||
app.use(basicAuth({
|
|
||||||
|
app.use("/", public_routes);
|
||||||
|
|
||||||
|
app.use("/app", basicAuth({
|
||||||
users: {
|
users: {
|
||||||
[app_conf.username]: app_conf.password
|
[app_conf.username]: app_conf.password
|
||||||
},
|
},
|
||||||
challenge: true
|
challenge: true
|
||||||
}));
|
}), private_routes);
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize console and file logger
|
|
||||||
*/
|
|
||||||
const logger = winston.createLogger({
|
|
||||||
levels: winston.config.syslog.levels,
|
|
||||||
level: process.env.LOG_LEVEL || app_conf.logger.level,
|
|
||||||
format: winston.format.combine(
|
|
||||||
winston.format.timestamp({
|
|
||||||
format: app_conf.timestamp_format,
|
|
||||||
}),
|
|
||||||
winston.format.printf((info) => `[${info.timestamp}][${info.level}]: ${info.message}`)
|
|
||||||
),
|
|
||||||
transports: [
|
|
||||||
new winston.transports.File({ filename: path.join(__dirname, app_conf.logger.error_path), level: "error", }),
|
|
||||||
new winston.transports.File({ filename: path.join(__dirname, app_conf.logger.full_path) }),
|
|
||||||
new winston.transports.Console()
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
app.delete("/app/remove", async (req, res) => {
|
|
||||||
if (req.query["element"]) {
|
|
||||||
try {
|
|
||||||
const remove = db.prepare(`DELETE FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
|
|
||||||
if (remove.run()["changes"]) {
|
|
||||||
res.status(200).send();
|
|
||||||
} else {
|
|
||||||
res.status(404).send();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).send();
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/app/upload", async (req, res) => {
|
|
||||||
if (!req.files || !req.files.file) {
|
|
||||||
res.status(422).send();
|
|
||||||
} else {
|
|
||||||
const uploadedFile = req.files.file;
|
|
||||||
|
|
||||||
db.close();
|
|
||||||
fs.copyFile(uploadedFile.tempFilePath, db_conf.path, (error) => {
|
|
||||||
if (error) {
|
|
||||||
logger.error(error);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
db = new Database(db_conf.path, { fileMustExist: true });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error);
|
|
||||||
shutting_down = true;
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
res.status(201).send();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/app/download", async (req, res) => {
|
|
||||||
res.download(db_conf.path);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/app/add", async (req, res) => {
|
|
||||||
if (req.query["element"] && req.body) {
|
|
||||||
try {
|
|
||||||
let keys = Object.keys(req.body);
|
|
||||||
let values = `'${req.query["element"]}',`;
|
|
||||||
|
|
||||||
for (const k of keys) {
|
|
||||||
if (req.body[k] === "null") {
|
|
||||||
values += `NULL,`
|
|
||||||
} else {
|
|
||||||
values += `'${req.body[k]}',`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values) {
|
|
||||||
values = values.slice(0, -1);
|
|
||||||
const update = db.prepare(`INSERT INTO ${db_conf.table_name} VALUES (${values});`);
|
|
||||||
update.run();
|
|
||||||
res.status(200).send();
|
|
||||||
} else {
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).send();
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/app/edit", async (req, res) => {
|
|
||||||
if (req.query["element"] && req.body) {
|
|
||||||
try {
|
|
||||||
let keys = Object.keys(req.body);
|
|
||||||
let values = "";
|
|
||||||
|
|
||||||
for (const k of keys) {
|
|
||||||
if (req.body[k] === "null") {
|
|
||||||
values += `${k}=NULL,`
|
|
||||||
} else {
|
|
||||||
values += `${k}='${req.body[k]}',`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values) {
|
|
||||||
values = values.slice(0, -1);
|
|
||||||
const update = db.prepare(`UPDATE ${db_conf.table_name} SET ${values} WHERE Name='${req.query["element"]}'`);
|
|
||||||
update.run();
|
|
||||||
res.status(200).send();
|
|
||||||
} else {
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).send();
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Main endpoint - might implement authentication step here...
|
|
||||||
*/
|
|
||||||
app.get("/", (req, res) => {
|
|
||||||
res.redirect("app/");
|
|
||||||
});
|
|
||||||
|
|
||||||
function errorPageRenderer(res, emoji, message) {
|
|
||||||
res.render("error", {
|
|
||||||
page_title: app_conf.name,
|
|
||||||
css_path: path.join(app_conf.web_paths.css, "stylesheet.css"),
|
|
||||||
error_emoji: emoji,
|
|
||||||
error_message: message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
app.get("/app/add", async (req, res) => {
|
|
||||||
try {
|
|
||||||
const select_get = db.prepare(`SELECT * FROM ${db_conf.table_name};`);
|
|
||||||
const row = select_get.get();
|
|
||||||
|
|
||||||
const sql_header = Object.keys(row);
|
|
||||||
var table_header = `<th>${sql_header[0]}</th>\n`;
|
|
||||||
sql_header.splice(0, 1);
|
|
||||||
|
|
||||||
if (row) {
|
|
||||||
var column_options = {};
|
|
||||||
for (const key of sql_header) {
|
|
||||||
table_header += `<th>${key}</th>\n`;
|
|
||||||
|
|
||||||
const select_distinct = db.prepare(`
|
|
||||||
SELECT DISTINCT ${key}
|
|
||||||
FROM ${db_conf.table_name};
|
|
||||||
`);
|
|
||||||
values = select_distinct.all();
|
|
||||||
|
|
||||||
for (v of values) {
|
|
||||||
if (column_options[key] == null) {
|
|
||||||
column_options[key] = Object.values(v);
|
|
||||||
} else {
|
|
||||||
column_options[key] = column_options[key].concat(Object.values(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var table_data = "";
|
|
||||||
const sql_row_values = Object.values(row);
|
|
||||||
|
|
||||||
table_data += `<tr><td><input type="text" placeholder="Sensor name"></td>\n`;
|
|
||||||
for (let i = 1; i < sql_row_values.length; i++) {
|
|
||||||
table_data += `<td><select></select></td>\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
table_data += "</tr>";
|
|
||||||
res.render("add", {
|
|
||||||
page_title: app_conf.name,
|
|
||||||
css_path: path.join(app_conf.web_paths.css, "stylesheet.css"),
|
|
||||||
js_path: path.join(app_conf.web_paths.js, "add.js"),
|
|
||||||
column_options: JSON.stringify(column_options),
|
|
||||||
table_header: table_header,
|
|
||||||
table_data: table_data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
errorPageRenderer(res, "❓", "The database is empty.");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Edit endpoint - edits a specific row
|
|
||||||
*/
|
|
||||||
app.get("/app/edit", async (req, res) => {
|
|
||||||
if (req.query["element"]) {
|
|
||||||
try {
|
|
||||||
const select_get = db.prepare(`SELECT * FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
|
|
||||||
const row = select_get.get();
|
|
||||||
|
|
||||||
if (row) {
|
|
||||||
const sql_header = Object.keys(row);
|
|
||||||
var table_header = `<th>${sql_header[0]}</th>\n`;
|
|
||||||
sql_header.splice(0, 1);
|
|
||||||
|
|
||||||
var column_options = {};
|
|
||||||
for (const key of sql_header) {
|
|
||||||
table_header += `<th>${key}</th>\n`;
|
|
||||||
|
|
||||||
const select_distinct = db.prepare(`
|
|
||||||
SELECT DISTINCT ${key}
|
|
||||||
FROM ${db_conf.table_name}
|
|
||||||
WHERE ${key} IS NOT NULL
|
|
||||||
AND ${key} NOT IN (
|
|
||||||
SELECT ${key}
|
|
||||||
FROM ${db_conf.table_name}
|
|
||||||
WHERE Name='${req.query["element"]}'
|
|
||||||
AND ${key} IS NOT NULL);
|
|
||||||
`);
|
|
||||||
values = select_distinct.all();
|
|
||||||
|
|
||||||
for (v of values) {
|
|
||||||
if (column_options[key] == null) {
|
|
||||||
column_options[key] = Object.values(v);
|
|
||||||
} else {
|
|
||||||
column_options[key] = column_options[key].concat(Object.values(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var table_data = "";
|
|
||||||
const sql_row_values = Object.values(row);
|
|
||||||
table_data += `<tr><td>${sql_row_values[0]}</td>\n`;
|
|
||||||
sql_row_values.splice(0, 1);
|
|
||||||
|
|
||||||
for (const v of sql_row_values) {
|
|
||||||
table_data += `<td><select><option selected="selected">${v}</option></select></td>\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
table_data += "</tr>";
|
|
||||||
|
|
||||||
res.render("edit", {
|
|
||||||
page_title: app_conf.name,
|
|
||||||
css_path: path.join(app_conf.web_paths.css, "stylesheet.css"),
|
|
||||||
js_path: path.join(app_conf.web_paths.js, "edit.js"),
|
|
||||||
column_options: JSON.stringify(column_options),
|
|
||||||
table_header: table_header,
|
|
||||||
table_data: table_data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
errorPageRenderer(res, "🔍❌", "Not found.");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorPageRenderer(res, "✋⛔", "Bad request.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* App endpoint - shows the database
|
|
||||||
*/
|
|
||||||
app.get("/app", async (req, res) => {
|
|
||||||
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const select = db.prepare(`SELECT * FROM ${db_conf.table_name}`);
|
|
||||||
const rows = select.all();
|
|
||||||
|
|
||||||
if (rows[0]) {
|
|
||||||
const sql_header = Object.keys(rows[0]);
|
|
||||||
|
|
||||||
var table_header = "";
|
|
||||||
for (const key of sql_header) {
|
|
||||||
table_header += `<th>${key}</th>\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
var table_data = "";
|
|
||||||
for (const row of rows) {
|
|
||||||
const sql_row_values = Object.values(row);
|
|
||||||
table_data += "<tr>";
|
|
||||||
|
|
||||||
for (const v of sql_row_values) {
|
|
||||||
table_data += `<td>${v}</td>\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
table_data += "</tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
res.render("index", {
|
|
||||||
page_title: app_conf.name,
|
|
||||||
css_path: path.join(app_conf.web_paths.css, "stylesheet.css"),
|
|
||||||
js_path: path.join(app_conf.web_paths.js, "index.js"),
|
|
||||||
table_header: table_header,
|
|
||||||
table_data: table_data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
errorPageRenderer(res, "❓", "The database is empty.");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
errorPageRenderer(res, "🌋💥", "Internal server error. Check logs for more information.");
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise ExpressJS
|
* Initialise ExpressJS
|
||||||
@@ -350,14 +41,7 @@ app.set("view engine", "ejs");
|
|||||||
app.set("views", path.join(__dirname, app_conf.views_directory));
|
app.set("views", path.join(__dirname, app_conf.views_directory));
|
||||||
const server = app.listen(app_conf.port, () => {
|
const server = app.listen(app_conf.port, () => {
|
||||||
logger.info("Starting Database Editor.");
|
logger.info("Starting Database Editor.");
|
||||||
logger.info("Connecting to Database...");
|
|
||||||
try {
|
|
||||||
db = new Database(db_conf.path, { fileMustExist: true });
|
|
||||||
logger.info("Connected to Database.");
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error.message);
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
fs.rm(path.join(__dirname, app_conf.temp_directory, "/."), { recursive: true }, (error) => {
|
fs.rm(path.join(__dirname, app_conf.temp_directory, "/."), { recursive: true }, (error) => {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
logger.info("Removed temp directory.");
|
logger.info("Removed temp directory.");
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ setEventListeners(download, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setEventListeners(logout, () => {
|
setEventListeners(logout, () => {
|
||||||
window.location.href = `${window.location.protocol}//log:out@${window.location.host}`;
|
window.location.href = `${window.location.protocol}//logout@${window.location.host}/`;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 1; i < sql_rows.length; i++) {
|
for (let i = 1; i < sql_rows.length; i++) {
|
||||||
Reference in New Issue
Block a user