"use strict"; var path = require("path"); var bodyParser = require("body-parser"); var util = require("util"); var urlencodedParser = bodyParser.urlencoded({ extended: false }); // ----- SERVER var express = require("express"); var app = express(); const port = 8080; // ----- DATA var ejs = require("ejs"); app.set("view engine", "ejs"); var mysql = require("mysql"); var { Client } = require("pg"); var con; var query; app.use(express.static(path.join(__dirname, 'views'))); /* host: "ctcap09", user: "ets_exm", password: "", database: "guez1", */ // Hostname: ctcap02 // Username: ets_exm // Database: guez_20210926 // If the user presses "GetData" button, they get saved here: let data = {}; let tempData = {}; // If the user presses "GetAllData" button, they get saved here: let allData = []; // Timelabels (01:00, 01:30, 02:00, ...) get saved here: let time = []; // Inputfields get saved here: let inputs = { // Database settings host: "ctcap09", user: "ets_exm", password: "", database: "guez1", startDay: 1, endDay: 1, selectedEvents: [], eventtypes: [], exercise: {}, }; let processStatus = ""; let progressCount = { cur: 0, max: 0 }; // All Exercises get saved here: let allExercises = []; let exerciseTable = ""; // All Eventtypes get saved here: let allEventtypes = []; // All distinct eventtypes on selected exercise let exerciseEventtypes = []; // Days that the user can select get saved here: let days = ["YYYY-MM-DD"]; // If user presses "Connect" button to connect to database. If successfull it gets set to true: let connectedToDatabase = false; let selectedExercise = {}; // Error array (should be 0) let error = 0; /* 1 = Database settings error 2 = 3 = 4 = 5 = */ // Settings that can be changed in /settings let settings = {}; const color = { reset: "\x1b[0m", bright: "\x1b[1m", dim: "\x1b[2m", underscore: "\x1b[4m", blink: "\x1b[5m", reverse: "\x1b[7m", hidden: "\x1b[8m", fg_black: "\x1b[30m", fg_red: "\x1b[31m", fg_green: "\x1b[32m", fg_yellow: "\x1b[33m", fg_blue: "\x1b[34m", fg_magenta: "\x1b[35m", fg_cyan: "\x1b[36m", fg_white: "\x1b[37m", bg_black: "\x1b[40m", bg_red: "\x1b[41m", bg_green: "\x1b[42m", bg_yellow: "\x1b[43m", bg_blue: "\x1b[44m", bg_magenta: "\x1b[45m", bg_cyan: "\x1b[46m", bg_white: "\x1b[47m" } function loadSiteFunc(siteRenderer){ loadSite(siteRenderer, data, time, inputs, days, allExercises, error); } async function loadSite(siteRenderer, dataSet, timeSet, inputsSet, daysSet, allExercisesSet, errorNum) { siteRenderer.render("index", { data: dataSet, time: timeSet, inputs: inputsSet, days: daysSet, allExercises: allExercisesSet, exerciseEventtypes: exerciseEventtypes, error: errorNum }); } async function getExercises() { try { let allExercises = []; const result = await query("SELECT * FROM exm.exercise ORDER BY start_time DESC"); for (let i = 0; i < result.rows.length; i++) { allExercises[i] = {}; allExercises[i]["name"] = result.rows[i].name; if(result.rows[i].start_time == 0){ allExercises[i]["start_time"] = await getStringDay(result.rows[i].begin_time); }else{ allExercises[i]["start_time"] = await getStringDay(result.rows[i].start_time); } if(result.rows[i].stop_time == 0){ allExercises[i]["stop_time"] = await getStringDay(0) }else{ allExercises[i]["stop_time"] = await getStringDay(result.rows[i].stop_time); } allExercises[i]["id"] = result.rows[i].id; } return allExercises; //loadSite(siteRenderer, {}, time, inputs, days, allExercises, error); } catch (err) { errOutput(err); return err } } async function getExerciseDays() { days = []; // Converting selected exercise start time to unix timestamp let mintime = new Date(inputs.exercise.start_time) * 1; // Converting selected exercise stop time to unix timestamp let maxtime = new Date(inputs.exercise.stop_time) * 1; // Calculate time difference let timeDifference = maxtime - mintime; // Calculate day difference from time difference let dayDifference = Math.floor(timeDifference / (1000 * 3600 * 24)); days[0] = await getStringDay(mintime); // Filling the day difference with days for (let i = 0; i < dayDifference ; i++) { let day = new Date(days[i]) day.setDate(day.getDate() + 1); // Converting Unixtimestamp to readable format (YYYY-MM-DD) and inserting it days[i + 1] = await getStringDay(parseInt(day * 1)); } return days; } async function getData(startTime, endTime, dayDif) { try { // Gets correct timelabels for x axis time = []; // 1 Day: 00:00 - 24:00, 2 Days: 00:00 - 24:00 - 00:00 - 24:00, ... for (let i = 0; i < dayDif; i++) { time = time.concat(await getTimeInSteps(startTime, endTime, 23, i)); } data = {}; // For every eventtype in exercise progressCount.max = inputs.eventtypes.length; for (const el of inputs.eventtypes) { if(inputs.selectedEvents.includes(el.id.toString())){ processStatus = el.name; // For showing what the server does on the client progressCount.cur++; // For showing what the server does on the client process.stdout.clearLine(0); process.stdout.cursorTo(0); process.stdout.write("Adding \"" + el.name + "\" to dataset..."); // For showing what the server does on the server data[el.id] = [[], el.name]; // Init data set to zero for (let i = 0; i < 24 * dayDif; i++) { data[el.id][0][i] = 0; } // Get start and end day from user inputs let startDay = new Date(days[parseInt(inputs.startDay)]); let endDay = new Date(days[parseInt(inputs.endDay)]); // Convert to unixtimestamp startDay *= 1; endDay = (endDay * 1) + 86400000; // Plus 24 hours // Sql query to database. Every sample_time from the selected exercise table where the event type is el.id and the sample time between start and endday from user inputs const res2 = await query("SELECT sample_time FROM " + exerciseTable + " WHERE event_type_id = " + el.id + " AND sample_time BETWEEN " + startDay + " AND " + endDay); // For every row from the query result for (const row of res2.rows) { let date = new Date(parseInt(row.sample_time)); // Converts current sample_time to javascript date data[el.id][0][date.getHours() + (24 * Math.floor(Math.abs(date - startDay) / (1000 * 60 * 60 * 24)))]++; /* * date.getHours() - gives a value between 0 and 23 * * Math.floor(Math.abs(date - startDay) / (1000 * 60 * 60 * 24)) - gives the day difference between the start day and the currentday * * The day difference is then multiplied by 24 to give the correct index in the data array * * Datenstruktur: * data = {event_type.id: [[0,0,0,0,0,0,0,0,0,0,0,0,...], event_type.name, [latitude, longitude]], ...} * 24 zeros, every zero stands for a time (first zero = 0:00, second = 1:00,...), if an * event is found at 1:00 that zero is incremented to 1, if another event is found the 1 is incremented to 2. * This is done for every zero on every event_type. */ } } } process.stdout.clearLine(0); process.stdout.cursorTo(0); successOutput("Filled \"dataset\" with data!"); successOutput("Sending data to \"index.ejs\"..."); progressCount.cur = 0; progressCount.max = 0; return data; } catch (err) { console.log(err); errOutput(err); data.errorcode = 600; data.errorinfo = "Something went wrong while the Server processed the data! Please try again later!" return data; } } app.get("/", (req, res2) => { //sendFile(__dirname + "/views/index.html") // -> input field sind nicht richtig loadSiteFunc(res2); //loadSite(res2, data, time, inputs, days, allExercises, error); }); app.get("/settings", (req, res) => { res.render("settings", { settings: settings, error: error }); }) app.get("/processstatus", async (req, res) => { let data = { curElement: processStatus, count: { cur: parseInt(progressCount.cur), max: parseInt(progressCount.max) } } res.send(data); processStatus = ""; }); app.get("/connectdatabase", async function(req, res){ let data = {}; if (req.query.host && req.query.user && req.query.database) { inputs["host"] = req.query.host; inputs["user"] = req.query.user; inputs["password"] = req.query.password; inputs["database"] = req.query.database; // Create connection from user inputs con = new Client({ user: inputs["user"], host: inputs["host"], database: inputs["database"], password: inputs["password"] }); // Check connection to database infoOutput("Connecting to \"" + inputs["database"] + "\"...") await con.connect() .then(async () => { successOutput("Connected to new Database (\"" + inputs["database"] + "\")!"); query = util.promisify(con.query).bind(con); data.errorcode = 0; data.allExercises = await getExercises(); allExercises = data.allExercises; // Save all Exercises }) .catch((err) => { console.log(err); if(err.code == "ENOTFOUND"){ // Hostname wrong data.errorcode = 501; data.errorinfo = "Hostname (" + err.hostname + ") is incorrect! Please check your inputfields and try again!"; }else if(err.code == "28000"){ // Username wrong data.errorcode = 502; data.errorinfo = "Username (" + inputs.user + ") is incorrect! Please check your inputfields and try again!"; }else if(err.code == "WRONG PASSWORD"){ // Not working (Has to be correct err.code) data.errorcode = 503; data.errorinfo = "Password is incorrect! Please check your inputfields and try again!"; }else if(err.code == "3D000"){ // Databasename wrong data.errorcode = 504; data.errorinfo = "Database (" + inputs.database + ") is incorrect! Please check your inputfields and try again!"; } errOutput(err); }); }else{ if(!req.query.host){ // Host inputfield empty data.errorcode = 505; data.errorinfo = "Host inputfield is empty! Please try again!"; }else if(!req.query.user){ // User inputfield empty data.errorcode = 506; data.errorinfo = "User inputfield is empty! Please try again!"; }else if(!req.query.database){ // Database inputfield empty data.errorcode = 508; data.errorinfo = "Database inputfield is empty! Please try again!"; }else{ // Something else data.errorcode = 500; data.errorinfo = "Internal server error!"; } } // Send data to client res.send(data); }); app.get("/selectexercise", async function(req, res){ let data = {}; inputs.startDay = req.query.startDay; inputs.endDay = req.query.endDay; inputs.eventtypes = await getEventtypes(req.query.id); inputs.days = await getExerciseDays(); data.errorcode = 0; data.data = await getData(0, 23, (inputs.endDay - inputs.startDay)+1); data.time = time; data.inputs = inputs; res.send(data); }); app.get("/getdata", async function(req, res){ let data = {}; inputs.startDay = req.query.startDay; inputs.endDay = req.query.endDay; data.errorcode = 0; inputs.selectedEvents = req.query.eventtypes; data.data = await getData(0, 23, (inputs.endDay - inputs.startDay)+1); data.time = time; data.inputs = inputs; res.send(data); }); app.post("/", urlencodedParser, async function (req, res) { let button_id = req.body.button_id; // 1 -> Connect, 2 -> Get Data, 3 -> Get All Data, 6 -> Select Exercise if (button_id == 1) { // Connect Button if (req.body.host && req.body.user && req.body.database) { inputs["host"] = req.body.host; inputs["user"] = req.body.user; inputs["password"] = req.body.password; inputs["database"] = req.body.database; // Create connection from user inputs con = new Client({ user: inputs["user"], host: inputs["host"], database: inputs["database"], password: inputs["password"] }); // Check connection to database infoOutput("Connecting to \"" + inputs["database"] + "\"...") con.connect() .then(async () => { connectedToDatabase = true; inputs["button_id"] = button_id; successOutput("Connected to new Database (\"" + inputs["database"] + "\")!"); query = util.promisify(con.query).bind(con); error = 0; getExercises(res); }) .catch((err) => { connectedToDatabase = false; errOutput(err); error = 1; loadSiteFunc(res); }); } } if (connectedToDatabase) { if (button_id == 2) { // Get Data Button let startTime = 0, endTime = 23; if (req.body.startTime && req.body.endTime) { startTime = parseInt(req.body.startTime); endTime = parseInt(req.body.endTime); // If end time is smaller/earlier than start time if (endTime < startTime) { endTime = startTime + 1; } } else if (req.body.startTime && !req.body.endTime) { startTime = parseInt(req.body.startTime); } else if (!req.body.start && req.body.endTime) { endTime = parseInt(req.body.endTime); } // If user selected eventtypes if (req.body.eventtypes) { // Insert them into inputs inputs["selectedEvents"] = req.body.eventtypes; } else { // Insert "random" number so .length is not 0 inputs["selectedEvents"] = ["1", "7"]; } // Save user inputs into inputs{} inputs["startTime"] = startTime; inputs["endTime"] = endTime; inputs["days"][0] = req.body.startDay; inputs["days"][1] = req.body.endDay; inputs["button_id"] = button_id; // Check if start day is higher than end days if (inputs["days"][0] > inputs["days"][1]) { inputs["days"][0] = inputs["days"][1]; } if (inputs["days"][0] == inputs["days"][1]) { getData(startTime, endTime, 1, res); } else { let dayDif = inputs["days"][1] - inputs["days"][0] + 1; getData(startTime, 23, dayDif, res); } } if (button_id == 6) { // Select exercise inputs["button_id"] = button_id; // Find exercise information selectedExercise = allExercises.find(el => el.id == req.body.exercise) selectedExerciseTable = "ex_" + selectedExercise.id + ".eem_event"; inputs["selectedExercise"] = selectedExercise.name + ", " + selectedExercise.id + ", " + selectedExercise.start_time + ", " + selectedExercise.stop_time; successOutput("Selected exercise: \"" + selectedExercise.name + ", " + selectedExercise.id + ", " + selectedExercise.start_time + ", " + selectedExercise.stop_time + "\""); // Select all event types const RESULTeventtypes = await query("SELECT * FROM pdm.pdm_event_type"); // all event types allEventtypes = RESULTeventtypes.rows; /* exerciseEventtypes = allEventtypes; let count = 0; for(let el in allEventtypes){ inputs["selectedEvents"][count] = el.toString(); count++; }*/ // Get all distinct event types from selected exercise const RESULTexerciseEventtypesid = await query("SELECT DISTINCT event_type_id FROM " + selectedExerciseTable + " ORDER BY event_type_id ASC" ); // all event types in selected exercise const exerciseEventtypesid = RESULTexerciseEventtypesid.rows; exerciseEventtypes = []; for (let i = 0; i < exerciseEventtypesid.length; i++) { // Activate all checkboxes inputs["selectedEvents"][i] = parseInt(exerciseEventtypesid[i].event_type_id).toString(); exerciseEventtypes[i] = {}; // Get name via id from allEventtypes exerciseEventtypes[i] = allEventtypes.find(el => el.id == exerciseEventtypesid[i].event_type_id); } // Empty allExercises so pop up window does not show up allExercises = []; getExerciseDays(res); } } }); async function getEventtypes(exerciseId){ let eventtypes = []; // Set exercise table exerciseTable = "ex_" + exerciseId + ".eem_event"; // Find selected exercise information let exercise = allExercises.find(el => el.id == exerciseId) // Save information in inputs inputs.exercise.name = exercise.name; inputs.exercise.id = exercise.id; inputs.exercise.start_time = exercise.start_time; inputs.exercise.stop_time = exercise.stop_time; successOutput("Selected exercise: \"" + inputs.exercise.name + ", " + inputs.exercise.id + ", " + inputs.exercise.start_time + ", " + inputs.exercise.stop_time + "\""); // Select all event types allEventtypes = (await query("SELECT * FROM pdm.pdm_event_type")).rows; // Get all distinct event types from selected exercise const exerciseEventtypesid = (await query("SELECT DISTINCT event_type_id FROM " + exerciseTable + " ORDER BY event_type_id ASC" )).rows; for (let i = 0; i < exerciseEventtypesid.length; i++) { // Activate all checkboxes inputs.selectedEvents[i] = parseInt(exerciseEventtypesid[i].event_type_id).toString(); eventtypes[i] = {}; // Get name via id from allEventtypes eventtypes[i] = allEventtypes.find(el => el.id == exerciseEventtypesid[i].event_type_id); } return eventtypes; } async function getTimeInSteps(start, end, steps, curDayIndex) { let times = []; // Where times are stored let hour = start; let startDay = new Date(days[parseInt(inputs["startDay"])]) let dayDate = await getStringDay(startDay.setDate(startDay.getDate() + curDayIndex) * 1); // First and last entry are the start and end time times[0] = dayDate + " " +("0" + hour).substr(-2) + ":00"; times[steps] = ("0" + end).substr(-2) + ":00"; let dif = end - start; // Difference between start time and end time let step = dif / steps * 60; // Calculate steps let minutes = 0, printMin, printHour; for (let i = 0; i < steps - 1; i++) { minutes += step; if (minutes >= 60) { // If minutes are over or 60 minutes hour++; // Hour gets incremented minutes -= 60; // Minutes minus 60 } printMin = ("0" + Math.trunc(minutes)).substr(-2); printHour = ("0" + Math.trunc(hour)).substr(-2); times[i + 1] = printHour + ":" + printMin; } return times; // Return times } async function getStringDay(InputTime) { let unixTimestamp = 0; let seperator = "-"; if (InputTime > 0) { unixTimestamp = new Date(parseInt(InputTime)); } else { unixTimestamp = new Date(new Date().getTime()) } return unixTimestamp.getFullYear() + seperator + ("0" + (unixTimestamp.getMonth() + 1)).substr(-2) + seperator + ("0" + unixTimestamp.getDate()).substr(-2); } function infoOutput(message, returnText){ let firstWord = message.split(' ')[0]; let quoteIndex = message.indexOf("\""); let text = color.fg_yellow + color.bg_black + "Message:" + color.reset + " " + color.fg_green + firstWord + color.fg_green + message.substring(firstWord.length, quoteIndex) + "\"" +color.fg_white + message.substring(quoteIndex+1, message.indexOf("\"", quoteIndex+1)) + color.fg_green + message.substring(message.indexOf("\"", quoteIndex+1), message.length+1) + color.reset + color.fg_white; if(returnText) return text; console.log(text); } function successOutput(message){ let firstWord = message.split(' ')[0]; let quoteIndex = message.indexOf("\""); console.log(color.fg_white + color.bg_green + "Successfully:" + color.bg_black + " " + color.fg_yellow + firstWord + color.fg_green + message.substring(firstWord.length, quoteIndex) + "\"" +color.fg_white + message.substring(quoteIndex+1, message.indexOf("\"", quoteIndex+1)) + color.fg_green + message.substring(message.indexOf("\"", quoteIndex+1), message.length+1) + color.reset + color.fg_white); } function errOutput(error) { // Prints error message with red color console.log(color.bg_red + "ERROR CAUGHT:" + color.bg_black + " " + color.fg_red + error + color.fg_white + color.reset); } app.listen(port, () => { infoOutput("Server: \"http://localhost:" + port + "/\""); infoOutput("Settings: \"http://localhost:" + port + "/settings\""); });