diff options
author | Joel Kronqvist <joelkronqvist@proton.me> | 2023-06-21 14:18:27 +0300 |
---|---|---|
committer | Joel Kronqvist <joelkronqvist@proton.me> | 2023-06-21 14:18:27 +0300 |
commit | c6eb85c138c267db08103de28a3a7c6dffee6c4f (patch) | |
tree | 5c55ba312926d61a13b04b32c9b801120b92fe78 | |
parent | 529477dc21ec03842ac55a2719b0875133d2aa43 (diff) | |
download | LYLLRuoka-c6eb85c138c267db08103de28a3a7c6dffee6c4f.tar.gz LYLLRuoka-c6eb85c138c267db08103de28a3a7c6dffee6c4f.zip |
Rescued WIP Shift, class and exception updation
-rw-r--r-- | Cont/custom-message/index.css | 3 | ||||
-rw-r--r-- | Cont/custom-message/index.html | 26 | ||||
-rw-r--r-- | Cont/index.css | 9 | ||||
-rw-r--r-- | Cont/index.html | 2 | ||||
-rw-r--r-- | Cont/updation/index.html | 41 | ||||
-rw-r--r-- | parseClasses.js | 61 | ||||
-rw-r--r-- | parseExceptions.js | 66 | ||||
-rw-r--r-- | server.js | 75 | ||||
-rw-r--r-- | update.js | 21 |
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; @@ -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) { @@ -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"); */ |