Compare commits

..
10 Commits
Author SHA1 Message Date
admin 21333592ac Update package-lock 2025-06-09 10:07:33 +02:00
admin 8b673c67d3 Added comments 2025-06-09 09:48:31 +02:00
admin 0c76b852eb General refactor 2025-06-09 08:53:29 +02:00
admin 1e5cd0790b Code refactor 2025-06-07 10:12:47 +02:00
admin c85b918f71 Update server.js 2025-05-29 12:28:50 +03:00
admin 8d75338676 Fixed port bug 2025-05-19 12:12:33 +03:00
Kostas Drakontidis 7ce2d111be Disabled zoom & fixed indentation 2025-05-18 20:48:26 +03:00
admin d2b606a03a Added about page 2025-05-17 13:43:27 +03:00
admin 8a01233feb Update app.conf.sample 2025-05-17 12:25:48 +03:00
admin a794688270 Update auth.ejs 2025-05-17 11:18:19 +03:00
17 changed files with 201 additions and 93 deletions
+4
View File
@@ -2,8 +2,10 @@ const Database = require("better-sqlite3");
const logger = require("../utils/logger.util"); const logger = require("../utils/logger.util");
const db_conf = require("../config/db.conf"); const db_conf = require("../config/db.conf");
// Holds the database class object
var db; var db;
// Connect to SQLite database
function connect() { function connect() {
try { try {
logger.info("Connecting to Database..."); logger.info("Connecting to Database...");
@@ -14,10 +16,12 @@ function connect() {
} }
} }
// Database object getter
function getDB() { function getDB() {
return db; return db;
} }
// Database object setter
function setDB(newDb) { function setDB(newDb) {
db = newDb; db = newDb;
} }
+45
View File
@@ -10,9 +10,12 @@ const messages = require("../config/messages.conf.js");
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
// Gets an Express response object an emoji code and a string message and renders as error message
function errorPageRenderer(res, emoji, message) { function errorPageRenderer(res, emoji, message) {
res.render("error", { res.render("error", {
page_title: app_conf.name, page_title: app_conf.name,
program: app_conf.program,
app_url: app_conf.app_url,
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"), css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
js_path: path.join(app_conf.paths.js.web, "error.js"), js_path: path.join(app_conf.paths.js.web, "error.js"),
error_emoji: emoji, error_emoji: emoji,
@@ -20,11 +23,14 @@ function errorPageRenderer(res, emoji, message) {
}) })
} }
// Remove SQL row endpoint
router.delete("/remove", async (req, res) => { router.delete("/remove", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
// Get the row Name as request parameter
if (req.query["element"]) { if (req.query["element"]) {
try { try {
// Create and run SQL statement to remove the row
const remove = db.getDB().prepare(`DELETE FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`); const remove = db.getDB().prepare(`DELETE FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
if (remove.run()["changes"]) { if (remove.run()["changes"]) {
res.status(200).send(); res.status(200).send();
@@ -40,21 +46,26 @@ router.delete("/remove", async (req, res) => {
} }
}); });
// Upload SQL database
router.post("/upload", async (req, res) => { router.post("/upload", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
// Check if file received
if (!req.files || !req.files.file) { if (!req.files || !req.files.file) {
res.status(422).send(); res.status(422).send();
} else { } else {
const uploadedFile = req.files.file; const uploadedFile = req.files.file;
// Close current database
if (db.getDB()) { if (db.getDB()) {
db.getDB().close(); db.getDB().close();
} }
// Overwrite current database file with the new one
fs.copyFile(uploadedFile.tempFilePath, db_conf.path, (error) => { fs.copyFile(uploadedFile.tempFilePath, db_conf.path, (error) => {
if (error) { if (error) {
logger.error(error); logger.error(error);
} else { } else {
// Create new database (connect to db) object and store it
try { try {
db.setDB(new Database(db_conf.path, { fileMustExist: true })); db.setDB(new Database(db_conf.path, { fileMustExist: true }));
} catch (error) { } catch (error) {
@@ -66,17 +77,21 @@ router.post("/upload", async (req, res) => {
res.status(201).send(); res.status(201).send();
}); });
// Download current database file
router.get("/download", async (req, res) => { router.get("/download", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
res.download(db_conf.path); res.download(db_conf.path);
}); });
// Add row to database
router.post("/add", async (req, res) => { router.post("/add", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
// Check if row name and row data received
if (req.query["element"] && req.body) { if (req.query["element"] && req.body) {
try { try {
// Constructing and executing SQL statement
let keys = Object.keys(req.body); let keys = Object.keys(req.body);
let values = `'${req.query["element"]}',`; let values = `'${req.query["element"]}',`;
@@ -105,11 +120,14 @@ router.post("/add", async (req, res) => {
} }
}); });
// Edit SQL row
router.post("/edit", async (req, res) => { router.post("/edit", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
// Check if row name and row data received
if (req.query["element"] && req.body) { if (req.query["element"] && req.body) {
try { try {
// Constructing and executing SQL statement
let keys = Object.keys(req.body); let keys = Object.keys(req.body);
let values = ""; let values = "";
@@ -138,10 +156,12 @@ router.post("/edit", async (req, res) => {
} }
}); });
// Add row to database page renderer
router.get("/add", async (req, res) => { router.get("/add", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
try { try {
// Get all SQL columns to create HTML table
const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name};`); const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name};`);
const row = select_get.get(); const row = select_get.get();
@@ -149,6 +169,10 @@ router.get("/add", async (req, res) => {
var table_header = `<th>${sql_header[0]}</th>\n`; var table_header = `<th>${sql_header[0]}</th>\n`;
sql_header.splice(0, 1); sql_header.splice(0, 1);
/*
* Getting all distinct values for each column except the value from the
* current column to add as options to the HTML selects.
*/
if (row) { if (row) {
var column_options = {}; var column_options = {};
for (const key of sql_header) { for (const key of sql_header) {
@@ -180,6 +204,8 @@ router.get("/add", async (req, res) => {
table_data += "</tr>"; table_data += "</tr>";
res.render("add", { res.render("add", {
page_title: app_conf.name, page_title: app_conf.name,
program: app_conf.program,
app_url: app_conf.app_url,
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"), css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
js_path: path.join(app_conf.paths.js.web, "add.js"), js_path: path.join(app_conf.paths.js.web, "add.js"),
column_options: JSON.stringify(column_options), column_options: JSON.stringify(column_options),
@@ -195,9 +221,11 @@ router.get("/add", async (req, res) => {
} }
}); });
// Edit SQL row page
router.get("/edit", async (req, res) => { router.get("/edit", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
// Same as ADD GET REQUEST but Name is constant as it identifies the row
if (req.query["element"]) { if (req.query["element"]) {
try { try {
const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`); const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`);
@@ -246,6 +274,8 @@ router.get("/edit", async (req, res) => {
res.render("edit", { res.render("edit", {
page_title: app_conf.name, page_title: app_conf.name,
program: app_conf.program,
app_url: app_conf.app_url,
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"), css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
js_path: path.join(app_conf.paths.js.web, "edit.js"), js_path: path.join(app_conf.paths.js.web, "edit.js"),
column_options: JSON.stringify(column_options), column_options: JSON.stringify(column_options),
@@ -264,10 +294,12 @@ router.get("/edit", async (req, res) => {
} }
}); });
// Main page
router.get("/", async (req, res) => { router.get("/", async (req, res) => {
logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`);
try { try {
// Get all rows from SQL and creating HTML table
const select = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name}`); const select = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name}`);
const rows = select.all(); const rows = select.all();
@@ -293,6 +325,8 @@ router.get("/", async (req, res) => {
res.render("index", { res.render("index", {
page_title: app_conf.name, page_title: app_conf.name,
program: app_conf.program,
app_url: app_conf.app_url,
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"), css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
js_path: path.join(app_conf.paths.js.web, "index.js"), js_path: path.join(app_conf.paths.js.web, "index.js"),
table_header: table_header, table_header: table_header,
@@ -307,4 +341,15 @@ router.get("/", async (req, res) => {
} }
}); });
// About page for github
router.get("/about", (req, res) => {
res.render("about", {
page_title: app_conf.name,
program: app_conf.program,
app_url: app_conf.app_url,
css_path: path.join(app_conf.paths.css.web, "stylesheet.css"),
version: app_conf.version
});
});
module.exports = router; module.exports = router;
+3 -7
View File
@@ -8,15 +8,11 @@ router.use(app_conf.paths.css.web, express.static(path.join(path.dirname(require
router.use(app_conf.paths.js.web, express.static(path.join(path.dirname(require.main.filename), app_conf.paths.js.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... * Main endpoint - authentication happens here
* Rewritting the whole url to fix logout bug
*/ */
router.get("/", (req, res) => { router.get("/", (req, res) => {
res.render("auth", { res.redirect(`${app_conf.protocol}://${app_conf.host}:${app_conf.port}${app_conf.app_url}`);
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; module.exports = router;
+37
View File
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>
<%= page_title %>
</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<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" style="display: flex; flex-direction: row; justify-content: space-between;">
<label style="font-size: 200%;">
<%= page_title%>
<%= program %>
</label>
</div>
<div class="main_div">
<center>
<label>Version <%= version %></label>
<br>
<a href="https://github.com/Centaurus-Racing-Team/5G-telemetry" target="_blank"
style="font-size: 150%;">GitHub</a>
</center>
<br>
<a href="<%= app_url %>"><span>&#129152; </span>Return</a>
</div>
</body>
</html>
+10 -2
View File
@@ -6,6 +6,7 @@
<%= page_title %> <%= page_title %>
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
@@ -15,12 +16,16 @@
<script src="<%= js_path %>" defer></script> <script src="<%= js_path %>" defer></script>
<script defer> <script defer>
var column_options = '<%- column_options %>'; var column_options = '<%- column_options %>';
var app_url = '<%= app_url %>';
</script> </script>
</head> </head>
<body> <body>
<div class="control_div"> <div class="control_div">
<label style="font-size: 200%;">CRTelemetry SQLite3</label> <label style="font-size: 200%;">
<%= page_title%>
<%= program %>
</label>
</div> </div>
<div class="main_div"> <div class="main_div">
<center><label>Add record</label></center> <center><label>Add record</label></center>
@@ -31,10 +36,13 @@
<%- table_data %> <%- table_data %>
</table> </table>
<div style="display: flex; flex-direction: row; justify-content: space-between;"> <div style="display: flex; flex-direction: row; justify-content: space-between;">
<a href="/app"><span>&#129152; </span>Return</a> <a href="<%= app_url %>"><span>&#129152; </span>Return</a>
<label id="commit" style="cursor: pointer;"><span>&#9989; </span>Commit</label> <label id="commit" style="cursor: pointer;"><span>&#9989; </span>Commit</label>
</div> </div>
</div> </div>
<div class="about_div">
<center><a href="<%= app_url %>/about">About</label></center>
</div>
</body> </body>
</html> </html>
-31
View File
@@ -1,31 +0,0 @@
<!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>
+10 -2
View File
@@ -6,6 +6,7 @@
<%= page_title %> <%= page_title %>
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
@@ -15,12 +16,16 @@
<script src="<%= js_path %>" defer></script> <script src="<%= js_path %>" defer></script>
<script defer> <script defer>
var column_options = '<%- column_options %>'; var column_options = '<%- column_options %>';
var app_url = '<%= app_url %>';
</script> </script>
</head> </head>
<body> <body>
<div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;"> <div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;">
<label style="font-size: 200%;">CRTelemetry SQLite3</label> <label style="font-size: 200%;">
<%= page_title%>
<%= program %>
</label>
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
<label id="remove" style="cursor: pointer; margin-right: 10px;"><span>&#45; </span>Remove</label> <label id="remove" style="cursor: pointer; margin-right: 10px;"><span>&#45; </span>Remove</label>
</div> </div>
@@ -34,10 +39,13 @@
<%- table_data %> <%- table_data %>
</table> </table>
<div style="display: flex; flex-direction: row; justify-content: space-between;"> <div style="display: flex; flex-direction: row; justify-content: space-between;">
<a href="/app"><span>&#129152; </span>Return</a> <a href="<%= app_url %>"><span>&#129152; </span>Return</a>
<label id="commit" style="cursor: pointer;"><span>&#9989; </span>Commit</label> <label id="commit" style="cursor: pointer;"><span>&#9989; </span>Commit</label>
</div> </div>
</div> </div>
<div class="about_div">
<center><a href="<%= app_url %>/about">About</label></center>
</div>
</body> </body>
</html> </html>
+13 -4
View File
@@ -6,6 +6,7 @@
<%= page_title %> <%= page_title %>
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
@@ -13,15 +14,23 @@
rel="stylesheet"> rel="stylesheet">
<link rel="stylesheet" href="<%= css_path %>"> <link rel="stylesheet" href="<%= css_path %>">
<script src="<%= js_path %>" defer></script> <script src="<%= js_path %>" defer></script>
<script defer>
var app_url = '<%= app_url %>';
</script>
</head> </head>
<body> <body>
<input type="file" id="file_input" accept=".db" style="display: none;" /> <input type="file" id="file_input" accept=".db" style="display: none;" />
<div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;"> <div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;">
<label style="font-size: 200%;">CRTelemetry SQLite3</label> <label style="font-size: 200%;">
<%= page_title%>
<%= program %>
</label>
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
<label id="upload" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129093; </span>Upload</label> <label id="upload" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129093;
<label id="download" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129095; </span>Download</label> </span>Upload</label>
<label id="download" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129095;
</span>Download</label>
<label id="logout" style="cursor: pointer; margin-left: 10px;"><span>&#129092; </span>Logout</label> <label id="logout" style="cursor: pointer; margin-left: 10px;"><span>&#129092; </span>Logout</label>
</div> </div>
</div> </div>
@@ -33,7 +42,7 @@
<%= error_message %> <%= error_message %>
</label> </label>
<br> <br>
<a href="/app"><span>&#129152; </span>Return</a> <a href="<%= app_url %>"><span>&#129152; </span>Return</a>
</div> </div>
</body> </body>
+15 -3
View File
@@ -6,6 +6,7 @@
<%= page_title %> <%= page_title %>
</title> </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
@@ -13,16 +14,24 @@
rel="stylesheet"> rel="stylesheet">
<link rel="stylesheet" href="<%= css_path %>"> <link rel="stylesheet" href="<%= css_path %>">
<script src="<%= js_path %>" defer></script> <script src="<%= js_path %>" defer></script>
<script defer>
var app_url = '<%= app_url %>';
</script>
</head> </head>
<body> <body>
<input type="file" id="file_input" accept=".db" style="display: none;" /> <input type="file" id="file_input" accept=".db" style="display: none;" />
<div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;"> <div class="control_div" style="display: flex; flex-direction: row; justify-content: space-between;">
<label style="font-size: 200%;">CRTelemetry SQLite3</label> <label style="font-size: 200%;">
<%= page_title%>
<%= program %>
</label>
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
<label id="add" style="cursor: pointer; margin-right: 10px;"><span>&#43; </span>Add</label> <label id="add" style="cursor: pointer; margin-right: 10px;"><span>&#43; </span>Add</label>
<label id="upload" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129093; </span>Upload</label> <label id="upload" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129093;
<label id="download" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129095; </span>Download</label> </span>Upload</label>
<label id="download" style="cursor: pointer; margin-left: 10px; margin-right: 10px;"><span>&#129095;
</span>Download</label>
<label id="logout" style="cursor: pointer; margin-left: 10px;"><span>&#129092; </span>Logout</label> <label id="logout" style="cursor: pointer; margin-left: 10px;"><span>&#129092; </span>Logout</label>
</div> </div>
</div> </div>
@@ -35,6 +44,9 @@
<%- table_data %> <%- table_data %>
</table> </table>
</div> </div>
<div class="about_div">
<center><a href="<%= app_url %>/about">About</label></center>
</div>
</body> </body>
</html> </html>
+4 -3
View File
@@ -4,6 +4,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "database_editor",
"dependencies": { "dependencies": {
"better-sqlite3": "^11.10.0", "better-sqlite3": "^11.10.0",
"ejs": "^3.1.10", "ejs": "^3.1.10",
@@ -1525,9 +1526,9 @@
} }
}, },
"node_modules/tar-fs": { "node_modules/tar-fs": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chownr": "^1.1.1", "chownr": "^1.1.1",
+4 -2
View File
@@ -1,11 +1,13 @@
module.exports = { module.exports = {
version: "1.0",
name: "CRTelemetry", name: "CRTelemetry",
program: "SQLite3",
host: "localhost", host: "localhost",
protocol: "http", protocol: "http",
port: 80, port: 8080,
app_url: "/app",
username: "admin", username: "admin",
password: "password", password: "password",
token_ttl: 1800,
logger: { logger: {
level: "info", level: "info",
error_path: "/app/logs/error.log", error_path: "/app/logs/error.log",
+12 -6
View File
@@ -18,15 +18,15 @@ var shutting_down = false;
* Static middleware - serve css and js files to public * Static middleware - serve css and js files to public
*/ */
app.use(express.json()); app.use(express.json());
// Set temp directory and upload size limit
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("/", public_routes); app.use(`/`, public_routes);
app.use(`${app_conf.app_url}`, basicAuth({
app.use("/app", basicAuth({
users: { users: {
[app_conf.username]: app_conf.password [app_conf.username]: app_conf.password
}, },
@@ -39,8 +39,8 @@ app.use("/app", basicAuth({
*/ */
app.set("view engine", "ejs"); 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, (error) => {
logger.info("Starting Database Editor."); logger.info(`Starting ${app_conf.name} ${app_conf.program}.`);
db.connect(); db.connect();
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) {
@@ -51,7 +51,13 @@ const server = app.listen(app_conf.port, () => {
logger.error(error.message); logger.error(error.message);
} }
}); });
logger.info(`Listening to port ${app_conf.port}.`);
if (error) {
logger.error(error.message);
shutdown();
} else {
logger.info(`Listening to port ${app_conf.port}.`);
}
}) })
/* /*
+16 -3
View File
@@ -7,9 +7,12 @@ body {
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
-webkit-user-select: none; /* Safari */ -webkit-user-select: none;
-ms-user-select: none; /* IE 10 and IE 11 */ /* Safari */
user-select: none; /* Standard syntax */ -ms-user-select: none;
/* IE 10 and IE 11 */
user-select: none;
/* Standard syntax */
} }
a:visited { a:visited {
@@ -27,6 +30,7 @@ a:hover {
margin: 3px; margin: 3px;
padding: 5px; padding: 5px;
border-radius: 5px; border-radius: 5px;
overflow: auto;
} }
.main_div { .main_div {
@@ -35,6 +39,15 @@ a:hover {
margin: 3px; margin: 3px;
padding: 5px; padding: 5px;
border-radius: 5px; border-radius: 5px;
overflow: auto;
}
.about_div {
color: #ececec;
background-color: #272727;
margin: 3px;
padding: 5px;
border-radius: 5px;
} }
table { table {
+8 -7
View File
@@ -2,9 +2,6 @@ const sql_table = document.getElementById("sql_table");
const sql_row = sql_table.rows; const sql_row = sql_table.rows;
const commit = document.getElementById("commit"); const commit = document.getElementById("commit");
column_options = JSON.parse(column_options);
console.log(column_options);
commit.onmouseenter = async function () { commit.onmouseenter = async function () {
this.style.backgroundColor = "blue"; this.style.backgroundColor = "blue";
} }
@@ -18,12 +15,13 @@ commit.ondblclick = async function () {
if (sql_row[1].cells[0].firstChild.value) { if (sql_row[1].cells[0].firstChild.value) {
let req_body = {}; let req_body = {};
// Constructing request body by getting the values of each HTML select
for (let i = 1; i < sql_row[1].cells.length; i++) { for (let i = 1; i < sql_row[1].cells.length; i++) {
req_body[sql_row[0].cells[i].firstChild.textContent] = sql_row[1].cells[i].firstChild[sql_row[1].cells[i].firstChild.selectedIndex].text; req_body[sql_row[0].cells[i].firstChild.textContent] = sql_row[1].cells[i].firstChild[sql_row[1].cells[i].firstChild.selectedIndex].text;
} }
try { try {
const response = await fetch(`/app/add?element=${sql_row[1].cells[0].firstChild.value}`, { const response = await fetch(`${app_url}/add?element=${sql_row[1].cells[0].firstChild.value}`, {
method: "POST", method: "POST",
body: JSON.stringify(req_body), body: JSON.stringify(req_body),
headers: { headers: {
@@ -31,21 +29,23 @@ commit.ondblclick = async function () {
} }
}); });
if (!response.ok) { if (!response.ok) {
alert(`Add unsuccessful. ${response.status}`);
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} else { } else {
this.style.backgroundColor = "blue"; this.style.backgroundColor = "blue";
window.location.href = "/app"; window.location.href = app_url;
} }
} catch (error) { } catch (error) {
alert(`Add unsuccessful. ${error.message}`); alert(`Add unsuccessful. ${error.message}`);
console.error(error.message);
} }
} else { } else {
alert("Sensor name can't be null."); alert("Sensor name can't be null.");
} }
}; };
// Parsing distinct SQL values from backend
column_options = JSON.parse(column_options);
// Adding options to HTML selects
for (let i = 1; i < sql_row[1].cells.length; i++) { for (let i = 1; i < sql_row[1].cells.length; i++) {
let opts = column_options[sql_row[0].cells[i].textContent]; let opts = column_options[sql_row[0].cells[i].textContent];
@@ -55,6 +55,7 @@ for (let i = 1; i < sql_row[1].cells.length; i++) {
} }
} }
// On right click add custom value - custom value is always the last one in HTML select
sql_row[1].cells[i].firstChild.oncontextmenu = async function (ev) { sql_row[1].cells[i].firstChild.oncontextmenu = async function (ev) {
ev.preventDefault(); ev.preventDefault();
let new_value = prompt("Enter a new value"); let new_value = prompt("Enter a new value");
+7 -11
View File
@@ -4,8 +4,6 @@ const commit = document.getElementById("commit");
const remove = document.getElementById("remove"); const remove = document.getElementById("remove");
var changes = 0; var changes = 0;
column_options = JSON.parse(column_options);
function setEventListeners(element, cb) { function setEventListeners(element, cb) {
element.onmouseenter = async function () { element.onmouseenter = async function () {
this.style.backgroundColor = "blue"; this.style.backgroundColor = "blue";
@@ -24,18 +22,16 @@ function setEventListeners(element, cb) {
setEventListeners(remove, async () => { setEventListeners(remove, async () => {
try { try {
const response = await fetch(`/app/remove?element=${sql_row[1].cells[0].firstChild.textContent}`, { const response = await fetch(`${app_url}/remove?element=${sql_row[1].cells[0].firstChild.textContent}`, {
method: "DELETE" method: "DELETE"
}); });
if (!response.ok) { if (!response.ok) {
alert(`Remove unsuccessful. ${response.status}`);
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} else { } else {
window.location.href = "/app"; window.location.href = app_url;
} }
} catch (error) { } catch (error) {
alert(`Remove unsuccessful. ${error.message}`); alert(`Remove unsuccessful. ${error.message}`);
console.error(error.message);
} }
}); });
@@ -43,6 +39,7 @@ setEventListeners(commit, async () => {
if (changes) { if (changes) {
let req_body = {}; let req_body = {};
// Constructing request body by adding ONLY updated values
for (let i = 1; i < sql_row[1].cells.length; i++) { for (let i = 1; i < sql_row[1].cells.length; i++) {
if (sql_row[1].cells[i].firstChild.selectedIndex != 0) { if (sql_row[1].cells[i].firstChild.selectedIndex != 0) {
req_body[sql_row[0].cells[i].firstChild.textContent] = sql_row[1].cells[i].firstChild[sql_row[1].cells[i].firstChild.selectedIndex].text; req_body[sql_row[0].cells[i].firstChild.textContent] = sql_row[1].cells[i].firstChild[sql_row[1].cells[i].firstChild.selectedIndex].text;
@@ -50,7 +47,7 @@ setEventListeners(commit, async () => {
} }
try { try {
const response = await fetch(`/app/edit?element=${sql_row[1].cells[0].firstChild.textContent}`, { const response = await fetch(`${app_url}/edit?element=${sql_row[1].cells[0].firstChild.textContent}`, {
method: "POST", method: "POST",
body: JSON.stringify(req_body), body: JSON.stringify(req_body),
headers: { headers: {
@@ -58,20 +55,20 @@ setEventListeners(commit, async () => {
} }
}); });
if (!response.ok) { if (!response.ok) {
alert(`Edit unsuccessful. ${response.status}`);
throw new Error(`Response status: ${response.status}`); throw new Error(`Response status: ${response.status}`);
} else { } else {
window.location.href = "/app"; window.location.href = app_url;
} }
} catch (error) { } catch (error) {
alert(`Edit unsuccessful. ${error.message}`); alert(`Edit unsuccessful. ${error.message}`);
console.error(error.message);
} }
} else { } else {
alert("Nothing to commit."); alert("Nothing to commit.");
} }
}); });
column_options = JSON.parse(column_options);
for (let i = 1; i < sql_row[1].cells.length; i++) { for (let i = 1; i < sql_row[1].cells.length; i++) {
let opts = column_options[sql_row[0].cells[i].textContent]; let opts = column_options[sql_row[0].cells[i].textContent];
@@ -97,7 +94,6 @@ for (let i = 1; i < sql_row[1].cells.length; i++) {
sql_row[1].cells[i].firstChild.onchange = async function () { sql_row[1].cells[i].firstChild.onchange = async function () {
if (this.selectedIndex) { if (this.selectedIndex) {
console.log(this);
this.parentElement.style.backgroundColor = "blue"; this.parentElement.style.backgroundColor = "blue";
changes++; changes++;
} else { } else {
+3 -2
View File
@@ -18,13 +18,14 @@ function setEventListeners(element, cb) {
}; };
} }
// Upload SQL database
setEventListeners(upload, async () => { setEventListeners(upload, async () => {
const input = document.getElementById("file_input"); const input = document.getElementById("file_input");
const upload = (file) => { const upload = (file) => {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
fetch('/app/upload', { fetch(`${app_url}/upload`, {
method: 'POST', method: 'POST',
body: formData body: formData
}).then((response) => { }).then((response) => {
@@ -41,7 +42,7 @@ setEventListeners(upload, async () => {
}); });
setEventListeners(download, () => { setEventListeners(download, () => {
window.location.href = "/app/download"; window.location.href = `${app_url}/download`;
}); });
setEventListeners(logout, () => { setEventListeners(logout, () => {
+6 -6
View File
@@ -4,8 +4,6 @@ const download = document.getElementById("download");
const logout = document.getElementById("logout"); const logout = document.getElementById("logout");
const add = document.getElementById("add"); const add = document.getElementById("add");
const sql_rows = sql_table.rows;
function setEventListeners(element, cb) { function setEventListeners(element, cb) {
element.onmouseenter = async function () { element.onmouseenter = async function () {
this.style.backgroundColor = "blue"; this.style.backgroundColor = "blue";
@@ -28,7 +26,7 @@ setEventListeners(upload, async () => {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
fetch('/app/upload', { fetch(`${app_url}/upload`, {
method: 'POST', method: 'POST',
body: formData body: formData
}).then((response) => { }).then((response) => {
@@ -45,19 +43,21 @@ setEventListeners(upload, async () => {
}); });
setEventListeners(add, () => { setEventListeners(add, () => {
window.location.href = "/app/add"; window.location.href = `${app_url}/add`;
}); });
setEventListeners(download, () => { setEventListeners(download, () => {
window.location.href = "/app/download"; window.location.href = `${app_url}/download`;
}); });
setEventListeners(logout, () => { setEventListeners(logout, () => {
window.location.href = `${window.location.protocol}//logout@${window.location.host}/`; window.location.href = `${window.location.protocol}//logout@${window.location.host}/`;
}); });
const sql_rows = sql_table.rows;
for (let i = 1; i < sql_rows.length; i++) { for (let i = 1; i < sql_rows.length; i++) {
setEventListeners(sql_rows[i], () => { setEventListeners(sql_rows[i], () => {
window.location.href = `/app/edit?element=${sql_rows[i].cells[0].innerText}`; window.location.href = `${app_url}/edit?element=${sql_rows[i].cells[0].innerText}`;
}); });
} }