diff --git a/modules/api/api.js b/modules/api/api.js new file mode 100644 index 0000000..84586d5 --- /dev/null +++ b/modules/api/api.js @@ -0,0 +1,316 @@ +/* ---------------------------------------------------------------------------- + + Question Server + GitLab: + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ------------------------------------------------------------------------- */ + +let url = '' + +const express = require('express') +const bodyParser = require('body-parser') +const busboy = require('connect-busboy') +const fs = require('fs') +const app = express() +// const http = require('http') +// const https = require('https') + +const logger = require('../../utils/logger.js') +const utils = require('../../utils/utils.js') +const actions = require('../../utils/actions.js') + +const recivedFiles = 'public/recivedfiles' +const uloadFiles = 'public/f' +const dataFile = 'public/data.json' +const msgFile = 'stats/msgs' +const motdFile = 'public/motd' +const versionFile = 'public/version' +let donateURL = '' +try { + donateURL = utils.ReadFile('./data/donateURL') +} catch (e) { + logger.Log('Couldnt read donate URL file!', logger.GetColor('red')) +} + +app.set('view engine', 'ejs') +app.set('views', [ + './modules/api/views', + './sharedViews' +]) +app.use(express.static('public')) +app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 + } +})) +app.use(bodyParser.json()) +app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true +})) +app.use(bodyParser.json({ + limit: '5mb' +})) + +var data = actions.LoadJSON(dataFile) +var version = '' +var motd = '' + +function LoadVersion () { + version = utils.ReadFile(versionFile) +} + +function LoadMOTD () { + motd = utils.ReadFile(motdFile) +} + +function Load () { + utils.WatchFile(motdFile, (newData) => { + logger.Log(`Motd changed: ${newData.replace(/\/n/g, '')}`) + LoadMOTD() + }) + utils.WatchFile(versionFile, (newData) => { + logger.Log(`Version changed: ${newData.replace(/\/n/g, '')}`) + LoadVersion() + }) + + LoadVersion() + LoadMOTD() +} + +Load() + +// -------------------------------------------------------------- + +app.get('/', function (req, res) { + res.end('hai') +}) + +app.get('/manual', function (req, res) { + res.render('man') + res.end() + logger.LogReq(req) +}) + +app.post('/postfeedback', function (req, res) { + logger.Log('New feedback message', logger.GetColor('bluebg'), true) + utils.AppendToFile('\n\n' + logger.GetDateString() + ': ' + req.body.message_field, msgFile) + res.redirect('back') + res.end() +}) + +app.get('/lred', function (req, res) { + res.redirect('/legacy') // TODO: redirect to react legacy + res.end() + logger.LogReq(req) +}) + +app.get('/menuClick', function (req, res) { + res.redirect('/') // TODO: redirect to react / + res.end() + logger.LogReq(req) +}) + +app.get('/install', function (req, res) { + res.redirect(url + '/moodle-test-userscript/stable.user.js?install') + res.end() + logger.LogReq(req) +}) + +app.get('/donate', function (req, res) { + res.redirect(donateURL) + res.end() + logger.LogReq(req) +}) + +app.get('/thanks', function (req, res) { + res.render('thanks', { // TODO: redirect to react thanks + siteurl: url + }) + res.end() + logger.LogReq(req) +}) + +app.get('/classesgit', function (req, res) { + res.redirect('https://gitlab.com/MrFry/question-classes') + res.end() + logger.LogReq(req) +}) + +app.get('/scriptgit', function (req, res) { + res.redirect('https://gitlab.com/MrFry/moodle-test-userscript') + res.end() + logger.LogReq(req) +}) + +app.get('/servergit', function (req, res) { + res.redirect('https://gitlab.com/MrFry/mrfrys-node-server') + res.end() + logger.LogReq(req) +}) + +function UploadFile (req, res, path, next) { + var fstream + req.pipe(req.busboy) + req.busboy.on('file', function (fieldname, file, filename) { + logger.Log('Uploading: ' + filename, logger.GetColor('blue')) + + utils.CreatePath(path, true) + let d = new Date() + let fn = d.getHours() + '' + d.getMinutes() + '' + d.getSeconds() + '_' + filename + + fstream = fs.createWriteStream(path + '/' + fn) + file.pipe(fstream) + fstream.on('close', function () { + logger.Log('Upload Finished of ' + path + '/' + fn, logger.GetColor('blue')) + next(fn) + }) + fstream.on('error', function (err) { + console.log(err) + res.end('something bad happened :s') + }) + }) +} + +app.route('/fosuploader').post(function (req, res, next) { + UploadFile(req, res, uloadFiles, (fn) => { + res.redirect('/f/' + fn) + }) +}) + +app.route('/badtestsender').post(function (req, res, next) { + UploadFile(req, res, recivedFiles, (fn) => { + res.redirect('back') + }) + logger.LogReq(req) +}) + +// ------------------------------------------------------------------------------------------- +// API + +app.post('/isAdding', function (req, res) { + logger.LogReq(req) + + // automatically saves to dataFile every n write + let result = actions.ProcessIncomingRequest( + req.body.datatoadd, + data, + { motd, version } + ) + + res.json({ + success: result !== -1, + newQuestions: result + }) +}) + +app.get('/ask', function (req, res) { + logger.LogReq(req) + if (Object.keys(req.query).length === 0) { + res.json({ + message: `ask something! ?q=[question]&subj=[subject]&data=[question data]. 'subj' is optimal for faster result`, + result: [], + recievedData: JSON.stringify(req.query), + success: false + }) + } else { + if (req.query.q && req.query.data) { + let subj = req.query.subj || '' + let question = decodeURIComponent(req.query.q) + let recData = {} + try { + recData = JSON.parse(req.query.data) + } catch (e) { + logger.Log(`Unable to parse recieved question data! '${req.query.data}'`, logger.GetColor('redbg')) + } + let r = data.Search(question, subj, recData) + + res.json({ + result: r, + success: true + }) + } else { + res.json({ + message: `Invalid question :(`, + result: [], + recievedData: JSON.stringify(req.query), + success: false + }) + } + } +}) + +function getSimplreRes () { + return { + subjects: data.length, + questions: data.Subjects.reduce((acc, subj) => { + return acc + subj.length + }, 0) + } +} +function getDetailedRes () { + return data.Subjects.map((subj) => { + return { + name: subj.Name, + count: subj.length + } + }) +} + +app.get('/datacount', function (req, res) { + logger.LogReq(req) + if (req.query.detailed === 'all') { + res.json({ + detailed: getDetailedRes(), + simple: getSimplreRes() + }) + } else if (req.query.detailed) { + res.json(getDetailedRes()) + } else { + res.json(getSimplreRes()) + } +}) + +app.get('/infos', function (req, res) { + let result = {} + if (req.query.subjinfo) { + result.subjinfo = getSimplreRes() + } + if (req.query.version) { + result.version = version + } + if (req.query.motd) { + result.motd = motd + } + res.json(result) +}) + +// ------------------------------------------------------------------------------------------- + +app.get('*', function (req, res) { + res.status(404).render('404') +}) + +app.post('*', function (req, res) { + res.status(404).render('404') +}) + +exports.app = app +exports.setup = (x) => { + url = x.url +} + +logger.Log('API module started', logger.GetColor('yellow')) diff --git a/modules/api/views/man.ejs b/modules/api/views/man.ejs new file mode 100755 index 0000000..db1a489 --- /dev/null +++ b/modules/api/views/man.ejs @@ -0,0 +1,172 @@ +
+

