From 0e643f59c043837ba018f4f5444a42c9165f80b9 Mon Sep 17 00:00:00 2001
From: MrFry
Date: Sun, 15 Mar 2020 13:38:16 +0100
Subject: [PATCH] Added api module
---
modules/api/api.js | 316 ++++++++++++++++++++++++++++++++++++++
modules/api/views/man.ejs | 172 +++++++++++++++++++++
2 files changed, 488 insertions(+)
create mode 100644 modules/api/api.js
create mode 100755 modules/api/views/man.ejs
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 - Ez szuper fontos, elsőnek olvasd el
+
+ -
+ Eddigi teszt kérdések - Itt elérhető az eddigi összes ismert teszt
+ kérdés-válaszai
+
+ -
+ Gyakran előforduló kérdések - Ha itt nincs kérdésed, akkor itt tedd fel!
+
+ -
+ Adat egyszerűsítés - Ha túl sok egyforma kérdésed van ;)
+
+ -
+ Other stuff
+
+
+
+ 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.
+
+ |
+
+
+ |
+
+
+ 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
+
+
+
+ -
+ 1. Olyan helyeken fut le a script, ahol nem kellene, vagy zavar
+ Tampermonkey bővitmény ikon -> click -> scriptet kapcsold ki. Csak ne felejtsd
+ visszakapcsolni ;) Meg passzív módot is bekapcsolhatod a menü gomb alatt.
+
+
+ -
+ 2. Túl nagy a kérdést és a választ megjelenítő ablak, nem tudok a válaszra kattintani
+ Zommolj ki egy kicsit, vagy kapcsold ki addig a scriptet. Továbbá középső
+ egérgombra kattintva rá el bírod tüntetni az ablakot, amíg újra nem töltöd az oldalt,
+ vagy másikra ugrasz.
+
+
+ -
+ 4. Mi ez a ... ?
+
+
+
+ -
+ 5.
+
+
+
+
+ -
+ Egyéb:
+ észrevétel
+
+
+
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
+
+
+
+
+