From eac815eaa7e6e613f055c39ecc1ce5fe50164f43 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Thu, 30 Dec 2021 11:18:51 +0200 Subject: Help icon Added a (reusable) help icon that shows additional info about what to do on hover. --- README.md | 4 +-- help.png | Bin 0 -> 2347 bytes index.css | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- index.html | 10 ++++--- server.js | 11 ++++++-- 5 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 help.png diff --git a/README.md b/README.md index 3f86b3f..f118d5f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Food-app -This is a site under development that tells you when your lesson is, when your lunch break is and what the school lunch of the day is. +Readme coming soon! ## Setup -You can add a link to this site to your startup folder to always get to know when your lunch break is when you turn on your computer in school. +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. diff --git a/help.png b/help.png new file mode 100644 index 0000000..51d84df Binary files /dev/null and b/help.png differ diff --git a/index.css b/index.css index 76b5df6..fe6de3b 100644 --- a/index.css +++ b/index.css @@ -2,17 +2,26 @@ margin: 0; padding: 0; text-align: center; + --info-width: 10em; + --fadetime: .3s; + --box-bg: #222; + --box-shadow: black; } +/*** bg etc... ***/ body { background: #444; color: white; padding: 1em; - font-family: Verdana, sans-serif; - text-shadow: .125em .125em black; + font-family: verdana, sans-serif; } +.shadow { + text-shadow: .124em .125em black; +} + +/*** dual layout ***/ #foodshift, #food { width: 100%; box-sizing: border-box; @@ -20,6 +29,7 @@ body { vertical-align: top; } +/*** responsivity ***/ @media screen and (min-width: 700px) { #foodshift @@ -31,12 +41,13 @@ body { } } +/*** the ui blocks ***/ .float-block { display: inline-block; margin: 1em; padding: 1em; - background: #222; + background: var(--box-bg); border: 0 solid black; border-radius: 5px; } @@ -45,18 +56,16 @@ body { margin: .5em; } +/*** the send-button ***/ #send { background: blue; padding: .5em; margin: .5em; - border: 1px solid black; - border-radius: 5px; font-weight: bold; position: relative; right: .125em; bottom: .125em; - box-shadow: .125em .125em; } #send:hover { @@ -64,3 +73,76 @@ body { bottom: .25em; box-shadow: .25em .25em; } + +/*** The shadowed elements ***/ +.highlight { + border: 1px solid black; + border-radius: 5px; + box-shadow: .125em .125em var(--box-shadow); +} + +/*** the info buttons & their animations ***/ +img.info { + width: 1em; + height: 1em; + vertical-align: middle; +} + +img.info ~ span { + position: relative; + vertical-align: middle; + left: -1em; + animation: hide-at-start calc(var(--fadetime) * 1.1); /* this hides the flash of the child element in the start */ +} +@keyframes hide-at-start { + 0% { bottom: 200vh; } + 99%{ bottom: 200vh; } + 100%{ bottom: 0; } +} + +p.infoblock { + display: inline; + position: absolute; + top: .5em; + left: 1.5em; + + background-color: var(--box-bg); + --box-shadow: #111; + margin: 0; + padding: .5em; + border-radius: 0 5px 5px 5px; + + animation-name: fade-out; + animation-duration: var(--fadetime); + visibility: hidden; + opacity: 0; +} + +img.info:hover ~ span > p.infoblock { + animation-name: fade-in; + animation-duration: var(--fadetime); + visibility: visible; + opacity: 1; +} + +@keyframes fade-in { + 0% { + visibility: hidden; + opacity: 0; + } + 100% { + opacity: 1; + visibility: visible; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + visibility: visible; + } + 100% { + opacity: 0; + visibility: hidden; + } +} diff --git a/index.html b/index.html index b12164d..4b6a503 100644 --- a/index.html +++ b/index.html @@ -16,9 +16,11 @@
- +
+ Siis häh? +

Syötä tähän kenttään yhdeltätoista alkavan tuntisi opettaja, kurssikoodi tai luokka. Älä syötä useampaa edellä mainituista, yksi on tarpeeksi.



@@ -32,13 +34,13 @@
- +

-

\(index-type\) \(shift-header\) ruokailuvuoro \(day\):

+

\(index-type\) \(shift-header\) ruokailuvuoro \(day\):

\(shift\)

@@ -46,7 +48,7 @@
-

