diff --git a/app/database/sqlite.database.js b/app/database/sqlite.database.js index dfcac54..03c2be4 100644 --- a/app/database/sqlite.database.js +++ b/app/database/sqlite.database.js @@ -2,8 +2,10 @@ const Database = require("better-sqlite3"); const logger = require("../utils/logger.util"); const db_conf = require("../config/db.conf"); +// Holds the database class object var db; +// Connect to SQLite database function connect() { try { logger.info("Connecting to Database..."); @@ -14,10 +16,12 @@ function connect() { } } +// Database object getter function getDB() { return db; } +// Database object setter function setDB(newDb) { db = newDb; } diff --git a/app/routes/private_routes.js b/app/routes/private_routes.js index 1b934ca..8c0ab92 100644 --- a/app/routes/private_routes.js +++ b/app/routes/private_routes.js @@ -10,6 +10,7 @@ const messages = require("../config/messages.conf.js"); const express = require('express'); 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) { res.render("error", { page_title: app_conf.name, @@ -22,11 +23,14 @@ function errorPageRenderer(res, emoji, message) { }) } +// Remove SQL row endpoint router.delete("/remove", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Get the row Name as request parameter if (req.query["element"]) { 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"]}';`); if (remove.run()["changes"]) { res.status(200).send(); @@ -42,21 +46,26 @@ router.delete("/remove", async (req, res) => { } }); +// Upload SQL database router.post("/upload", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Check if file received if (!req.files || !req.files.file) { res.status(422).send(); } else { const uploadedFile = req.files.file; + // Close current database if (db.getDB()) { db.getDB().close(); } + // Overwrite current database file with the new one fs.copyFile(uploadedFile.tempFilePath, db_conf.path, (error) => { if (error) { logger.error(error); } else { + // Create new database (connect to db) object and store it try { db.setDB(new Database(db_conf.path, { fileMustExist: true })); } catch (error) { @@ -68,17 +77,21 @@ router.post("/upload", async (req, res) => { res.status(201).send(); }); +// Download current database file router.get("/download", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); res.download(db_conf.path); }); +// Add row to database router.post("/add", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Check if row name and row data received if (req.query["element"] && req.body) { try { + // Constructing and executing SQL statement let keys = Object.keys(req.body); let values = `'${req.query["element"]}',`; @@ -107,11 +120,14 @@ router.post("/add", async (req, res) => { } }); +// Edit SQL row router.post("/edit", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Check if row name and row data received if (req.query["element"] && req.body) { try { + // Constructing and executing SQL statement let keys = Object.keys(req.body); let values = ""; @@ -140,10 +156,12 @@ router.post("/edit", async (req, res) => { } }); +// Add row to database page renderer router.get("/add", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); try { + // Get all SQL columns to create HTML table const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name};`); const row = select_get.get(); @@ -151,6 +169,10 @@ router.get("/add", async (req, res) => { var table_header = `${sql_header[0]}\n`; 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) { var column_options = {}; for (const key of sql_header) { @@ -199,9 +221,11 @@ router.get("/add", async (req, res) => { } }); +// Edit SQL row page router.get("/edit", async (req, res) => { 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"]) { try { const select_get = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name} WHERE Name='${req.query["element"]}';`); @@ -270,10 +294,12 @@ router.get("/edit", async (req, res) => { } }); +// Main page router.get("/", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); try { + // Get all rows from SQL and creating HTML table const select = db.getDB().prepare(`SELECT * FROM ${db_conf.table_name}`); const rows = select.all(); @@ -315,6 +341,7 @@ router.get("/", async (req, res) => { } }); +// About page for github router.get("/about", (req, res) => { res.render("about", { page_title: app_conf.name, diff --git a/app/routes/public_routes.js b/app/routes/public_routes.js index 0bed904..c12a319 100644 --- a/app/routes/public_routes.js +++ b/app/routes/public_routes.js @@ -8,7 +8,8 @@ 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))); /* - * Main endpoint - might implement authentication step here... + * Main endpoint - authentication happens here + * Rewritting the whole url to fix logout bug */ router.get("/", (req, res) => { res.redirect(`${app_conf.protocol}://${app_conf.host}:${app_conf.port}${app_conf.app_url}`); diff --git a/server.js b/server.js index d26319d..86a948c 100644 --- a/server.js +++ b/server.js @@ -18,6 +18,7 @@ var shutting_down = false; * Static middleware - serve css and js files to public */ app.use(express.json()); +// Set temp directory and upload size limit app.use(fileUpload({ limits: { fileSize: 102400 }, useTempFiles: true, diff --git a/src/javascript/add.js b/src/javascript/add.js index ca2bcc4..94ab017 100644 --- a/src/javascript/add.js +++ b/src/javascript/add.js @@ -15,6 +15,7 @@ commit.ondblclick = async function () { if (sql_row[1].cells[0].firstChild.value) { 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++) { req_body[sql_row[0].cells[i].firstChild.textContent] = sql_row[1].cells[i].firstChild[sql_row[1].cells[i].firstChild.selectedIndex].text; } @@ -41,8 +42,10 @@ commit.ondblclick = async function () { } }; +// 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++) { let opts = column_options[sql_row[0].cells[i].textContent]; @@ -52,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) { ev.preventDefault(); let new_value = prompt("Enter a new value"); diff --git a/src/javascript/edit.js b/src/javascript/edit.js index 829599d..c2af2c3 100644 --- a/src/javascript/edit.js +++ b/src/javascript/edit.js @@ -39,6 +39,7 @@ setEventListeners(commit, async () => { if (changes) { let req_body = {}; + // Constructing request body by adding ONLY updated values for (let i = 1; i < sql_row[1].cells.length; i++) { 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; diff --git a/src/javascript/error.js b/src/javascript/error.js index 0d9a0a9..ae9bec2 100644 --- a/src/javascript/error.js +++ b/src/javascript/error.js @@ -18,6 +18,7 @@ function setEventListeners(element, cb) { }; } +// Upload SQL database setEventListeners(upload, async () => { const input = document.getElementById("file_input"); const upload = (file) => {