diff --git a/app/routes/private_routes.js b/app/routes/private_routes.js index cd39cbc..6eaa489 100644 --- a/app/routes/private_routes.js +++ b/app/routes/private_routes.js @@ -11,6 +11,7 @@ const map = require("../utils/map.util.js"); 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, @@ -23,6 +24,7 @@ function errorPageRenderer(res, emoji, message) { }) } +// Disable map endpoint router.get("/disable", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -31,6 +33,7 @@ router.get("/disable", async (req, res) => { res.status(200).send(); }); +// Enable map endpoint router.get("/enable", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -45,17 +48,20 @@ router.get("/enable", async (req, res) => { } }); +// Remove map endpoint router.delete("/remove", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Get map name var element = req.query["element"]; if (element) { try { + // Delete map file and check if the map was selected - to disable it fs.unlinkSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, element)); if (fs.existsSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected"))) { selected_map_name = fs.readFileSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected"), "utf-8"); if (selected_map_name == element) { - fs.unlinkSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected")); + fs.writeFileSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected"), ""); } } res.status(200).send(); @@ -68,6 +74,7 @@ router.delete("/remove", async (req, res) => { } }); +// Upload map file router.post("/upload", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -87,6 +94,7 @@ router.post("/upload", async (req, res) => { } }); +// Download map router.get("/download", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -97,9 +105,11 @@ router.get("/download", async (req, res) => { } }); +// Add new map router.post("/add", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Get new map data and write it to csv if (req.body) { await map.addMap(`${map_conf.prefix}_${uuid.v4()}.${map_conf.extension}`, req.body["meta"], req.body["throttle"], req.body["motor"]); @@ -109,11 +119,14 @@ router.post("/add", async (req, res) => { } }); +// Edit map data router.post("/edit", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); + // Check if a map name and data have been received if (req.query["element"] && req.body) { try { + // Update the map file await map.updateMap(req.query["element"], req.body["meta"], req.body["throttle"], req.body["motor"]); res.status(200).send(); @@ -126,6 +139,7 @@ router.post("/edit", async (req, res) => { } }); +// Add map page router.get("/add", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -142,6 +156,7 @@ router.get("/add", async (req, res) => { }); }); +// Edit map page router.get("/edit", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -174,6 +189,7 @@ router.get("/edit", async (req, res) => { } }); +// Main page router.get("/", async (req, res) => { logger.info(`${req.method}: "${req.url}" => ${req.get("User-Agent")}`); @@ -181,10 +197,12 @@ router.get("/", async (req, res) => { const maps = await map.getAvailableMaps(); var selected_map_name = ""; + // Check if a map has been selected to show it if (fs.existsSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected"))) { selected_map_name = fs.readFileSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, "selected"), "utf-8"); } + // Construct the maps table var table_data = ""; if (Object.keys(maps).length) { for (m of Object.keys(maps)) { @@ -229,6 +247,7 @@ router.get("/", async (req, res) => { } }); +// About page 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 ad716ec..9b23520 100644 --- a/app/routes/public_routes.js +++ b/app/routes/public_routes.js @@ -9,7 +9,8 @@ router.use(app_conf.paths.js.web, express.static(path.join(path.dirname(require. router.use(app_conf.paths.chartjs.web, express.static(path.join(path.dirname(require.main.filename), app_conf.paths.chartjs.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/app/utils/map.util.js b/app/utils/map.util.js index d678982..772d2e3 100644 --- a/app/utils/map.util.js +++ b/app/utils/map.util.js @@ -5,10 +5,12 @@ const uuid = require("uuid"); const map_conf = require("../config/map.conf"); const logger = require("./logger.util"); +// Creates new map async function addMap(filename, meta, throttle, motor) { var total = ""; var map = [[[]]]; + // Get the new map metadata if (meta) { if ("name" in meta) { total += `#name:${meta["name"]}\n`; @@ -21,7 +23,9 @@ async function addMap(filename, meta, throttle, motor) { } } + // Check if the required data has been received if (throttle && motor && ("0" in motor) && ("1" in motor)) { + // Creating csv and storing it const throttle_values = Object.values(throttle); const current_values = Object.values(motor["0"]); const brake_values = Object.values(motor["1"]); @@ -39,10 +43,13 @@ async function addMap(filename, meta, throttle, motor) { } } +// Update current map file async function updateMap(filename, meta, throttle, motor) { + // Get merged map comments and data var total = await generateComments(filename, meta); const map = await generateData(filename, throttle, motor); + // Create and store file try { await csv.writeToString(map).then(data => total += data); fs.writeFileSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, filename), total); @@ -55,6 +62,7 @@ async function updateMap(filename, meta, throttle, motor) { } } +// Merges data from a stored map and a new map async function generateData(filename, throttle, motor) { const map = await parseMap(filename, 0); @@ -80,6 +88,7 @@ async function generateData(filename, throttle, motor) { return map; } +// Merges comments from stored map and new map async function generateComments(filename, meta) { const comments = await parseMapJson(filename, 1); var comment_string = ""; @@ -105,6 +114,7 @@ async function generateComments(filename, meta) { return comment_string; } +// Check if a map exists function mapExists(filename) { if (path.extname(filename) != ".csv") { return false; @@ -112,7 +122,7 @@ function mapExists(filename) { return fs.existsSync(path.join(path.dirname(require.main.filename), map_conf.map_storage_path, filename)); } -// mode: comments 1 or data 0 +// Parse a map and returns it as array. On 1 returns comments on 0 returns data function parseMap(filename, mode) { var result = []; @@ -131,6 +141,7 @@ function parseMap(filename, mode) { }); } +// Parse map data as JSON async function parseMapJson(filename, mode) { const map = await parseMap(filename, mode); var json_map = {}; @@ -150,8 +161,8 @@ async function parseMapJson(filename, mode) { return json_map } +// Get available map names in storage directory async function getAvailableMaps() { - // path in app_conf var available_maps = {}; try { diff --git a/server.js b/server.js index b432c7f..5c6a958 100644 --- a/server.js +++ b/server.js @@ -17,6 +17,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 36706f9..700f5e5 100644 --- a/src/javascript/add.js +++ b/src/javascript/add.js @@ -25,6 +25,7 @@ function setEventListeners(element, cb) { }; } +// Creates a request body with all data to add new map setEventListeners(commit, async () => { if (changes) { let req_body = {}; @@ -33,26 +34,33 @@ setEventListeners(commit, async () => { req_body["throttle"] = {}; req_body["motor"] = { 0: {}, 1: {} }; + // blue color means the value has been changed if (map_name.style.backgroundColor == "blue") { + // Write the map name metadata req_body["meta"]["name"] = map_name.value; } if (map_id.style.backgroundColor == "blue") { + // Write the map id metadata req_body["meta"]["id"] = map_id.value; } if (map_description.style.backgroundColor == "blue") { + // Write the map description metadata req_body["meta"]["description"] = map_description.value; } + // Write the throttle output data for each step for (let i = 1; i < throttle_table.rows[1].cells.length; i++) { let e = throttle_table.rows[1].cells[i].firstChild; req_body["throttle"][i - 1] = (e.value ? e.value : e.placeholder); } + // Write the motor current data for each step for (let i = 1; i < motor_table.rows[1].cells.length; i++) { let e = motor_table.rows[1].cells[i].firstChild; req_body["motor"][0][i - 1] = (e.value ? e.value : e.placeholder); } + // Write the motor brake current data for each step for (let i = 1; i < motor_table.rows[2].cells.length; i++) { let e = motor_table.rows[2].cells[i].firstChild; req_body["motor"][1][i - 1] = (e.value ? e.value : e.placeholder); @@ -79,6 +87,7 @@ setEventListeners(commit, async () => { } }); +// Handles the throttle chart and table (function () { let data = []; @@ -89,6 +98,7 @@ setEventListeners(commit, async () => { throttle_output_row.appendChild(Object.assign(document.createElement("th"), { textContent: "Throttle output" })); for (let i = 0; i <= steps; i++) { + // Initialize throttle table let c_percentage = i * ((max_throttle * 100) / steps); let c_output = 0; @@ -106,6 +116,7 @@ setEventListeners(commit, async () => { placeholder: c_output }) + // onchange event, tracks number of changes, checks the value and changes color to blue input.onchange = async function () { if (this.value) { let value = parseFloat(this.value); @@ -135,6 +146,7 @@ setEventListeners(commit, async () => { this.style.backgroundColor = ""; changes--; + // Update chart throttle_chart.data.datasets[0].data[this.parentElement.cellIndex - 1] = this.placeholder; throttle_chart.update(); } @@ -148,6 +160,7 @@ setEventListeners(commit, async () => { throttle_table.appendChild(throttle_percentage_row); throttle_table.appendChild(throttle_output_row); + // Chart class object const throttle_chart = new Chart( throttle_plot, { @@ -169,6 +182,7 @@ setEventListeners(commit, async () => { ); })(); +// Same as throttle but for motor current and motor brake current (function () { let data = []; diff --git a/src/javascript/edit.js b/src/javascript/edit.js index b27a04b..77bea16 100644 --- a/src/javascript/edit.js +++ b/src/javascript/edit.js @@ -1,3 +1,4 @@ +// Same as map add.js with minor changes const commit = document.getElementById("commit"); const enable = document.getElementById("enable"); const download = document.getElementById("download");