Moodle/Elearnig/KMOOC manual

+
+
+ Ez a userscript Moodle/Elearnig/KMOOC tesztek megoldása során segítséget jelenít meg. +
+

+A válasz ablakban jobb felül lévő százalék jelzi, hogy mekkora eséllyel jó a megoldás. Ez +sokszor jó viszonyítás, de semmi sem biztos! Bármikor előfordulhat, hogy nem jó a +megjelenített válasz! Ezért csak saját felelősségedre használd! Sok kikerülhetetlen +hibalehetőség van, amit egyszerű nem lehet scriptben lekezelni (Pl rosszul megadott kérdés +tanár részéről). Kézzel is lehet keresni a elmentett kérdések között. Ezért mindig +legyen egy letöltött verziód a kérdésekről, mert nem 100% hogy mindég elérhető a szerver! +Továbbá ha a moodle oldalán a DOM megváltozik, a script nem fog működni! Ez nem annyira +gyakori, de bármikor megtörténhet! Érdemes nem kikapcsolni a tampermonkey-ban a userscript +frissítést. Ez nem windows update, itt tényleg hibajavítások jönnek ki. Hiba, észrevétel +esetén : Script Feedback (ezt +gyakran még aznap megnézem.) +

+

+Továbbá ez a userscript HTTP requestekket küldhet egy szerver felé, ahova az összes megoldott +tesztjeid kérdéseit és (helyes)válaszait feltölti! Ezzel garantálja, hogy neked, és mindenki +másnak a legfrissebb adatok állnak rendelkezésre. +
+ +

