diff options
-rw-r--r-- | 404/index.css | 3 | ||||
-rw-r--r-- | 404/index.html | 16 | ||||
-rw-r--r-- | Cont/404/index.css | 3 | ||||
-rw-r--r-- | Cont/404/index.html | 26 | ||||
-rw-r--r-- | Cont/Images/back.png | bin | 0 -> 3528 bytes | |||
-rw-r--r-- | Cont/Images/help.png (renamed from help.png) | bin | 2347 -> 2347 bytes | |||
-rw-r--r-- | Cont/devs/index.css | 18 | ||||
-rw-r--r-- | Cont/devs/index.html | 26 | ||||
-rw-r--r-- | Cont/index.css (renamed from index.css) | 0 | ||||
-rw-r--r-- | Cont/index.html (renamed from index.html) | 6 | ||||
-rw-r--r-- | Cont/non-main.css | 26 | ||||
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | database.js | 52 | ||||
-rw-r--r-- | dbparse.js | 365 | ||||
-rw-r--r-- | package.json | 29 | ||||
-rw-r--r-- | parse.js | 1 | ||||
-rw-r--r-- | server.js | 82 |
17 files changed, 619 insertions, 52 deletions
diff --git a/404/index.css b/404/index.css deleted file mode 100644 index ceb8016..0000000 --- a/404/index.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - padding-top: calc(30vh); -} diff --git a/404/index.html b/404/index.html deleted file mode 100644 index e6771ad..0000000 --- a/404/index.html +++ /dev/null @@ -1,16 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"> - <title>Page not found</title> - <link href="/index.css" rel="stylesheet" type="text/css"> - <link href="/404/index.css" rel="stylesheet" type="text/css"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - </head> - <body> - <div class="float-block"> - <h1>404: sivua \(path\) ei löytynyt.</h1> - <p>Voi myös olla, että sinulla ei ole oikeuksia sivun tarkasteluun tai että palvelimella on tapahtunut virhe. Jos epäilet jälkimmäistä, otathan yhteyttä joel.kronqvist@edu.lohja.fi</p> - </div> - </body> -</html> diff --git a/Cont/404/index.css b/Cont/404/index.css new file mode 100644 index 0000000..664d7fb --- /dev/null +++ b/Cont/404/index.css @@ -0,0 +1,3 @@ +body { + padding-top: 30vh; +} diff --git a/Cont/404/index.html b/Cont/404/index.html new file mode 100644 index 0000000..5b01684 --- /dev/null +++ b/Cont/404/index.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html lang="fi"> + <head> + <meta charset="utf-8"> + <title>Page not found</title> + <link href="/index.css" rel="stylesheet" type="text/css"> + <link href="/non-main.css" rel="stylesheet" type="text/css"> + <link href="/404/index.css" rel="stylesheet" type="text/css"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + </head> + <body> + <div class="float-block"> + <h1>404: sivua \(path\) ei löytynyt.</h1> + <p>Voi myös olla, että palvelimella on tapahtunut virhe. Jos epäilet jälkimmäistä, otathan yhteyttä palvelusta vastaaviin henkilöihin.</p> + </div> + + <a class="back" href="/"><img src="/Images/back.png" alt="Takaisin etusivulle"></a> + + <footer> + <a href="https://www.github.com/JoelHMikael/FoodJS">Lähdekoodi</a> + <span>|</span> + <a href="/devs">Ota yhteyttä</a> + </footer> + + </body> +</html> diff --git a/Cont/Images/back.png b/Cont/Images/back.png Binary files differnew file mode 100644 index 0000000..01b9bc7 --- /dev/null +++ b/Cont/Images/back.png diff --git a/help.png b/Cont/Images/help.png Binary files differindex 51d84df..51d84df 100644 --- a/help.png +++ b/Cont/Images/help.png diff --git a/Cont/devs/index.css b/Cont/devs/index.css new file mode 100644 index 0000000..1cce621 --- /dev/null +++ b/Cont/devs/index.css @@ -0,0 +1,18 @@ +.column { + display: inline-block; + padding: 0; + margin: .5em; + box-sizing: border-box; + vertical-align: middle; + overflow-wrap: break-word; + width: 100%; +} + + +@media screen and (min-width: 700px) +{ + .column { + width: calc(33% - 2em); + } +} + diff --git a/Cont/devs/index.html b/Cont/devs/index.html new file mode 100644 index 0000000..69116c6 --- /dev/null +++ b/Cont/devs/index.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html lang="fi"> + <head> + <meta charset="utf-8"> + <title>Developers</title> + <link href="/index.css" rel="stylesheet" type="text/css"> + <link href="/non-main.css" rel="stylesheet" type="text/css"> + <link href="/devs/index.css" rel="stylesheet" type="text/css"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + </head> + <body> + <h1 class="shadow">Sivun kehittäjät</h1> + <p>Jos muokkaat/lisäät jotain tähän projektiin, voit pyytää serverin ylläpidosta vastaavilta, että nimesi lisätään tietokantaan.</p> + + \(devs\) + + <a class="back" href="/"><img src="/Images/back.png" alt="Takaisin etusivulle"></a> + + <footer> + <a href="https://www.github.com/JoelHMikael/FoodJS">Lähdekoodi</a> + <span>|</span> + <a href="/devs">Ota yhteyttä</a> + </footer> + + </body> +</html> diff --git a/index.css b/Cont/index.css index 1f5a422..1f5a422 100644 --- a/index.css +++ b/Cont/index.css diff --git a/index.html b/Cont/index.html index 90e4a9b..c35b7c1 100644 --- a/index.html +++ b/Cont/index.html @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="fi"> <head> <meta charset="utf-8"> <title>LYLL-ruokailuvuoro</title> @@ -19,7 +19,7 @@ <label for="index" class="shadow">Opettaja, kurssi tai luokka:</label> <br> <input type="text" name="index" placeholder="\(example-input\)"> - <img src="/help.png" class="info" alt="Siis häh?"> + <img src="/Images/help.png" class="info" alt="Siis häh?"> <span><p class="infoblock highlight">Syötä tähän kenttään yhdeltätoista alkavan tuntisi opettaja, kurssikoodi tai luokka. Älä syötä useampaa edellä mainituista, yksi on tarpeeksi.</p></span> <br> <label for="day">Päivä:</label> @@ -57,7 +57,7 @@ <footer> <a href="https://www.github.com/JoelHMikael/FoodJS">Lähdekoodi</a> <span>|</span> - <a href="https://www.example.com">Ota yhteyttä</a> + <a href="/devs">Ota yhteyttä</a> </footer> </body> </html> diff --git a/Cont/non-main.css b/Cont/non-main.css new file mode 100644 index 0000000..d8003ef --- /dev/null +++ b/Cont/non-main.css @@ -0,0 +1,26 @@ +.back { + display: block; + margin-left: auto; + margin-right: auto; +} + +.back > * { +} + +.back > img { + width: 4rem; + height: 4rem; + margin: 1rem; + filter: drop-shadow(.125rem .125rem 0 black); + position: relative; + bottom: .125rem; + right: .125rem; + vertical-align: middle; + display: inline; +} + +.back > img:hover { + filter: drop-shadow(.20rem .20rem 0 black); + bottom: .20rem; + right: .20rem; +} @@ -4,6 +4,24 @@ Readme coming soon! ## Setup If you want to set up the server, you will have to get a SSL certificate or generate one yourself. If you want to run a dedicated server that can update, you also need to add the cron jobs from crontab\_add. You must create a MySQL DB and give its login info in ../dblogin.txt. The database should have the following tables set up: +CREATE TABLE shiftnames ( + day INT, + id INT, + name VARCHAR(128) NOT NULL, + PRIMARY KEY (day, id) +); +CREATE TABLE classes ( + course VARCHAR(6) PRIMARY KEY, + class VARCHAR(4) +); +CREATE TABLE shifts ( + day INT, + shift INT, + course VARCHAR(6), + teacher VARCHAR(4), + class VARCHAR(4), + PRIMARY KEY (day, course) +); CREATE TABLE devs ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30) NOT NULL, diff --git a/database.js b/database.js index 3a2822a..30396fe 100644 --- a/database.js +++ b/database.js @@ -1,35 +1,55 @@ +const mysql = require("mysql2"); + class Database { - constructor(credentials, log) + constructor(credentials) { this.connection = mysql.createConnection(credentials); - this.log = log; } - query(q) + query(query, values) { - return new Promise((resolve, reject), () => + return new Promise((resolve, reject) => { - this.connection.query(q, (err, res, fields) => + this.connection.query(query, values, (err, res, fields) => { - if (err) - { - this.log(err); - reject(err); - } + if (err) reject(err); + resolve(res); + }); + }); + } + execute(query, values) + { + return new Promise((resolve, reject) => + { + this.connection.execute(query, values, (err, res, fields) => + { + if (err) reject(err); resolve(res); }); }); + + } + query_raw(query) + { + return new Promise((resolve, reject) => + { + this.connection.query(query, (err, res, fields) => + { + if (err) + reject(err) + resolve(res); + }); + }) } close() { - this.connection.end(err => + return new Promise((resolve, reject) => { - if (err) + this.connection.end(err => { - this.log(err); - reject(err); - } - resolve(); + if (err) reject(err); + resolve(); + }); }); } } diff --git a/dbparse.js b/dbparse.js new file mode 100644 index 0000000..b260d50 --- /dev/null +++ b/dbparse.js @@ -0,0 +1,365 @@ + + +// String searching +function getCharAmount(s, c) +{ + let n = 0; + for (let c_i = 0; c_i < s.length; c_i++) + { + n += +(s[c_i] === c); + } + return n; +} +function getNextChar(s, c, i = 0) +{ + if (!(Number.isInteger(i) && (i >= 0))) + return -1; + for (; i < s.length; i++) + { + if (s[i] === c) + return i; + } + return -1; +} +function getNextLine(s, i) +{ + i = getNextChar(s, "\n", i); + i += +(i !== -1) * 1; + return i; +} +function getToLineStartingWith(s, ss, start = 0) +{ + if (!(Number.isInteger(start) && (start >= 0))) + return -1 + + let i = start; + do + { + if (s.substring(i, i + ss.length) === ss) + break; + i = getNextLine(s, i); + } while(i !== -1) + + return i; +} +function findExpression(data, expr, start = 0) +{ + if (start == -1) + return -1; + if (!(Number.isInteger(start) && (start >= 0))) + throw new TypeError("Start must be a positive integer!"); + if (typeof expr !== "string") + return -1; + while ((data.substring(start, start + expr.length) !== expr) && (start + expr.length < data.length)) + start++; + if (data.substring(start, start + expr.length) !== expr) + return -1; + return start; +} + +// Normalizing +function parseCluttered(s) +{ + if (!(typeof s === "string")) + return ""; + return s.replaceAll(".", "").replaceAll(" ", "").toUpperCase(); +} + +// Class parsing +async function writeClasses(classData, DB) +{ + classData = parseCluttered(classData) + "\n"; // newline so that loop can find last value + await DB.query_raw("DELETE FROM classes"); + // parse data to dict + let i = 0; + while (i < classData.length) + { + let separator = getNextChar(classData, ":", i); + if (separator === -1) + break; + let lineEnd = getNextChar(classData, "\n", i); + let key = classData.substring(i, separator); + let val = classData.substring(separator + 1, lineEnd); + i = lineEnd + 1; + let res = await DB.execute("INSERT INTO classes VALUES (?, ?)", [key, val]); + } +} +/* +function parseShift(data, weekdays = ["MAANANTAISIN", "TIISTAISIN", "KESKIVIIKKOISIN", "TORSTAISIN", "PERJANTAISIN"]) +{ + + let i = 0; + let db = []; + while (db.length < weekdays.length) + { + let day = []; + + i = getNextChar(data, "\n", findExpression(data, weekdays[db.length])); + let end; + if (db.length === weekdays.length - 1) + end = data.length; + else + end = findExpression(data, weekdays[db.length + 1]); + let unparsedDay = data.substring(i + 1, end); + day = parseDay(unparsedDay); + + db.push(day); + } + return db; +} + +function parseDay(day) +{ + let shifts = {}; + let i = getToLineStartingWith(day, "RUOKAILUVUORO"); + do + { + let endOfLine = getNextChar(day, "\n", i); + let shiftDesc = day.substring(i, endOfLine); + i = getNextChar(day, "\n", i) + 1; + i = getNextChar(day, "\n", i) + 1; + if (getNextChar(day, "\n", i) === -1) + endOfLine = day.length; + else + endOfLine = getNextChar(day, "\n", i); + let unparsedIndexes = day.substring(i, endOfLine); + shifts[shiftDesc] = parseLine(unparsedIndexes); + i = getToLineStartingWith(day, "RUOKAILUVUORO", i); + } while (i !== -1); + return shifts; +} +function parseLine(line, toRemove = " ja KAHDEN TUTKINNON OPINNOT 1., 2. ja 3. VUOSITASON RYHMÄT ") +{ + let i = 0; + let courses = []; + let teachers = []; + // get to the teachers & courses + let nextSpace = 0; + + if (line.substring(line.length - toRemove.length, line.length) === toRemove) + line = line.substring(0, line.length - toRemove.length); + line = line.replaceAll(",", "").replaceAll("ja ", "").replaceAll(" + ", "+"); + + while (i < line.length) + { + if (line[i] === "+") + { + + nextSpace = getNextChar(line, " ", i); + let nextNextSpace = getNextChar(line, " ", nextSpace + 1); + if (nextNextSpace === -1) + nextNextSpace = line.length; + line = `${line.substring(0, i)} ${line.substring(nextSpace + 1, nextNextSpace)} ${line.substring(i + 1, line.length)}`; + i = nextNextSpace - 1; + } + i++; + } + nextSpace = 0; + i = 0; + + const getElement = list => + { + nextSpace = getNextChar(line, " ", i); + if (nextSpace === -1) + nextSpace = line.length; + list.push(line.substring(i, nextSpace)); + i = nextSpace + 1; + } + + do + { + getElement(courses); + getElement(teachers); + } while (i < line.length) + + return [courses, teachers]; +} + +*/ +async function parseLine(data, day, shift, DB) +{ + // "preprocessing" + let i = 0; + let courses = []; + let teachers = []; + const toRemove = " ja KAHDEN TUTKINNON OPINNOT 1., 2. ja 3. VUOSITASON RYHMÄT "; + if (data.substring(data.length - toRemove.length, data.length) === toRemove) + data = data.substring(0, data.length - toRemove.length); + data = data.replaceAll(",", "").replaceAll("ja ", "").replaceAll(" + ", "+"); + + while (i < data.length) + { + if (data[i] === "+") + { + + nextSpace = getNextChar(data, " ", i); + let nextNextSpace = getNextChar(data, " ", nextSpace + 1); + if (nextNextSpace === -1) + nextNextSpace = data.length; + data = `${data.substring(0, i)} ${data.substring(nextSpace + 1, nextNextSpace)} ${data.substring(i + 1, data.length)}`; + i = nextNextSpace - 1; + } + i++; + } + nextSpace = 0; + i = 0; + + const getElement = list => + { + nextSpace = getNextChar(data, " ", i); + if (nextSpace === -1) + nextSpace = data.length; + list.push(data.substring(i, nextSpace)); + i = nextSpace + 1; + } + + do + { + getElement(courses); + getElement(teachers); + } while (i < data.length) + + let values = "VALUES"; + for(let el = 0; el < courses.length; el++) + { + values += ` ROW(${day}, ${shift}, '${courses[el]}', '${teachers[el]}', NULL),`; + } + values = values.substring(0, values.length - 1); + return DB.execute(`INSERT INTO shifts ${values}`, []); +} + +async function parseDay(data, day, DB) +{ + let i = getToLineStartingWith(data, "RUOKAILUVUORO"); + let indexOfShift = 1; + while (i !== -1) + { + let endOfLine = getNextChar(data, "\n", i); + // Insert the food shift name + let shiftName = DB.execute("INSERT INTO shiftnames VALUES (?, ?, ?)", [day, indexOfShift, data.substring(i, endOfLine)]); + // get to the teachers & courses + i = endOfLine + 1; + i = getNextChar(data, "\n", i) + 1; + if (getNextChar(data, "\n", i) === -1) + endOfLine = data.length; + else + endOfLine = getNextChar(data, "\n", i); + let unparsedIndexes = data.substring(i, endOfLine); + + // do the magic + let lineParse = parseLine(unparsedIndexes, day, indexOfShift, DB); + + i = getToLineStartingWith(data, "RUOKAILUVUORO", i); + indexOfShift++; + await Promise.all([shiftName, lineParse]); + } + return 0; +} + +async function writeShifts(data, DB) +{ + weekdays = ["MAANANTAISIN", "TIISTAISIN", "KESKIVIIKKOISIN", "TORSTAISIN", "PERJANTAISIN"]; + let deletions = Promise.all([ + DB.query_raw("DELETE FROM shifts"), + DB.query_raw("DELETE FROM shiftnames") + ]); + + // iterate over the weekdays + let i = 0; + for (let day = 0; day < weekdays.length; day++) + { + // find the start of the shifts of the day + i = getNextChar(data, "\n", findExpression(data, weekdays[day], i)); + + // find the end of the shifts of the day + let end = [ + data.length, + findExpression(data, weekdays[day + 1], i) + ][+(day !== weekdays.length - 1)]; + + await deletions; // wait for deletion to get completed before proceeding to write new data to the table + + // do the magic: + let shifts = data.substring(i, end); + await parseDay(shifts, day, DB); + + i = end; + } + return 0; +} + +/* +function getIndexType(index) +{ + if (/^[A-Za-zåäöÅÄÖ]{2,3}\d{2,3}$/.test(index)) + return "course"; + if (/^[A-Za-zåäöÅÄÖ]{4}$/.test(index)) + return "teacher"; + if (/^\w\d{3}$/.test(index)) + return "class"; +} + +function getShift(day, index, db) // day: int, 1 = monday; index: string of course/teacher; db: parsed shifts +{ + if ((typeof day !== "number") || isNaN(day) || (typeof index !== "string")) + return -1; + + let shifts = db[day - 1]; + + let _endOfIndex = parseInt(index.substring(2, 4)); + let type = getIndexType(index); + if (type === undefined) + return {}; + let type_index = +(type === "teacher") + (+(type === "class") * 2); + + let res = {}; + for (const [key, val] of Object.entries(shifts)) + { + let indexes = val[type_index]; + for (let i = 0; i < indexes.length; i++) + { + if (indexes[i] === index) + res[key] = [val[0][i], val[1][i], val[2][i]]; + } + } + return res; +} + +function randInt(start, stop) +{ + return start + Math.floor(Math.random() * (stop - start)); +} + +function getIndexes(db, day, shift, type) +{ + let d = db[day]; + let sh = Object.values(d)[shift][type]; + return Object.values(db[day])[shift][type]; +} + +function getRandomIndex(db, day = randInt(0, 5), shift = randInt(0, 3), type = randInt(0, 3)) +{ + let el; + let i = 0; + let indexes = getIndexes(db, day, shift, type); + while ((el === undefined) && (i < indexes.length)) + { + el = indexes[i]; + i++; + } + if (el == undefined) + return getRandomIndex(db); + return el; +} + +exports.build = parseShift; +exports.indexType = getIndexType; +exports.classes = parseClasses; +exports.get = getShift; +exports.cluttered = parseCluttered; +exports.find = findExpression; +exports.getNextChar = getNextChar; +exports.randomIndex = getRandomIndex;*/ + +exports.classes = writeClasses; +exports.build = writeShifts; diff --git a/package.json b/package.json new file mode 100644 index 0000000..cad9a81 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "lyll-ruoka", + "version": "1.0.0", + "description": "Server to serve information about the food shifts and foods in LYLL", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/JoelHMikael/FoodJS.git" + }, + "keywords": [ + "food", + "server", + "database", + "school" + ], + "author": "Joel Kronqvist", + "license": "UNLICENSED", + "bugs": { + "url": "https://github.com/JoelHMikael/FoodJS/issues" + }, + "homepage": "https://github.com/JoelHMikael/FoodJS#readme", + "dependencies": { + "mysql2": "^2.3.3" + } +} @@ -261,4 +261,5 @@ exports.classes = parseClasses; exports.get = getShift; exports.cluttered = parseCluttered; exports.find = findExpression; +exports.getNextChar = getNextChar; exports.randomIndex = getRandomIndex; @@ -3,7 +3,8 @@ const fs = require("fs"); const url = require("url"); const parse = require("./parse.js"); const scrape = require("./scrape.js"); -const mysql = require("mysql2"); +const SQL_DBS = require("./database.js"); +const DBPARSE = require("./dbparse.js"); async function init() @@ -11,24 +12,36 @@ async function init() const weekdays = [undefined, "MAANANTAI", "TIISTAI", "KESKIVIIKKO", "TORSTAI", "PERJANTAI", undefined]; const build = { - "./index.html": buildMain, - "./index.css": buildDefault, - "./404/index.css": buildDefault, - "./help.png": buildImage + "./Cont/index.html": buildMain, + "./Cont/index.css": buildDefault, + "./Cont/devs/index.html": buildDevs, + "./Cont/devs/index.css": buildDefault, + "./Cont/404/index.css": buildDefault, + "./Cont/non-main.css": buildDefault, + "./Cont/Images/help.png": buildImage, + "./Cont/Images/back.png": buildImage }; - const errorPath = "./404/index.html"; + const errorPath = "./Cont/404/index.html"; // await for needed things in async - let [shiftCont, classCont, foodsThisWeek, foodsNextWeek] = await Promise.all([ + let [shiftCont, classCont, foodsThisWeek, foodsNextWeek, dbcredentials] = await Promise.all([ openFile("./shifts.txt"), openFile("./classes.txt"), scrape.food(scrape.link(1)), - scrape.food(scrape.link(2)) + scrape.food(scrape.link(2)), + openFile("../dblogin.txt") ]); + // get the MySQL DB connection + const SQLDB = new SQL_DBS.Database(JSON.parse(dbcredentials)); + // get the food shift "database" shiftCont = shiftCont.toString("utf-8").replaceAll("\r", ""); // \r because of the \r\n newline on windows which creates problems classCont = classCont.toString("utf-8").replaceAll("\r", ""); + + await DBPARSE.classes(classCont, SQLDB); + await DBPARSE.build(shiftCont, SQLDB); + let DB = parse.build(shiftCont); parse.classes(classCont, DB); @@ -54,9 +67,9 @@ async function init() index: ind, day: d }; - let path = "." + antiXSS(q.pathname); - if (path == "./") - path = "./index.html"; + let path = "./Cont" + antiXSS(q.pathname); + if (isDir(path)) + path += ["/index.html", "index.html"][+(path[path.length - 1] === "/")]; // pack the data required by the builders let data; @@ -65,7 +78,8 @@ async function init() "path404": errorPath, "query": q.query, "db": DB, - "foods": foods + "foods": foods, + "sqldb": SQLDB }; // build the page @@ -77,10 +91,21 @@ async function init() } // start server - http.createServer(server).listen(8080); + const runningServer = http.createServer(server).listen(8080); + + // stop server + function closeServer() { + SQLDB.close(); + runningServer.close(); + } + process.on("SIGINT", closeServer); + process.on("SIGQUIT", closeServer); + process.on("SIGTERM", closeServer); } + + function validateIndex(sus) { return antiXSS(parse.cluttered(sus)); @@ -93,6 +118,12 @@ function antiXSS(sus) return replace(sus, ["<", ">", "(", ")"], ["<", ">", "(", ")"]); } +function isDir(path) +{ + return (parse.getNextChar(path.substring(1), ".") === -1); +} + + function replace(s, from, to) { for (let i = 0; i < from.length; i++) @@ -131,7 +162,7 @@ async function buildMain(args) let day = d.getDay(); const actualDay = day; day = +((day === 0) || (day === 6)) + (+(!(day === 0) && !(day === 6)) * day); - if ((typeof query.day === "string") && (parseInt(query.day).toString() === query.day) && (!isNaN(parseInt(query.day))) && (parseInt(query.day) > 0) && (parseInt(query.day) < 7)) + if ((typeof query.day === "string") && (parseInt(query.day).toString() === query.day) && (!isNaN(parseInt(query.day))) && (parseInt(query.day) > 0) && (parseInt(query.day) < 6)) day = parseInt(query.day); data_string = data_string.replace(`<option value=\"${day}\">`, `<option value=\"${day}\" selected>`); @@ -197,8 +228,31 @@ async function buildMain(args) return data_string; } +async function buildDevs(args) +{ + const path = args["path"]; + const data = await openFile(path); + const DB = args["sqldb"]; + + let res = ""; + let devs = await DB.query_raw("SELECT name, description, contact FROM devs"); + for (let dev = 0; dev < devs.length; dev++) + { + let devInfo = devs[dev]; + res += '<div class="float-block">' + + `<p class="column">${devInfo.name}</p>` + + `<p class="column">${devInfo.description}</p>` + + `<a href="mailto:${devInfo.contact}" class="column" style="white-space: nowrap; overflow: hidden; overflow-wrap: normal; text-overflow: ellipsis;">${devInfo.contact}</a>` + + '</div>'; + } + + return build_replace(data.toString("utf-8"), {"devs": res}); +} + + async function build404(args) { + args["path"] = args["path"].substring("./Cont".length); const data = await openFile(args["path404"]); const data_string = data.toString("utf-8"); return data_string.replace("\\(path\\)", args["path"]); |