\(food-header\)

+

\(food-header\)

\(food\)

diff --git a/server.js b/server.js index 39c3a38..2f45e95 100644 --- a/server.js +++ b/server.js @@ -12,7 +12,8 @@ async function init() const build = { "./index.html": buildMain, "./index.css": buildDefault, - "./404/index.css": buildDefault + "./404/index.css": buildDefault, + "./help.png": buildImage }; const errorPath = "./404/index.html"; @@ -80,7 +81,6 @@ async function buildMain(args) { const path = args["path"]; const query = args["query"]; - console.log(query); const foods = args["foods"]; let index; if (typeof query.index === "string") @@ -172,6 +172,13 @@ async function buildDefault(args) return data.toString("utf-8"); } +async function buildImage(args) +{ + const path = args["path"]; + const data = await openFile(path); + return data; +} + function build_replace(s, dict) { -- cgit v1.2.3 From da0fc08fe5a7ee72914197ff4eebd42b397957f6 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Thu, 30 Dec 2021 12:13:11 +0200 Subject: Made the help work somehow on mobile + other minor fixes --- index.css | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/index.css b/index.css index fe6de3b..5e09566 100644 --- a/index.css +++ b/index.css @@ -2,7 +2,7 @@ margin: 0; padding: 0; text-align: center; - --info-width: 10em; + --info-width: 13em; --fadetime: .3s; --box-bg: #222; --box-shadow: black; @@ -103,14 +103,16 @@ img.info ~ span { p.infoblock { display: inline; position: absolute; - top: .5em; - left: 1.5em; + top: 1.5em; + left: calc(var(--info-width) * -1 - 1em); + width: var(--info-width); + z-index: 1; background-color: var(--box-bg); --box-shadow: #111; margin: 0; padding: .5em; - border-radius: 0 5px 5px 5px; + border-radius: 5px 0 5px 5px; animation-name: fade-out; animation-duration: var(--fadetime); -- cgit v1.2.3 From 4c4f007130ff20691b9ac2f5fbf05ed5be3c9931 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Thu, 30 Dec 2021 12:48:42 +0200 Subject: Example input --- index.html | 2 +- parse.js | 28 ++++++++++++++++++++++++++++ server.js | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 4b6a503..b66abad 100644 --- a/index.html +++ b/index.html @@ -18,7 +18,7 @@

- + Siis häh?

Syötä tähän kenttään yhdeltätoista alkavan tuntisi opettaja, kurssikoodi tai luokka. Älä syötä useampaa edellä mainituista, yksi on tarpeeksi.


diff --git a/parse.js b/parse.js index 7c47423..c3b7684 100644 --- a/parse.js +++ b/parse.js @@ -277,9 +277,37 @@ function getShift(day, index, db) // day: int, 1 = monday; index: string of cour 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.randomIndex = getRandomIndex; diff --git a/server.js b/server.js index 2f45e95..d3c8838 100644 --- a/server.js +++ b/server.js @@ -132,6 +132,9 @@ async function buildMain(args) if (res["shift"] === -1) res["shift"] = "Kurssilla/opettajalla/luokalla ei ole ruokailua päivällä tai kurssia ei ole olemassa!"; + // get the example input + res["example-input"] = parse.randomIndex(DB, day - 1); + // get the day let weekdays = ["su", "ma", "ti", "ke", "to", "pe", "la"]; res["day"] = weekdays[day]; -- cgit v1.2.3 From 7743b9ff7b9eb85ea9502e401529f10fed83a0f6 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Thu, 30 Dec 2021 21:30:53 +0200 Subject: Footer --- index.css | 28 ++++++++++++++++++++++++++-- index.html | 6 ++++++ parse.js | 51 --------------------------------------------------- 3 files changed, 32 insertions(+), 53 deletions(-) diff --git a/index.css b/index.css index 5e09566..d71e3f3 100644 --- a/index.css +++ b/index.css @@ -56,6 +56,11 @@ body { margin: .5em; } +/*** the input field & choose ***/ +#input[type="text"], select { + background-color: white; +} + /*** the send-button ***/ #send { background: blue; @@ -74,6 +79,25 @@ body { box-shadow: .25em .25em; } +/*** Footer ***/ +footer { + position: fixed; + top: calc(100% - 3em); + left: 0; + + width: 100%; + margin: 0; + padding: 1em; + line-height: 1em; + box-sizing: border-box; + + background-color: #0d0d0d; +} + +footer > a { + color: #b3b3b3; +} + /*** The shadowed elements ***/ .highlight { border: 1px solid black; @@ -88,7 +112,7 @@ img.info { vertical-align: middle; } -img.info ~ span { +img.info + span { position: relative; vertical-align: middle; left: -1em; @@ -120,7 +144,7 @@ p.infoblock { opacity: 0; } -img.info:hover ~ span > p.infoblock { +img.info:hover + span > p.infoblock { animation-name: fade-in; animation-duration: var(--fadetime); visibility: visible; diff --git a/index.html b/index.html index b66abad..eba1547 100644 --- a/index.html +++ b/index.html @@ -53,5 +53,11 @@
+ + diff --git a/parse.js b/parse.js index c3b7684..77e7b52 100644 --- a/parse.js +++ b/parse.js @@ -1,54 +1,3 @@ -/*let i = 0; - let foodShiftNames = []; - let db = []; // first level array: days - second level array: shifts - third level dict: course/teacher - fourth level array: indexes - while (db.length < weekdays.length) - { - i = findExpression(data, weekdays[db.length], i); - let end = i; - if (db.length === weekdays.length) - end = data.length; - else - end = findExpression(data, weekdays[db.length + 1], i + 1); - - db.push([]); // add the day - let shifts = 0; - - do - { - let teachers = []; - let courses = []; - i = findExpression(data, "RUOKAILUVUORO", i); - let nextLineStart = getNextChar(data, i, "\n"); - foodShiftNames.push(data.substring(i, nextLineStart)); - db[db.length - 1].push([]); // add the food shift - nextLineStart = getNextChar(data, nextLineStart + 1, "\n"); - while (!((nextLineStart - i) > 2)) - { - i = nextLineStart; - nextLineStart = getNextChar(data, i + 1, "\n"); - } - let parsedLine = data.substring(i, nextLineStart).replaceAll(",", "").replaceAll("ja ", ""); - let parse_i = 0; - let nextSpace = getNextChar(parsedLine, parse_i, " "); - while (parse_i !== -1) - { - courses.push(parsedLine.substring(parse_i, nextSpace)); - parse_i = nextSpace + 1; - nextSpace = getNextChar(parsedLine, parse_i, " "); - teachers.push(parsedLine.substring(parse_i, nextSpace)); - parse_i = nextSpace + 1; - nextSpace = getNextChar(parsedLine, parse_i, " "); - } - i = nextLineStart; - db[db.length - 1][shifts][0] = courses; - db[db.length - 1][shifts][1] = teachers; - shifts++; - } while ((i < end) && (i !== -1)) - - i = getNextChar("\n"); - } - return [db, foodShiftNames];*/ - function getCharAmount(s, c) { let n = 0; -- cgit v1.2.3 From 2878bb666d1a2d1032683cd1783dbe6a9b505ba4 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Sat, 1 Jan 2022 11:28:37 +0200 Subject: Clearer Anti-XSS --- parse.js | 4 +++- server.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/parse.js b/parse.js index 77e7b52..81269e7 100644 --- a/parse.js +++ b/parse.js @@ -56,7 +56,9 @@ function findExpression(data, expr, start = 0) function parseCluttered(s) { - return s.replaceAll(".", "").replaceAll(" ", "").replaceAll("<", "(").replaceAll(">", ")").toUpperCase(); + if (!(typeof s === "string")) + return ""; + return s.replaceAll(".", "").replaceAll(" ", "").toUpperCase(); } function parseClasses(classData, DB) diff --git a/server.js b/server.js index d3c8838..2ed10fc 100644 --- a/server.js +++ b/server.js @@ -37,24 +37,40 @@ async function init() // server code async function server(req, res) { + // validate inputs let q = url.parse(req.url, true); - let path = "." + q.pathname; + let ind = q.query.index; + if (typeof ind === "string") + ind = validateIndex(q.query.index.substring(0, 20)); + else + ind = ""; + let d = q.query.day; + if (typeof d === "string") + d = antiXSS(d); + else + d = ""; + q.query = { + index: ind, + day: d + }; + let path = "." + antiXSS(q.pathname); if (path == "./") path = "./index.html"; + // pack the data required by the builders let data; const args = { "path": path, + "path404": errorPath, "query": q.query, "db": DB, "foods": foods }; - if (typeof build[path] === "function") - data = await build[path](args); - else - data = await build404(errorPath, q.pathname); - + // build the page + const buildFound = +(typeof build[path] === "function"); + res.writeHead([404, 200][buildFound]); + data = await [build404, build[path]][buildFound](args); res.write(data); res.end(); } @@ -64,6 +80,27 @@ async function init() } +function validateIndex(sus) +{ + return antiXSS(parse.cluttered(sus)); +} + +function antiXSS(sus) +{ + if (!(typeof sus === "string")) + return ""; + return replace(sus, ["<", ">", "(", ")"], ["<", ">", "(", ")"]); +} + +function replace(s, from, to) +{ + for (let i = 0; i < from.length; i++) + { + s = s.replaceAll(from[i], to[i]); + } + return s; +} + function openFile(path) { return new Promise((resolve, reject) => @@ -82,9 +119,7 @@ async function buildMain(args) const path = args["path"]; const query = args["query"]; const foods = args["foods"]; - let index; - if (typeof query.index === "string") - index = parse.cluttered(query.index); + const index = query.index; const DB = args["db"]; const data = await openFile(path); let data_string = data.toString("utf-8"); @@ -161,11 +196,11 @@ async function buildMain(args) return data_string; } -async function build404(path, attemptpath) +async function build404(args) { - const data = await openFile(path); + const data = await openFile(args["path404"]); const data_string = data.toString("utf-8"); - return data_string.replace("\\(path\\)", attemptpath); + return data_string.replace("\\(path\\)", args["path"]); } async function buildDefault(args) -- cgit v1.2.3 From e7b4d365f287f173c8cc0b5a4d965c3a0579c2e0 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Tue, 4 Jan 2022 14:18:20 +0200 Subject: Minor GUI improvements --- index.css | 1 + index.html | 2 +- scrape.js | 7 ++++++- server.js | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/index.css b/index.css index d71e3f3..1f5a422 100644 --- a/index.css +++ b/index.css @@ -13,6 +13,7 @@ body { background: #444; color: white; padding: 1em; + margin-bottom: 3em; /* for the footer */ font-family: verdana, sans-serif; } diff --git a/index.html b/index.html index eba1547..c9f6c4c 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@
-

LYLL-ruokailuvuoro

+

LYLL-ruokailuvuoro


diff --git a/scrape.js b/scrape.js index 45dd0b4..64e00fb 100644 --- a/scrape.js +++ b/scrape.js @@ -49,7 +49,7 @@ async function scrapeFood(url) let weekdayIndex = weekdays.findIndex(val => { return val === title.substring(0, 2); }); if (weekdayIndex !== -1) - foodList[weekdayIndex] = [title, food]; + foodList[weekdayIndex] = [title, neatify(food)]; titleSpan = getSpan(data, titleTags, foodSpan[1]); foodSpan = getSpan(data, foodTags, titleSpan[1]); @@ -63,5 +63,10 @@ function getFoodLink(week) return `https://eruokalista.lohja.fi/AromieMenus/FI/Default/Lohja/Koulut/Rss.aspx?Id=97f76449-f57c-4217-aede-b5f9dbf2b41e&DateMode=${week}`; } +function neatify(food) +{ + return food.replaceAll(")", ")
").replaceAll(" :", ":").replaceAll(":", ":
"); +} + exports.food = scrapeFood; exports.link = getFoodLink; diff --git a/server.js b/server.js index 2ed10fc..d26da04 100644 --- a/server.js +++ b/server.js @@ -178,7 +178,7 @@ async function buildMain(args) // get the food let food; - food = foods[ +(day < actualDay) ][day]; // test this out more + food = foods[ +(day < actualDay) ][day]; if (food !== undefined) { res["food-header"] = food[0]; -- cgit v1.2.3 From 4e5fe4711fe46a6af740aadbf23bde86bb5acf69 Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Fri, 7 Jan 2022 10:58:02 +0200 Subject: Added the DB class & instructions to set up DB --- README.md | 9 ++++++++- database.js | 37 +++++++++++++++++++++++++++++++++++++ index.html | 2 +- server.js | 1 + 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 database.js diff --git a/README.md b/README.md index f118d5f..7c60f52 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,11 @@ 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. +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 devs ( + id INT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(30) NOT NULL, + description VARCHAR(128), + contact VARCHAR(40) +); diff --git a/database.js b/database.js new file mode 100644 index 0000000..3a2822a --- /dev/null +++ b/database.js @@ -0,0 +1,37 @@ +class Database +{ + constructor(credentials, log) + { + this.connection = mysql.createConnection(credentials); + this.log = log; + } + query(q) + { + return new Promise((resolve, reject), () => + { + this.connection.query(q, (err, res, fields) => + { + if (err) + { + this.log(err); + reject(err); + } + resolve(res); + }); + }); + } + close() + { + this.connection.end(err => + { + if (err) + { + this.log(err); + reject(err); + } + resolve(); + }); + } +} + +exports.Database = Database; diff --git a/index.html b/index.html index c9f6c4c..90e4a9b 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@
-

LYLL-ruokailuvuoro

+

LYLL-ruoka


diff --git a/server.js b/server.js index d26da04..4b1e8a3 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,7 @@ const fs = require("fs"); const url = require("url"); const parse = require("./parse.js"); const scrape = require("./scrape.js"); +const mysql = require("mysql2"); async function init() -- cgit v1.2.3 From 24709fa862636702fd0430e832463b751fce323e Mon Sep 17 00:00:00 2001 From: JoelHMikael Date: Sat, 8 Jan 2022 16:49:37 +0200 Subject: Parsing the shifts (not classes) to the database + some GUI improvements --- 404/index.css | 3 - 404/index.html | 16 --- Cont/404/index.css | 3 + Cont/404/index.html | 26 ++++ Cont/Images/back.png | Bin 0 -> 3528 bytes Cont/Images/help.png | Bin 0 -> 2347 bytes Cont/devs/index.css | 18 +++ Cont/devs/index.html | 26 ++++ Cont/index.css | 175 ++++++++++++++++++++++++ Cont/index.html | 63 +++++++++ Cont/non-main.css | 26 ++++ README.md | 18 +++ database.js | 52 +++++--- dbparse.js | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++ help.png | Bin 2347 -> 0 bytes index.css | 175 ------------------------ index.html | 63 --------- package.json | 29 ++++ parse.js | 1 + server.js | 82 ++++++++++-- 20 files changed, 854 insertions(+), 287 deletions(-) delete mode 100644 404/index.css delete mode 100644 404/index.html create mode 100644 Cont/404/index.css create mode 100644 Cont/404/index.html create mode 100644 Cont/Images/back.png create mode 100644 Cont/Images/help.png create mode 100644 Cont/devs/index.css create mode 100644 Cont/devs/index.html create mode 100644 Cont/index.css create mode 100644 Cont/index.html create mode 100644 Cont/non-main.css create mode 100644 dbparse.js delete mode 100644 help.png delete mode 100644 index.css delete mode 100644 index.html create mode 100644 package.json 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 @@ - - - - - Page not found - - - - - -
-

404: sivua \(path\) ei löytynyt.

-

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

-
- - 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 @@ + + + + + Page not found + + + + + + +
+

404: sivua \(path\) ei löytynyt.

+

Voi myös olla, että palvelimella on tapahtunut virhe. Jos epäilet jälkimmäistä, otathan yhteyttä palvelusta vastaaviin henkilöihin.

+
+ + Takaisin etusivulle + + + + + diff --git a/Cont/Images/back.png b/Cont/Images/back.png new file mode 100644 index 0000000..01b9bc7 Binary files /dev/null and b/Cont/Images/back.png differ diff --git a/Cont/Images/help.png b/Cont/Images/help.png new file mode 100644 index 0000000..51d84df Binary files /dev/null and b/Cont/Images/help.png differ 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 @@ + + + + + Developers + + + + + + +

Sivun kehittäjät

+

Jos muokkaat/lisäät jotain tähän projektiin, voit pyytää serverin ylläpidosta vastaavilta, että nimesi lisätään tietokantaan.

+ + \(devs\) + + Takaisin etusivulle + + + + + diff --git a/Cont/index.css b/Cont/index.css new file mode 100644 index 0000000..1f5a422 --- /dev/null +++ b/Cont/index.css @@ -0,0 +1,175 @@ +* { + margin: 0; + padding: 0; + text-align: center; + --info-width: 13em; + --fadetime: .3s; + --box-bg: #222; + --box-shadow: black; +} + +/*** bg etc... ***/ +body { + background: #444; + color: white; + padding: 1em; + margin-bottom: 3em; /* for the footer */ + + font-family: verdana, sans-serif; +} + +.shadow { + text-shadow: .124em .125em black; +} + +/*** dual layout ***/ +#foodshift, #food { + width: 100%; + box-sizing: border-box; + display: inline-block; + vertical-align: top; +} + +/*** responsivity ***/ +@media screen and (min-width: 700px) +{ + #foodshift + { + width: 58%; + } + #food { + width: 41%; + } +} + +/*** the ui blocks ***/ +.float-block { + display: inline-block; + margin: 1em; + padding: 1em; + + background: var(--box-bg); + border: 0 solid black; + border-radius: 5px; +} + +.float-block p, .float-block h1, .float-block h2, .float-block label, .float-block select, .float-block input { + margin: .5em; +} + +/*** the input field & choose ***/ +#input[type="text"], select { + background-color: white; +} + +/*** the send-button ***/ +#send { + background: blue; + padding: .5em; + margin: .5em; + font-weight: bold; + + position: relative; + right: .125em; + bottom: .125em; +} + +#send:hover { + right: .25em; + bottom: .25em; + box-shadow: .25em .25em; +} + +/*** Footer ***/ +footer { + position: fixed; + top: calc(100% - 3em); + left: 0; + + width: 100%; + margin: 0; + padding: 1em; + line-height: 1em; + box-sizing: border-box; + + background-color: #0d0d0d; +} + +footer > a { + color: #b3b3b3; +} + +/*** The shadowed elements ***/ +.highlight { + border: 1px solid black; + border-radius: 5px; + box-shadow: .125em .125em var(--box-shadow); +} + +/*** the info buttons & their animations ***/ +img.info { + width: 1em; + height: 1em; + vertical-align: middle; +} + +img.info + span { + position: relative; + vertical-align: middle; + left: -1em; + animation: hide-at-start calc(var(--fadetime) * 1.1); /* this hides the flash of the child element in the start */ +} +@keyframes hide-at-start { + 0% { bottom: 200vh; } + 99%{ bottom: 200vh; } + 100%{ bottom: 0; } +} + +p.infoblock { + display: inline; + position: absolute; + top: 1.5em; + left: calc(var(--info-width) * -1 - 1em); + width: var(--info-width); + z-index: 1; + + background-color: var(--box-bg); + --box-shadow: #111; + margin: 0; + padding: .5em; + border-radius: 5px 0 5px 5px; + + animation-name: fade-out; + animation-duration: var(--fadetime); + visibility: hidden; + opacity: 0; +} + +img.info:hover + span > p.infoblock { + animation-name: fade-in; + animation-duration: var(--fadetime); + visibility: visible; + opacity: 1; +} + +@keyframes fade-in { + 0% { + visibility: hidden; + opacity: 0; + } + 100% { + opacity: 1; + visibility: visible; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + visibility: visible; + } + 100% { + opacity: 0; + visibility: hidden; + } +} diff --git a/Cont/index.html b/Cont/index.html new file mode 100644 index 0000000..c35b7c1 --- /dev/null +++ b/Cont/index.html @@ -0,0 +1,63 @@ + + + + + LYLL-ruokailuvuoro + + + + +
+

LYLL-ruoka

+
+ +
+ +
+
+ + +
+ + Siis häh? +

Syötä tähän kenttään yhdeltätoista alkavan tuntisi opettaja, kurssikoodi tai luokka. Älä syötä useampaa edellä mainituista, yksi on tarpeeksi.

+
+ +
+ +
+ + + +
+ +
+

\(index-type\) \(shift-header\) ruokailuvuoro \(day\):

+

\(shift\)

+
+
+ + +
+
+

\(food-header\)

+

\(food\)

+
+
+
+ + + + 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; +} diff --git a/README.md b/README.md index 7c60f52..5ac073c 100644 --- a/README.md +++ b/README.md @@ -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/help.png b/help.png deleted file mode 100644 index 51d84df..0000000 Binary files a/help.png and /dev/null differ diff --git a/index.css b/index.css deleted file mode 100644 index 1f5a422..0000000 --- a/index.css +++ /dev/null @@ -1,175 +0,0 @@ -* { - margin: 0; - padding: 0; - text-align: center; - --info-width: 13em; - --fadetime: .3s; - --box-bg: #222; - --box-shadow: black; -} - -/*** bg etc... ***/ -body { - background: #444; - color: white; - padding: 1em; - margin-bottom: 3em; /* for the footer */ - - font-family: verdana, sans-serif; -} - -.shadow { - text-shadow: .124em .125em black; -} - -/*** dual layout ***/ -#foodshift, #food { - width: 100%; - box-sizing: border-box; - display: inline-block; - vertical-align: top; -} - -/*** responsivity ***/ -@media screen and (min-width: 700px) -{ - #foodshift - { - width: 58%; - } - #food { - width: 41%; - } -} - -/*** the ui blocks ***/ -.float-block { - display: inline-block; - margin: 1em; - padding: 1em; - - background: var(--box-bg); - border: 0 solid black; - border-radius: 5px; -} - -.float-block p, .float-block h1, .float-block h2, .float-block label, .float-block select, .float-block input { - margin: .5em; -} - -/*** the input field & choose ***/ -#input[type="text"], select { - background-color: white; -} - -/*** the send-button ***/ -#send { - background: blue; - padding: .5em; - margin: .5em; - font-weight: bold; - - position: relative; - right: .125em; - bottom: .125em; -} - -#send:hover { - right: .25em; - bottom: .25em; - box-shadow: .25em .25em; -} - -/*** Footer ***/ -footer { - position: fixed; - top: calc(100% - 3em); - left: 0; - - width: 100%; - margin: 0; - padding: 1em; - line-height: 1em; - box-sizing: border-box; - - background-color: #0d0d0d; -} - -footer > a { - color: #b3b3b3; -} - -/*** The shadowed elements ***/ -.highlight { - border: 1px solid black; - border-radius: 5px; - box-shadow: .125em .125em var(--box-shadow); -} - -/*** the info buttons & their animations ***/ -img.info { - width: 1em; - height: 1em; - vertical-align: middle; -} - -img.info + span { - position: relative; - vertical-align: middle; - left: -1em; - animation: hide-at-start calc(var(--fadetime) * 1.1); /* this hides the flash of the child element in the start */ -} -@keyframes hide-at-start { - 0% { bottom: 200vh; } - 99%{ bottom: 200vh; } - 100%{ bottom: 0; } -} - -p.infoblock { - display: inline; - position: absolute; - top: 1.5em; - left: calc(var(--info-width) * -1 - 1em); - width: var(--info-width); - z-index: 1; - - background-color: var(--box-bg); - --box-shadow: #111; - margin: 0; - padding: .5em; - border-radius: 5px 0 5px 5px; - - animation-name: fade-out; - animation-duration: var(--fadetime); - visibility: hidden; - opacity: 0; -} - -img.info:hover + span > p.infoblock { - animation-name: fade-in; - animation-duration: var(--fadetime); - visibility: visible; - opacity: 1; -} - -@keyframes fade-in { - 0% { - visibility: hidden; - opacity: 0; - } - 100% { - opacity: 1; - visibility: visible; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - visibility: visible; - } - 100% { - opacity: 0; - visibility: hidden; - } -} diff --git a/index.html b/index.html deleted file mode 100644 index 90e4a9b..0000000 --- a/index.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - LYLL-ruokailuvuoro - - - - -
-

LYLL-ruoka

-
- -
- -
-
-
- -
- - Siis häh? -

Syötä tähän kenttään yhdeltätoista alkavan tuntisi opettaja, kurssikoodi tai luokka. Älä syötä useampaa edellä mainituista, yksi on tarpeeksi.

-
- -
- -
- -
- -
- -
-

\(index-type\) \(shift-header\) ruokailuvuoro \(day\):

-

\(shift\)

-
-
- - -
-
-

\(food-header\)

-

\(food\)

-
-
-
- - - - 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" + } +} diff --git a/parse.js b/parse.js index 81269e7..a776f13 100644 --- a/parse.js +++ b/parse.js @@ -261,4 +261,5 @@ exports.classes = parseClasses; exports.get = getShift; exports.cluttered = parseCluttered; exports.find = findExpression; +exports.getNextChar = getNextChar; exports.randomIndex = getRandomIndex; diff --git a/server.js b/server.js index 4b1e8a3..26ab9bb 100644 --- a/server.js +++ b/server.js @@ -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(`