aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joelkronqvist@proton.me>2023-06-21 14:18:27 +0300
committerJoel Kronqvist <joelkronqvist@proton.me>2023-06-21 14:18:27 +0300
commitc6eb85c138c267db08103de28a3a7c6dffee6c4f (patch)
tree5c55ba312926d61a13b04b32c9b801120b92fe78
parent529477dc21ec03842ac55a2719b0875133d2aa43 (diff)
downloadLYLLRuoka-c6eb85c138c267db08103de28a3a7c6dffee6c4f.tar.gz
LYLLRuoka-c6eb85c138c267db08103de28a3a7c6dffee6c4f.zip
Rescued WIP Shift, class and exception updation
-rw-r--r--Cont/custom-message/index.css3
-rw-r--r--Cont/custom-message/index.html26
-rw-r--r--Cont/index.css9
-rw-r--r--Cont/index.html2
-rw-r--r--Cont/updation/index.html41
-rw-r--r--parseClasses.js61
-rw-r--r--parseExceptions.js66
-rw-r--r--server.js75
-rw-r--r--update.js21
9 files changed, 252 insertions, 52 deletions
diff --git a/Cont/custom-message/index.css b/Cont/custom-message/index.css
new file mode 100644
index 0000000..664d7fb
--- /dev/null
+++ b/Cont/custom-message/index.css
@@ -0,0 +1,3 @@
+body {
+ padding-top: 30vh;
+}
diff --git a/Cont/custom-message/index.html b/Cont/custom-message/index.html
new file mode 100644
index 0000000..791513d
--- /dev/null
+++ b/Cont/custom-message/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>\(header\)</h1>
+ <p>\(content\)</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/index.css b/Cont/index.css
index 8df7295..102dac8 100644
--- a/Cont/index.css
+++ b/Cont/index.css
@@ -61,12 +61,16 @@ body {
#input[type="text"], select {
background-color: white;
}
+textarea {
+ width: 80%;
+}
/*** the send-button ***/
#send {
background: blue;
padding: .5em;
margin: .5em;
+ margin-bottom: 0;
font-weight: bold;
position: relative;
@@ -80,6 +84,11 @@ body {
box-shadow: .25em .25em;
}
+#updationlink {
+ color: #aaaaaa;
+ font-size: .8rem;
+}
+
/*** Footer ***/
footer {
position: fixed;
diff --git a/Cont/index.html b/Cont/index.html
index 694e4c9..edd72f5 100644
--- a/Cont/index.html
+++ b/Cont/index.html
@@ -36,6 +36,8 @@
</select>
<br>
<input type="submit" id="send" class="highlight" value="Löydä vuoro">
+ <br>
+ <a href="/updation" id="updationlink">Päivitä ruoat</a>
</form>
<br>
diff --git a/Cont/updation/index.html b/Cont/updation/index.html
new file mode 100644
index 0000000..49167bc
--- /dev/null
+++ b/Cont/updation/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="fi">
+ <head>
+ <meta charset="utf-8">
+ <title>LYLL-ruokailuvuoro</title>
+ <link href="/index.css" rel="stylesheet" type="text/css">
+ <link rel="icon" type="image/x-icon" href="/Images/favicon.ico">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ </head>
+ <body>
+ <header>
+ <h1 class=shadow>Ruokailuvuorojen ja luokkien päivityssivu</h1>
+ </header>
+
+ <br>
+
+ <main>
+ <form method="POST">
+ <p class=shadow>Liitä allaolevaan tekstikenttään ruokailuvuorot (Wilma-viestin teksti):</p>
+ <br>
+ <textarea name="shifts" rows="24" style="text-align: left;"></textarea>
+ <br>
+ <p class="shadow">Kiitos paljon! Kun painat sivun lopusta 'Päivitä'-painiketta, toimii ruokailuvuorohaku (toivon mukaan) jälleen. Jos sinulla on yhtään enemmän aikaa, voit myös suorittaa allaolevan vaiheen. Sen suoritettuasi ruokailuvuoroja voi hakea opettajan ja kurssikoodin lisäksi luokkatilan perusteella.</p>
+ <br>
+ <p class="shadow">Liitä allaolevaan tekstikenttään kurssitarjottimista tämä jakso. Voit avata kurssitarjottimet Excelissä tai Libreoffice Calcissa, valita alueen, jossa on jakson kurssit ja CTRL+C CTRL+V tähän. Toista sama kaikille jakson alueille kaikista vuoden kurssitarjottimista.</p>
+ <br>
+ <textarea name="classes" rows="24" style="text-align: left;"></textarea>
+ <br>
+ <input type="submit" id="send" class="highlight" value="Päivitä">
+ <br>
+ <p>Painikkeen painamisen jälkeen seuraavan sivun latautumisessa kestää, koska serveri käsittelee syötteesi loppuun asti ennen vastaamista, jotta se voi kertoa, onnistuiko päivitys.</p>
+ </form>
+ </main>
+
+ <footer>
+ <a href="https://www.github.com/JoelHMikael/LYLLRuoka">Lähdekoodi</a>
+ <span>|</span>
+ <a href="/devs">Ota yhteyttä</a>
+ </footer>
+ </body>
+</html>
diff --git a/parseClasses.js b/parseClasses.js
index b114f33..fd48768 100644
--- a/parseClasses.js
+++ b/parseClasses.js
@@ -5,46 +5,38 @@ const readline = require("readline");
const stream = require("stream");
const getIndexType = require("./dbparse.js").indexType;
-// What a mess.
-async function parseClassData(path, DB)
+async function parseClassData(classes, DB)
{
const separator = "\t";
- const inStream = fs.createReadStream(path)
- const outStream = new stream();
- const rl = readline.createInterface(inStream, outStream);
-
+ classes = classes.split('\n');
let lineNum = 0;
let courses = [];
- rl.on("line", line =>
- {
+ for(let line of classes) {
let lineList = line.split(separator);
- let type = getIndexType(lineList[0]);
- if (!((type === "class") || (type === "teacher")))
- lineNum = 0;
+ let type = getIndexType(lineList[0]);
+ if (!((type === "class") || (type === "teacher")))
+ lineNum = 0;
- if (lineNum % 3 === 0)
- courses = lineList;
+ if (lineNum % 3 === 0)
+ courses = lineList;
if ((lineNum % 3) === 2)
- {
- // Remove the weird "R":s in the end of the classes
- for(let i = 0; i < lineList.length; i++)
- {
- let _s = lineList[i];
- lineList[i] = _s.substring(0, _s.length - 1);
- }
+ {
+ // Remove the weird "R":s in the end of the classes
+ for(let i = 0; i < lineList.length; i++)
+ {
+ let _s = lineList[i];
+ lineList[i] = _s.substring(0, _s.length - 1);
+ }
addToDBFromLists(DB, courses, lineList,
- index => { return getIndexType(index) === "course"; },
- index => { return getIndexType(index) === "class"; }
- );
- }
+ index => { return getIndexType(index) === "course"; },
+ index => { return getIndexType(index) === "class"; }
+ );
+ }
lineNum++
- });
- rl.on("close", () =>
- {
- return 0;
- });
+ }
+ return 0;
}
function addToDBFromLists(DB, l1, l2, l1cond, l2cond)
@@ -56,13 +48,10 @@ function addToDBFromLists(DB, l1, l2, l1cond, l2cond)
}
}
-async function parseClasses(DB, ...paths)
+async function parseClasses(DB, classes)
{
- let parsed = [];
- await DB.query_raw("DELETE FROM classes");
- for(const path of paths)
- parsed.push(parseClassData(path, DB))
- return await Promise.all(parsed);
+ await DB.query_raw("DELETE FROM classes");
+ return await parseClassData(classes, DB);
}
-exports.classes = parseClasses; \ No newline at end of file
+exports.classes = parseClasses;
diff --git a/parseExceptions.js b/parseExceptions.js
new file mode 100644
index 0000000..63cd6d2
--- /dev/null
+++ b/parseExceptions.js
@@ -0,0 +1,66 @@
+
+const assert = require('node:assert').strict;
+
+function parseLine(line) {
+ const [datePart] = line.split(' ', 1);
+ assert.equal(datePart !== undefined, true, `otsikkoa ei annettu rivillä ”${line}”`);
+ const rest = line.substring(datePart.length + 1);
+ let dateStrings = datePart.split('-');
+ if (dateStrings.length === 1)
+ dateStrings.push(dateStrings[0]);
+ assert.equal(dateStrings.length, 2, `päivämääräväli ${datePart} on virheellinen (ks. rivi ${line})`);
+ let d1 = dateStrings[0].split('.');
+ const d2 = dateStrings[1].split('.');
+ assert.equal(d2.length, 3, `päivämäärästä ”${dateStrings[1]}” puuttui päivä, kuukausi tai vuosi tai se on muutoin virheellinen (ks. rivi ”${line}”)`);
+ while (d1.length < 3) {
+ d1.push(d2[d1.length])
+ }
+ for (let i = 0; i < 3; i++) {
+ d1[i] = +d1[i];
+ d2[i] = +d2[i];
+ let opts = ['päivä', 'kuukausi', 'vuosi'];
+ assert.ok(!isNaN(d1[i]), `syötetty ${opts[i]} ei koostunut pelkistä numeroista (ks. rivi ${line})`);
+ assert.ok(!isNaN(d2[i]), `syötetty ${opts[i]} ei koostunut pelkistä numeroista (ks. rivi ${line})`);
+ }
+ const start = new Date(d1[2], d1[1] - 1, d1[0]);
+ const end = new Date(d2[2], d2[1] - 1, d2[0]);
+
+ let [header, message = ''] = rest.split('|', 2);
+ assert.equal(header === undefined, false, 'otsikko täytyy antaa (ks. rivi ${line})');
+ header = header.trimEnd();
+ message = message.trimStart();
+
+ return [
+ start,
+ end,
+ header,
+ message
+ ];
+}
+assert.deepEqual(
+ parseLine('02.06.2024-07.08.2024 Hyvää kesää LYLLin väelle! | Kesäloma 2.6.-7.8.'),
+ [
+ new Date(2024, 5, 2),
+ new Date(2024, 7, 7),
+ 'Hyvää kesää LYLLin väelle!',
+ 'Kesäloma 2.6.-7.8.'
+ ]
+);
+
+async function updateExceptions(exceptions, DB) {
+ await DB.query_raw('DELETE FROM exceptions');
+ let dbOperations = [];
+ for (line of exceptions.split('\n')) {
+ if (line === '' || line[0] === '#')
+ continue
+ const [start, end, header, message] = parseLine(line);
+ dbOperations.push(DB.execute(
+ 'INSERT INTO exceptions VALUE (?, ?, ?, ?)',
+ [start, end, header, message]
+ ));
+ }
+ await Promise.all(dbOperations);
+ return 0;
+}
+
+exports.updateExceptions = updateExceptions;
diff --git a/server.js b/server.js
index ccab1b7..e682622 100644
--- a/server.js
+++ b/server.js
@@ -1,6 +1,5 @@
-//const http = require("http");
const https = require("https");
-const http = require("http");
+const http = require("http");
const url = require("url");
const food = require("./food.js");
const SQL_DBS = require("./database.js");
@@ -16,6 +15,7 @@ async function init()
const build = {
"./Cont/index.html": buildMain,
"./Cont/index.css": buildDefault,
+ "./Cont/updation/index.html": buildDefault,
"./Cont/devs/index.html": buildDevs,
"./Cont/devs/index.css": buildDefault,
"./Cont/404/index.css": buildDefault,
@@ -25,9 +25,11 @@ async function init()
"./Cont/Images/favicon.ico": buildImage,
};
const errorPath = "./Cont/404/index.html";
+ const SHIFTPATH = "../Updation/shifts.txt";
+ const CLASSPATH = "../Updation/classes.txt";
- const startDate = new Date();
- let visitorCount = 0;
+ const startDate = new Date();
+ let visitorCount = 0;
// await for needed things in async
let [dbcredentials, httpsKey, httpsCert] = await Promise.all([
@@ -37,7 +39,7 @@ async function init()
]);
- // https options, you need to get a certificate in the file ../Certificate for the server to work
+ // https options, you need to get a certificate in the file ../Certificate for the server to work
const httpsOpts = {
key: httpsKey,
cert: httpsCert
@@ -48,7 +50,7 @@ async function init()
// Update...
// ...shifts and classes
- await updateDB.update(SQLDB, "../Updation/shifts.txt", "../Updation/vanhalops.csv", "../Updation/uusilops.csv");
+ await updateDB.update(SQLDB, SHIFTPATH, CLASSPATH);
// ...foods
dateFuncs.run_at_monday_mornings(() => food.build(SQLDB));
if ((new Date()).getDay() !== 1) // update if it's not monday. if it's monday, it has already been run by the scheduler above.
@@ -56,8 +58,57 @@ async function init()
// server code
async function server(req, res)
{
- // Lightweight analytics. Don't be evil. We just want to know if anyone uses this.
- visitorCount++;
+ visitorCount++;
+
+ // Updation panel
+ if (req.method === "POST") {
+ let data = "";
+ req.on("data", chunk => {
+ data += chunk;
+ if (data.length > 1e6) {
+ res.writeHead(413);
+ res.end("Liian pitkä pyyntö");
+ req.connection.destroy();
+ }
+ });
+ req.on("end", async function updateandrespond() {
+ let q = new URLSearchParams(data);
+ let shifts = "";
+ let classes = "";
+ try {
+ shifts = decodeURIComponent(q.get("shifts")).replaceAll("+", " ");
+ classes = decodeURIComponent(q.get("classes")).replaceAll("+", " ");
+ } catch {
+ console.log("Malformed url, presumably");
+ res.writeHead(400);
+ res.end();
+ }
+ if (shifts === null || classes === null) {
+ res.writeHead(400);
+ res.end("Avainta 'shifts' ja/tai 'classes' ei löytynyt pyynnöstä.");
+ }
+ let shiftfile = await fs.open(SHIFTPATH, "w");
+ await shiftfile.write(shifts);
+ shiftfile.close();
+ if (classes != "") {
+ let classfile = await fs.open(CLASSPATH, "w");
+ await classfile.write(classes)
+ classfile.close();
+ }
+
+ try {
+ await updateDB.update(SQLDB, SHIFTPATH, CLASSPATH);
+ } catch(e) {
+ res.writeHead(400);
+ res.end("Virhe tietojen käsittelyssä. Ota yhteys kehittäjään.");
+ console.log(e);
+ return;
+ }
+ res.writeHead(200);
+ res.end("Kiitos paljon! Näyttää siltä, että tiedot saatiin päivitettyä.");
+ });
+ return;
+ }
// validate inputs
let q = url.parse(req.url, true);
@@ -322,6 +373,14 @@ async function buildDevs(args)
return build_replace(data.toString("utf-8"), {"devs": res});
}
+async function buildCustomMessage(header, message) {
+ let data = await open.file("./Cont/custom-message/index.html");
+ data = data
+ .toString("utf-8")
+ .replace("\\(header\\)", header)
+ .replace("\\(content\\)", message);
+ return data;
+}
async function build404(args)
{
diff --git a/update.js b/update.js
index 9a0c027..be7794c 100644
--- a/update.js
+++ b/update.js
@@ -3,15 +3,20 @@ const parseClasses = require("./parseClasses.js").classes;
const parse = require("./dbparse.js");
// Run this if you want to build the database from text files
-async function buildDB(dbconnection, shiftPath, ...classfiles)
-{
+async function buildDB(dbconnection, shiftPath, classPath, exceptionPath) {
let shiftCont = await openFile(shiftPath);
- shiftCont = shiftCont.toString("utf-8").replaceAll("\r", ""); // \r because of the \r\n newline on windows which may create problems
+ shiftCont = shiftCont.toString("utf-8");
+
+ let exceptions = await openFile(exceptionPath);
+ exceptions = exceptions.toString("utf-8");
+
+ let classes = await openFile(classPath);
+ classes = classes.toString('utf-8');
+
+ await parseClasses(dbconnection, classes);
+ await parse.build(shiftCont, dbconnection);
+ await updateExceptions(exceptions, dbconnection);
- await parseClasses(dbconnection, ...classfiles),
- console.log("Classes updated.");
- await parse.build(shiftCont, dbconnection)
- console.log("Shifts updated.");
return 0;
}
@@ -22,5 +27,5 @@ const openFile = require("./Functions/open.js").file;
const database = require("./database.js");
const dbcredentials = await openFile("../dblogin.txt");
const DB = new database.Database(JSON.parse(dbcredentials));
-await updateDB.update(dbcredentials, "./shifts.txt", "./Kurssitarjottimet/2016Classes.txt", "./Kurssitarjottimet/NewClasses.txt");
+await updateDB.update(DB, "./shifts.txt", "./Kurssitarjottimet/2016Classes.txt", "./Kurssitarjottimet/NewClasses.txt");
*/