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(`