Tartalomjegyzék

+
+
+ +
+

Használat

+
+
+ + + +
+

Először is tölts le egy userscript futtató kiegészítőt a böngésződhöz. Én Tampermonkeyt használok, és ezzel van tesztelve a + userscript is, ezért ez ajánlott. Más is működhet (violentmonkey, etc), de az nem garantált. + Majd a weboldalról egy kattintással elvileg + le tudod tölteni a scriptet, és elvileg kész is. Script majd udvariasan megkéri, hogy + hagy beszélgessen a szerverrel, mert mással nem tud. +

+

Teszt közben még több dolog történhet: +

+
    +
  • Nem jó kérdésre ad választ a script: Ilyenkor az van, hogy nincs meg a + kérdés, vagy több hasonló kérdés/válasz van. Ilyenkor a jobbra/balra gombbal + váltogathatsz azok a kérdés/válasz combók közül, amit talált a script
  • + +
  • Több teszt kérdés van egy oldalon: Fel le gombbal váltogathatsz a kérdések között. + Ilyenkor is működik az előbb említett funkció. Az indexek, amit kiír a bal felső sarokban: + aktuális kérdés száma / aktuális találat száma.
  • + +
  • Nem jelenik meg semmi, vagy nem működik a script: Megesik az ilyesmi. Ha + a webszerver még elérhető akkor ott meg bírod nézni a kérdéseket, és ott lehet + keresgélni Ctrl + F -el Ha az sincs, akkor lehet hogy jól jön ha van egy + lementett kérdés gyűjteményed.
  • +
+ +

Egyéb funkciók: +
    +
  • + Ha esetleg videókat nézel, akkor spaceval lehet play/pausolni, és jobbra/balra + gombbal ugrani a videóban. +
  • +
  • + Ha bármikor nem kell a script, akkor a menü gomb alatt bekapcsolhatod a passzív + módot, ami nem piszkálja a szervert. Vagy kikapcsolhatod magát a scriptet + tampermonkey-ban. Ha bármiért is el akarod tüntetni a következő oldalig az éppen + megjelenő script ablakot, akkor középső egér gombbal kattintva rajta ezt + megteheted. +
  • +
+ +

Ha 2.0 előttről jöttél, és rettenetesen össze vagy zavarodva: +

+ 2.0 előtt a script az egész adatbázist leszedte, beolvasta, és onnan keresett. Ez a + keresés most szerver oldalon van megvalósítva, és a script csak a kérdést, hozzá tartózó + egyéb infót (pl kép nevek) és a tárgy nevét küldi el szervernek. Ezután az visszaküldi a + helyes válaszokat. + +
+ img +
+
+

Eddigi teszt kérdések:

+
+
+Eddigi összes kérdés +Továbbá ez még arra jó, hogy ha valamiért bugos a script, akkor itt tudsz ctrl-f el nézegetni, +vagy ha lemented az összes kérdést, akkor még akkor is biztonságban vagy, ha netán leáll a +szerver, vagy elmegy a neted. Bár úgy nehezen moodlezel, de mind1 + +
+

Gyakran előforduló kérdések

+
+
+ +
Jogosultságok: +
GM_openInTab: help megnyitása új lapon, GM_xmlhttpRequest: online adatbázishoz. GM_info: a +scriptről információ, a verzióváltozás érzékeléséhez. GM_getValue/ GM_setValue: oldal +bezárásakor megmaradó változók kezelése. Előző verzió tárolására, ugyanúgy verzióváltozás +érzékeléséhez, néhány beállítás, illetve hogy melyik tárgyakból keressen kérdéseket. Ezek +függvények, és a sciptben néhol meg vannak hívva, keresd meg. +

Elküldött adatok online módban: Minden teszt végén az összes kérdés, és rá a moodle szerint +helyesnek vélt válaszok. Fogadott adatok: az összes eddig ismert moodle kérdés +
+
+

+Weboldal +

+
+