nodebb-plugin-registration-exam
Version:
Adds an exam page in your forum, so any new user must pass the exam to register.
254 lines (238 loc) • 6.78 kB
JavaScript
;
var Controllers = {};
const async = require('async'),
Questions = require('./questions'),
Invitations = require('./invitations'),
Settings = require('./settings'),
IPChecker = require('./ipchecker'),
{meta} = require('./nodebb');
Controllers.renderAdminPage = function (req, res, next) {
/*
Make sure the route matches your path to template exactly.
If your route was:
myforum.com/some/complex/route/
your template should be:
templates/some/complex/route.tpl
and you would render it like so:
res.render('some/complex/route');
*/
async.waterfall([
initSettings,
(settings, next) => {
let settingsNew = Object.assign({}, settings);
settingsNew.questions = settings.questions.map(ques => {
return {
"c": ques.c.join("\n").replace(/\"/g, """),
"q": ques.q.replace(/\"/g, """),
"a": ques.a.replace(/\"/g, """),
"n": ques.n,
"m": ques.m,
"r": ques.r,
"i": ques.i
};
})
if(settingsNew.questions.length == 0) {
settingsNew.questions.push({
"c": "",
"q": "",
"a": "",
"n": 0,
"m": false,
"r": false,
"i": false
});
}
res.render('admin/plugins/exam', settingsNew);
}
]);
};
// middleware for /exam
Controllers.renderExam = function(req, res, next) {
var settings;
async.waterfall([
initSettings,
(sett, next) => {
settings = sett;
getExamPaper(settings, next);
}
], (err, result) => {
if(err) {
res.render('exam', {"error" : err});
}
else {
res.render('exam', {
"time" : settings.timeLimit,
"timeMinutes" : Math.floor(settings.timeLimit / 60),
"maxScore" : settings.qCount * settings.eachScore,
"needScore" : settings.needScore,
"id" : result.id,
"questions" : result.questions,
});
}
});
};
// middleware for /api/get_paper
Controllers.renderGetPaper = function (req, res, next) {
let settings = {};
async.waterfall([
initSettings,
(result, next) => {
settings = result;
next(null);
},
(next) => {
getExamPaper(settings, next);
}
], (err, result) => {
if(err) {
res.send(Object.assign(err, {
"result" : "error"
}));
}
else {
res.send(Object.assign(result, {
"result" : "success"
}));
}
});
};
// middleware for /api/submit
Controllers.renderSubmit = function(req, res, next) {
async.waterfall([
(next) => {
checkExamResult(req, next);
}
], (err, result) => {
if(err) {
res.send(Object.assign(err, {"error" : true}));
}
else {
res.send(result);
}
});
};
// middleware for /api/cancel_exam (currently unused)
Controllers.renderCancelExam = function(req, res, next) {
console.log(req.body);
var reqBody = req.body;
async.waterfall([
(next) => {
cancelExam(reqBody.id, next);
}
], (err, result) => {
if(err) {
res.send(err);
}
else {
res.send(result);
}
});
};
function initSettings(next) {
Settings.load(next);
};
// for /api/get_paper (currently unused), and before exam_start
function getExamPaper(settings, callback) {
async.waterfall([
Questions.getExamId,
(id, next) => {
next(null, {
"id" : id,
"questions" : Questions.buildExamPaper(settings)
});
}
], callback);
};
// for /api/cancel_exam
function cancelExam(id, callback) {
async.waterfall([
(next) => {
Questions.removeExamId(id, next);
}
], callback);
};
// for /api/submit
function checkExamResult(req, callback) {
var settings = {}, ansObj = req.body;
async.waterfall([
initSettings,
(result, next) => {
settings = result;
next(null);
},
(next) => {
// ip limit
if(settings.ipDayLimit > 0) {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
IPChecker.checkIP(ip, settings.ipDayLimit, next);
}
else {
next(null);
}
},
(next) => {
// read exam starting time from DB
Questions.checkExamTime(ansObj, next);
},
(dbTime, next) => {
// check if time is over
// in case of network lag, add a 60 sec extra time window
if(dbTime > 0 && Date.now() > dbTime + (settings.timeLimit + settings.extraTime) * 1000) {
next({source: 'registration-exam', message: 'error'}, {
"result" : "timeup"
});
}
else {
next(null);
}
},
(next) => {
next(null);
},
(next) => {
// mark the answer
var mark = Questions.markAnswer(ansObj.answers, settings);
// if score is high enough, go get an invitation code
if(mark >= settings.needScore) {
var invitationID = Invitations.randomInvitationString();
Invitations.setDBInvitation(invitationID, settings.inviExpire * 3600000, err => {
next(err, {
"result" : "success",
"invite" : invitationID,
"score" : mark
});
});
}
else {
next(null, {
"result" : "fail",
"score" : mark
});
}
}
], callback);
};
// for register check
function checkRegister(code, callback) {
async.waterfall([
(next) => {
Invitations.checkDBInvitation(code, next);
},
(result, next) => {
if(result) {
next(null, "success");
// remove the invite code in true async
Invitations.removeDBInvitation(code, () => 0);
}
else {
next(null, "failure");
}
}
], callback);
}
Controllers.initSettings = initSettings;
Controllers.getExamPaper = getExamPaper;
Controllers.cancelExam = cancelExam;
Controllers.checkExamResult = checkExamResult;
Controllers.checkRegister = checkRegister;
module.exports = Controllers;