'update'
authorBenjamin Auder <benjamin.auder@somewhere>
Thu, 15 Feb 2018 00:34:00 +0000 (01:34 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Thu, 15 Feb 2018 00:34:00 +0000 (01:34 +0100)
19 files changed:
README.md
gulpfile.js
models/course.js
models/evaluation.js [moved from models/assessment.js with 69% similarity]
public/javascripts/components/statements.js
public/javascripts/course.js
public/javascripts/evaluation.js [moved from public/javascripts/assessment.js with 80% similarity]
public/javascripts/grade.js
public/javascripts/monitor.js
public/javascripts/utils/validation.js
routes/all.js
routes/evaluations.js [moved from routes/assessments.js with 60% similarity]
routes/pages.js
setup/database.js
sockets.js
views/course.pug
views/evaluation.pug [moved from views/assessment.pug with 100% similarity]
views/grade.pug
views/monitor.pug

index 0fc0587..3de47b1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -27,8 +27,6 @@ As a teacher, first create an account from the upper-left "login" menu.
 Then create a course using the appropriate button in the middle of the screen.
 Finally, create some exams ("new assessment" button). The syntax for a series of questions is described by the following example:
 
-       > Global (HTML) introduction [optional]
-
        Question 1 text or introduction (optional if there are subquestions)
 
                Text for question 1.1 (index detected from indentation)
index a1286c5..b05610e 100644 (file)
@@ -9,8 +9,6 @@ var nodemonOptions = {
        watch: ['./','config','utils','routes','models','entities']
 };
 
-// TODO: tasks for uglify / sass / use webpack
-
 gulp.task('server', function () {
        nodemon(nodemonOptions)
        .on('restart', function () {
index 631bab9..cbe2c44 100644 (file)
@@ -1,5 +1,5 @@
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const db = require("../utils/database");
 
 const CourseModel =
@@ -159,8 +159,8 @@ const CourseModel =
                CourseModel.getById(cid, (err,course) => {
                        if (!!err || !course || !course.uid.equals(uid))
                                return cb({errmsg:"Not your course"},{});
-                       // 2) remove all associated assessments
-                       AssessmentModel.removeGroup(cid, (err2,ret) => {
+                       // 2) remove all associated evaluations
+                       EvaluationModel.removeGroup(cid, (err2,ret) => {
                                if (!!err)
                                        return cb(err,{});
                                // 3) remove course (with its students)
similarity index 69%
rename from models/assessment.js
rename to models/evaluation.js
index de3d2d7..89f2560 100644 (file)
@@ -4,7 +4,7 @@ const ObjectId = require("bson-objectid");
 const TokenGen = require("../utils/tokenGenerator");
 const db = require("../utils/database");
 
-const AssessmentModel =
+const EvaluationModel =
 {
        /*
         * Structure:
@@ -24,7 +24,7 @@ const AssessmentModel =
         *     options: array of varchar --> if present, question type == quiz!
         *     fixed: bool, options in fixed order (default: false)
         *     answer: array of integers (for quiz) or html text (for paper); striped in exam mode
-        *     active: boolean, is question in current assessment?
+        *     active: boolean, is question in current evaluation?
         *     points: points for this question (default 1)
         *     param: parameter (if applicable)
         *   papers : array of
@@ -40,17 +40,17 @@ const AssessmentModel =
        //////////////////
        // BASIC FUNCTIONS
 
-       getById: function(aid, callback)
+       getById: function(eid, callback)
        {
-               db.assessments.findOne(
-                       { _id: aid },
+               db.evaluations.findOne(
+                       { _id: eid },
                        callback
                );
        },
 
        getByPath: function(cid, name, callback)
        {
-               db.assessments.findOne(
+               db.evaluations.findOne(
                        {
                                cid: cid,
                                name: name,
@@ -61,7 +61,7 @@ const AssessmentModel =
 
        insert: function(cid, name, callback)
        {
-               db.assessments.insert(
+               db.evaluations.insert(
                        {
                                name: name,
                                cid: cid,
@@ -81,34 +81,34 @@ const AssessmentModel =
 
        getByCourse: function(cid, callback)
        {
-               db.assessments.find(
+               db.evaluations.find(
                        { cid: cid },
                        callback
                );
        },
 
-       // arg: full assessment without _id field
-       replace: function(aid, assessment, cb)
+       // arg: full evaluation without _id field
+       replace: function(eid, evaluation, cb)
        {
                // Should be: (but unsupported by mongojs)
-//             db.assessments.replaceOne(
-//                     { _id: aid },
-//                     assessment,
+//             db.evaluations.replaceOne(
+//                     { _id: eid },
+//                     evaluation,
 //                     cb
 //             );
                // Temporary workaround:
-               db.assessments.update(
-                       { _id: aid },
-                       { $set: assessment },
+               db.evaluations.update(
+                       { _id: eid },
+                       { $set: evaluation },
                        cb
                );
        },
 
-       getQuestions: function(aid, callback)
+       getQuestions: function(eid, callback)
        {
-               db.assessments.findOne(
+               db.evaluations.findOne(
                        {
-                               _id: aid,
+                               _id: eid,
                                display: "all",
                        },
                        { questions: 1},
@@ -118,11 +118,11 @@ const AssessmentModel =
                );
        },
 
-       getQuestion: function(aid, index, callback)
+       getQuestion: function(eid, index, callback)
        {
-               db.assessments.findOne(
+               db.evaluations.findOne(
                        {
-                               _id: aid,
+                               _id: eid,
                                display: "one",
                        },
                        { questions: 1},
@@ -137,11 +137,11 @@ const AssessmentModel =
                );
        },
 
-       getPaperByNumber: function(aid, number, callback)
+       getPaperByNumber: function(eid, number, callback)
        {
-               db.assessments.findOne(
+               db.evaluations.findOne(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                        },
                        (err,a) => {
@@ -159,11 +159,11 @@ const AssessmentModel =
        // NOTE: no callbacks for 2 next functions, failures are not so important
        // (because monitored: teachers can see what's going on)
 
-       addDisco: function(aid, number, deltaTime)
+       addDisco: function(eid, number, deltaTime)
        {
-               db.assessments.update(
+               db.evaluations.update(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                        },
                        { $inc: {
@@ -174,21 +174,21 @@ const AssessmentModel =
                );
        },
 
-       setDiscoTime: function(aid, number)
+       setDiscoTime: function(eid, number)
        {
-               db.assessments.update(
+               db.evaluations.update(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                        },
                        { $set: { "papers.$.discoTime": Date.now() } }
                );
        },
 
-       getDiscoTime: function(aid, number, cb)
+       getDiscoTime: function(eid, number, cb)
        {
-               db.assessments.findOne(
-                       { _id: aid },
+               db.evaluations.findOne(
+                       { _id: eid },
                        (err,a) => {
                                if (!!err)
                                        return cb(err, null);
@@ -198,11 +198,11 @@ const AssessmentModel =
                );
        },
 
-       hasInput: function(aid, number, password, idx, cb)
+       hasInput: function(eid, number, password, idx, cb)
        {
-               db.assessments.findOne(
+               db.evaluations.findOne(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                                "papers.password": password,
                        },
@@ -221,11 +221,11 @@ const AssessmentModel =
        },
 
        // https://stackoverflow.com/questions/27874469/mongodb-push-in-nested-array
-       setInput: function(aid, number, password, input, callback) //input: index + arrayOfInt (or txt)
+       setInput: function(eid, number, password, input, callback) //input: index + arrayOfInt (or txt)
        {
-               db.assessments.update(
+               db.evaluations.update(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                                "papers.password": password,
                        },
@@ -234,11 +234,11 @@ const AssessmentModel =
                );
        },
 
-       endAssessment: function(aid, number, password, callback)
+       endEvaluation: function(eid, number, password, callback)
        {
-               db.assessments.update(
+               db.evaluations.update(
                        {
-                               _id: aid,
+                               _id: eid,
                                "papers.number": number,
                                "papers.password": password,
                        },
@@ -250,17 +250,17 @@ const AssessmentModel =
                );
        },
 
-       remove: function(aid, cb)
+       remove: function(eid, cb)
        {
-               db.assessments.remove(
-                       { _id: aid },
+               db.evaluations.remove(
+                       { _id: eid },
                        cb
                );
        },
 
        removeGroup: function(cid, cb)
        {
-               db.assessments.remove(
+               db.evaluations.remove(
                        { cid: cid },
                        cb
                );
@@ -277,24 +277,24 @@ const AssessmentModel =
                        CourseModel.getByPath(user._id, code, (err2,course) => {
                                if (!!err2 || !course)
                                        return cb(err2 || {errmsg: "Course not found"});
-                               AssessmentModel.getByPath(course._id, name, (err3,assessment) => {
-                                       if (!!err3 || !assessment)
-                                               return cb(err3 || {errmsg: "Assessment not found"});
-                                       cb(null,assessment);
+                               EvaluationModel.getByPath(course._id, name, (err3,evaluation) => {
+                                       if (!!err3 || !evaluation)
+                                               return cb(err3 || {errmsg: "Evaluation not found"});
+                                       cb(null,evaluation);
                                });
                        });
                });
        },
 
-       checkPassword: function(aid, number, password, cb)
+       checkPassword: function(eid, number, password, cb)
        {
-               AssessmentModel.getById(aid, (err,assessment) => {
-                       if (!!err || !assessment)
-                               return cb(err, assessment);
-                       const paperIdx = assessment.papers.findIndex( item => { return item.number == number; });
+               EvaluationModel.getById(eid, (err,evaluation) => {
+                       if (!!err || !evaluation)
+                               return cb(err, evaluation);
+                       const paperIdx = evaluation.papers.findIndex( item => { return item.number == number; });
                        if (paperIdx === -1)
                                return cb({errmsg: "Paper not found"}, false);
-                       cb(null, assessment.papers[paperIdx].password == password);
+                       cb(null, evaluation.papers[paperIdx].password == password);
                });
        },
 
@@ -306,35 +306,35 @@ const AssessmentModel =
                                return cb({errmsg: "Course retrieval failure"});
                        if (!course.uid.equals(uid))
                                return cb({errmsg:"Not your course"},undefined);
-                       // 2) Insert new blank assessment
-                       AssessmentModel.insert(cid, name, cb);
+                       // 2) Insert new blank evaluation
+                       EvaluationModel.insert(cid, name, cb);
                });
        },
 
-       update: function(uid, assessment, cb)
+       update: function(uid, evaluation, cb)
        {
-               const aid = ObjectId(assessment._id);
-               // 1) Check that assessment is owned by user of ID uid
-               AssessmentModel.getById(aid, (err,assessmentOld) => {
-                       if (!!err || !assessmentOld)
-                               return cb({errmsg: "Assessment retrieval failure"});
-                       CourseModel.getById(ObjectId(assessmentOld.cid), (err2,course) => {
+               const eid = ObjectId(evaluation._id);
+               // 1) Check that evaluation is owned by user of ID uid
+               EvaluationModel.getById(eid, (err,evaluationOld) => {
+                       if (!!err || !evaluationOld)
+                               return cb({errmsg: "Evaluation retrieval failure"});
+                       CourseModel.getById(ObjectId(evaluationOld.cid), (err2,course) => {
                                if (!!err2 || !course)
                                        return cb({errmsg: "Course retrieval failure"});
                                if (!course.uid.equals(uid))
                                        return cb({errmsg:"Not your course"},undefined);
-                               // 2) Replace assessment
-                               delete assessment["_id"];
-                               assessment.cid = ObjectId(assessment.cid);
-                               AssessmentModel.replace(aid, assessment, cb);
+                               // 2) Replace evaluation
+                               delete evaluation["_id"];
+                               evaluation.cid = ObjectId(evaluation.cid);
+                               EvaluationModel.replace(eid, evaluation, cb);
                        });
                });
        },
 
        // Set password in responses collection
-       startSession: function(aid, number, password, cb)
+       startSession: function(eid, number, password, cb)
        {
-               AssessmentModel.getPaperByNumber(aid, number, (err,paper) => {
+               EvaluationModel.getPaperByNumber(eid, number, (err,paper) => {
                        if (!!err)
                                return cb(err,null);
                        if (!paper && !!password)
@@ -346,14 +346,14 @@ const AssessmentModel =
                                if (paper.password != password)
                                        return cb({errmsg: "Wrong password"});
                        }
-                       AssessmentModel.getQuestions(aid, (err2,questions) => {
+                       EvaluationModel.getQuestions(eid, (err2,questions) => {
                                if (!!err2)
                                        return cb(err2,null);
                                if (!!paper)
                                        return cb(null,{paper:paper});
                                const pwd = TokenGen.generate(12); //arbitrary number, 12 seems enough...
-                               db.assessments.update(
-                                       { _id: aid },
+                               db.evaluations.update(
+                                       { _id: eid },
                                        { $push: { papers: {
                                                number: number,
                                                startTime: Date.now(),
@@ -370,15 +370,15 @@ const AssessmentModel =
                });
        },
 
-       newAnswer: function(aid, number, password, input, cb)
+       newAnswer: function(eid, number, password, input, cb)
        {
                // Check that student hasn't already answered
-               AssessmentModel.hasInput(aid, number, password, input.index, (err,ret) => {
+               EvaluationModel.hasInput(eid, number, password, input.index, (err,ret) => {
                        if (!!err)
                                return cb(err,null);
                        if (!!ret)
                                return cb({errmsg:"Question already answered"},null);
-                       AssessmentModel.setInput(aid, number, password, input, (err2,ret2) => {
+                       EvaluationModel.setInput(eid, number, password, input, (err2,ret2) => {
                                if (!!err2 || !ret2)
                                        return cb(err2,ret2);
                                return cb(null,ret2);
@@ -388,14 +388,14 @@ const AssessmentModel =
 
        // NOTE: no callbacks for next function, failures are not so important
        // (because monitored: teachers can see what's going on)
-       newConnection: function(aid, number)
+       newConnection: function(eid, number)
        {
                //increment discoCount, reset discoTime to NULL, update totalDisco
-               AssessmentModel.getDiscoTime(aid, number, (err,discoTime) => {
+               EvaluationModel.getDiscoTime(eid, number, (err,discoTime) => {
                        if (!!discoTime)
-                               AssessmentModel.addDisco(aid, number, Date.now() - discoTime);
+                               EvaluationModel.addDisco(eid, number, Date.now() - discoTime);
                });
        },
 }
 
-module.exports = AssessmentModel;
+module.exports = EvaluationModel;
index 64057f9..824ce76 100644 (file)
@@ -15,6 +15,8 @@ Imaginary example: (using math.js)
        $$\begin{matrix}7 & x\\y & -3\end{matrix}$$</div>
        * ...
 
++ fixed + question time (syntax ?)
+
 --> input of type text (number, or vector, or matrix e.g. in R syntax)
 --> parameter stored in question.param (TODO)
 
@@ -91,8 +93,8 @@ Vue.component("statements", {
                                                                "input",
                                                                {
                                                                        domProps: {
-                                                                               checked: this.inputs[q.index][idx],
-                                                                               disabled: monitoring,
+                                                                               checked: !!this.inputs && this.inputs[q.index][idx],
+                                                                               disabled: monitoring || this.display == "solution",
                                                                        },
                                                                        attrs: {
                                                                                id: this.inputId(q.index,idx),
@@ -125,7 +127,7 @@ Vue.component("statements", {
                                                                        "class": {
                                                                                option: true,
                                                                                choiceCorrect: this.display == "solution" && q.answer.includes(idx),
-                                                                               choiceWrong: this.display == "solution" && this.inputs[q.index][idx] && !q.answer.includes(idx),
+                                                                               choiceWrong: this.display == "solution" && !!this.inputs && this.inputs[q.index][idx] && !q.answer.includes(idx),
                                                                        },
                                                                },
                                                                option
index ab17fe3..65b6ab7 100644 (file)
@@ -1,7 +1,5 @@
 /*Draft format (compiled to json)
 
-> Some global (HTML) intro
-
 <some html question (or/+ exercise intro)>
 
        <some html subQuestion>
 new Vue({
        el: '#course',
        data: {
-               display: "assessments", //or "students", or "grades" (admin mode)
+               display: "evaluations", //or "students", or "grades" (admin mode)
                course: course,
-               mode: "view", //or "edit" (some assessment)
                monitorPwd: "",
-               newAssessment: { name: "" },
-               assessmentArray: assessmentArray,
-               assessmentIndex: 0, //current edited assessment index
-               assessment: { }, //copy of assessment at editing index in array
-               assessmentText: "", //questions in an assessment, in text format
+               newEvaluation: { name: "" },
+               evaluationArray: evaluationArray,
+               mode: "view", //or "edit" (some evaluation)
+               evaluationIndex: 0, //current edited evaluation index
+               evaluation: { }, //copy of evaluation at editing index in array
+               questionsText: "", //questions in an evaluation, in text format
        },
        mounted: function() {
+               
+               
+               
                $('.modal').each( (i,elem) => {
-                       if (elem.id != "assessmentEdit")
+                       if (elem.id != "evaluationEdit")
                                $(elem).modal();
                });
-               $('ul.tabs').tabs();
-               $('#assessmentEdit').modal({
+               $('ul.tabs').tabs(); //--> migrate to grade.js
+               
+               
+               
+               $('#evaluationEdit').modal({
                        complete: () => {
-                               this.parseAssessment();
-                               Vue.nextTick( () => {
-                                       $("#questionList").find("code[class^=language-]").each( (i,elem) => {
-                                               Prism.highlightElement(elem);
-                                       });
-                                       MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]);
-                               });
+                               this.parseEvaluation();
+                               Vue.nextTick(statementsLibsRefresh);
                        },
                });
        },
@@ -108,29 +107,29 @@ new Vue({
                                },
                        });
                },
-               // ASSESSMENT:
-               addAssessment: function() {
+               // evaluation:
+               addEvaluation: function() {
                        if (!admin)
                                return;
                        // modal, fill code and description
-                       let error = Validator.checkObject(this.newAssessment, "Assessment");
+                       let error = Validator.checkObject(this.newEvaluation, "Evaluation");
                        if (!!error)
                                return alert(error);
                        else
-                               $('#newAssessment').modal('close');
-                       $.ajax("/assessments",
+                               $('#newEvaluation').modal('close');
+                       $.ajax("/evaluations",
                                {
                                        method: "POST",
                                        data: {
-                                               name: this.newAssessment.name,
+                                               name: this.newEvaluation.name,
                                                cid: course._id,
                                        },
                                        dataType: "json",
                                        success: res => {
                                                if (!res.errmsg)
                                                {
-                                                       this.newAssessment["name"] = "";
-                                                       this.assessmentArray.push(res);
+                                                       this.newEvaluation["name"] = "";
+                                                       this.evaluationArray.push(res);
                                                }
                                                else
                                                        alert(res.errmsg);
@@ -142,15 +141,15 @@ new Vue({
                        $("#" + id).modal("open");
                        Materialize.updateTextFields(); //textareas, time field...
                },
-               updateAssessment: function() {
-                       $.ajax("/assessments", {
+               updateEvaluation: function() {
+                       $.ajax("/evaluations", {
                                method: "PUT",
-                               data: {assessment: JSON.stringify(this.assessment)},
+                               data: {evaluation: JSON.stringify(this.evaluation)},
                                dataType: "json",
                                success: res => {
                                        if (!res.errmsg)
                                        {
-                                               this.assessmentArray[this.assessmentIndex] = this.assessment;
+                                               this.evaluationArray[this.evaluationIndex] = this.evaluation;
                                                this.mode = "view";
                                        }
                                        else
@@ -158,20 +157,20 @@ new Vue({
                                },
                        });
                },
-               deleteAssessment: function(assessment) {
+               deleteEvaluation: function(evaluation) {
                        if (!admin)
                                return;
-                       if (confirm("Delete assessment '" + assessment.name + "' ?"))
+                       if (confirm("Delete evaluation '" + evaluation.name + "' ?"))
                        {
-                               $.ajax("/assessments",
+                               $.ajax("/evaluations",
                                        {
                                                method: "DELETE",
-                                               data: { qid: this.assessment._id },
+                                               data: { qid: this.evaluation._id },
                                                dataType: "json",
                                                success: res => {
                                                        if (!res.errmsg)
-                                                               this.assessmentArray.splice( this.assessmentArray.findIndex( item => {
-                                                                       return item._id == assessment._id;
+                                                               this.evaluationArray.splice( this.evaluationArray.findIndex( item => {
+                                                                       return item._id == evaluation._id;
                                                                }), 1 );
                                                        else
                                                                alert(res.errmsg);
@@ -181,16 +180,16 @@ new Vue({
                        }
                },
                toggleState: function(questionIndex) {
-                       // add or remove from activeSet of current assessment
-                       let activeIndex = this.assessment.activeSet.findIndex( item => { return item == questionIndex; });
+                       // add or remove from activeSet of current evaluation
+                       let activeIndex = this.evaluation.activeSet.findIndex( item => { return item == questionIndex; });
                        if (activeIndex >= 0)
-                               this.assessment.activeSet.splice(activeIndex, 1);
+                               this.evaluation.activeSet.splice(activeIndex, 1);
                        else
-                               this.assessment.activeSet.push(questionIndex);
+                               this.evaluation.activeSet.push(questionIndex);
                },
-               setAssessmentText: function() {
+               setEvaluationText: function() {
                        let txt = "";
-                       this.assessment.questions.forEach( q => {
+                       this.evaluation.questions.forEach( q => {
                                txt += q.wording; //already ended by \n
                                q.options.forEach( (o,i) => {
                                        let symbol = q.answer.includes(i) ? "+" : "-";
@@ -198,11 +197,11 @@ new Vue({
                                });
                                txt += "\n"; //separate questions by new line
                        });
-                       this.assessmentText = txt;
+                       this.questionsText = txt;
                },
-               parseAssessment: function() {
+               parseEvaluation: function() {
                        let questions = [ ];
-                       let lines = this.assessmentText.split("\n").map( L => { return L.trim(); })
+                       let lines = this.questionsText.split("\n").map( L => { return L.trim(); })
                        lines.push(""); //easier parsing
                        let emptyQuestion = () => {
                                return {
@@ -239,28 +238,23 @@ new Vue({
                                        }
                                }
                        });
-                       this.assessment.questions = questions;
+                       this.evaluation.questions = questions;
                },
-               actionAssessment: function(index) {
+               actionEvaluation: function(index) {
                        if (admin)
                        {
                                // Edit screen
-                               this.assessmentIndex = index;
-                               this.assessment = $.extend(true, {}, this.assessmentArray[index]);
-                               this.setAssessmentText();
+                               this.evaluationIndex = index;
+                               this.evaluation = $.extend(true, {}, this.evaluationArray[index]);
+                               this.setEvaluationText();
                                this.mode = "edit";
-                               Vue.nextTick( () => {
-                                       $("#questionList").find("code[class^=language-]").each( (i,elem) => {
-                                               Prism.highlightElement(elem);
-                                       });
-                                       MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]);
-                               });
+                               Vue.nextTick(statementsLibsRefresh);
                        }
-                       else //external user: show assessment
-                               this.redirect(this.assessmentArray[index].name);
+                       else //external user: show evaluation
+                               this.redirect(this.evaluationArray[index].name);
                },
-               redirect: function(assessmentName) {
-                       document.location.href = "/" + initials + "/" + course.code + "/" + assessmentName;
+               redirect: function(evaluationName) {
+                       document.location.href = "/" + initials + "/" + course.code + "/" + evaluationName;
                },
                setPassword: function() {
                        let hashPwd = Sha1.Compute(this.monitorPwd);
similarity index 80%
rename from public/javascripts/assessment.js
rename to public/javascripts/evaluation.js
index 2a451e4..565794f 100644 (file)
@@ -1,6 +1,6 @@
 let socket = null; //monitor answers in real time
 
-if (assessment.mode == "secure" && !checkWindowSize())
+if (evaluation.mode == "secure" && !checkWindowSize())
        document.location.href= "/fullscreen";
 
 function checkWindowSize()
@@ -13,9 +13,9 @@ function checkWindowSize()
 }
 
 new Vue({
-       el: "#assessment",
+       el: "#evaluation",
        data: {
-               assessment: assessment,
+               evaluation: evaluation,
                answers: { }, //filled later with answering parameters
                student: { }, //filled later (name, password)
                // Stage 0: unauthenticated (number),
@@ -23,13 +23,13 @@ new Vue({
                //       2: locked: password set, exam started
                //       3: completed
                //       4: show answers
-               remainingTime: assessment.time, //integer or array
-               stage: assessment.mode != "open" ? 0 : 1,
+               remainingTime: evaluation.time, //integer or array
+               stage: evaluation.mode != "open" ? 0 : 1,
                warnMsg: "",
        },
        computed: {
                countdown: function() {
-                       const remainingTime = assessment.display == "one" && _.isArray(assessment.time)
+                       const remainingTime = evaluation.display == "one" && _.isArray(evaluation.time)
                                ? this.remainingTime[this.answers.index]
                                : this.remainingTime;
                        let seconds = remainingTime % 60;
@@ -39,12 +39,12 @@ new Vue({
        },
        mounted: function() {
                $(".modal").modal();
-               if (["exam","open"].includes(assessment.mode))
+               if (["exam","open"].includes(evaluation.mode))
                        return;
                window.addEventListener("blur", () => {
                        if (this.stage != 2)
                                return;
-                       if (assessment.mode == "secure")
+                       if (evaluation.mode == "secure")
                        {
                                this.sendAnswer();
                                document.location.href= "/noblur";
@@ -52,7 +52,7 @@ new Vue({
                        else //"watch" mode
                                socket.emit(message.studentBlur, {number:this.student.number});
                }, false);
-               if (assessment.mode == "watch")
+               if (evaluation.mode == "watch")
                {
                        window.addEventListener("focus", () => {
                                if (this.stage != 2)
@@ -63,7 +63,7 @@ new Vue({
                window.addEventListener("resize", e => {
                        if (this.stage != 2)
                                return;
-                       if (assessment.mode == "secure")
+                       if (evaluation.mode == "secure")
                        {
                                this.sendAnswer();
                                document.location.href = "/fullscreen";
@@ -94,7 +94,7 @@ new Vue({
                                method: "GET",
                                data: {
                                        number: this.student.number,
-                                       cid: assessment.cid,
+                                       cid: evaluation.cid,
                                },
                                dataType: "json",
                                success: s => {
@@ -111,7 +111,7 @@ new Vue({
                        this.stage = 0;
                },
                // stage 1 --> 2 (get all questions, set password)
-               startAssessment: function() {
+               startEvaluation: function() {
                        let initializeStage2 = paper => {
                                $("#leftButton, #rightButton").hide();
                                // Initialize structured answer(s) based on questions type and nesting (TODO: more general)
@@ -121,21 +121,21 @@ new Vue({
                                
                                
                                if (!!questions)
-                                       assessment.questions = questions;
+                                       evaluation.questions = questions;
                                this.answers.inputs = [ ];
-                               for (let q of assessment.questions)
+                               for (let q of evaluation.questions)
                                        this.answers.inputs.push( _(q.options.length).times( _.constant(false) ) );
                                if (!paper)
                                {
-                                       this.answers.indices = assessment.fixed
-                                               ? _.range(assessment.questions.length)
-                                               : _.shuffle( _.range(assessment.questions.length) );
+                                       this.answers.indices = evaluation.fixed
+                                               ? _.range(evaluation.questions.length)
+                                               : _.shuffle( _.range(evaluation.questions.length) );
                                }
                                else
                                {
                                        // Resuming
                                        let indices = paper.inputs.map( input => { return input.index; });
-                                       let remainingIndices = _.difference( _.range(assessment.questions.length).map(String), indices );
+                                       let remainingIndices = _.difference( _.range(evaluation.questions.length).map(String), indices );
                                        this.answers.indices = indices.concat( _.shuffle(remainingIndices) );
                                }
 
@@ -145,29 +145,29 @@ new Vue({
 
 
 
-                               if (assessment.time > 0)
+                               if (evaluation.time > 0)
                                {
 
 // TODO: distinguish total exam time AND question time
 
                                        const deltaTime = !!paper ? Date.now() - paper.startTime : 0;
-                                       this.remainingTime = assessment.time * 60 - Math.round(deltaTime / 1000);
+                                       this.remainingTime = evaluation.time * 60 - Math.round(deltaTime / 1000);
                                        this.runTimer();
                                }
 
 
                                this.answers.index = !!paper ? paper.inputs.length : 0;
-                               this.answers.displayAll = assessment.display == "all";
+                               this.answers.displayAll = evaluation.display == "all";
                                this.answers.showSolution = false;
                                this.stage = 2;
                        };
-                       if (assessment.mode == "open")
+                       if (evaluation.mode == "open")
                                return initializeStage2();
-                       $.ajax("/assessments/start", {
+                       $.ajax("/evaluations/start", {
                                method: "PUT",
                                data: {
                                        number: this.student.number,
-                                       aid: assessment._id
+                                       aid: evaluation._id
                                },
                                dataType: "json",
                                success: s => {
@@ -186,7 +186,7 @@ new Vue({
                                                // action (power failure, computer down, ...)
                                        }
                                        socket = io.connect("/", {
-                                               query: "aid=" + assessment._id + "&number=" + this.student.number + "&password=" + this.student.password
+                                               query: "aid=" + evaluation._id + "&number=" + this.student.number + "&password=" + this.student.password
                                        });
                                        socket.on(message.allAnswers, this.setAnswers);
                                        initializeStage2(s.questions, s.paper);
@@ -197,7 +197,7 @@ new Vue({
 
                // stage 2
                runGlobalTimer: function() {
-                       if (assessment.time <= 0)
+                       if (evaluation.time <= 0)
                                return;
                        let self = this;
                        setInterval( function() {
@@ -205,13 +205,13 @@ new Vue({
                                if (self.remainingTime <= 0)
                                {
                                        if (self.stage == 2)
-                                               self.endAssessment();
+                                               self.endEvaluation();
                                        clearInterval(this);
                                }
                        }, 1000);
                },
                runQuestionTimer: function(idx) {
-                       if (assessment.questions[idx].time <= 0)
+                       if (evaluation.questions[idx].time <= 0)
                                return;
                        let self = this; //TODO: question remaining time
                        setInterval( function() {
@@ -219,7 +219,7 @@ new Vue({
                                if (self.remainingTime <= 0)
                                {
                                        if (self.stage == 2)
-                                               self.endAssessment();
+                                               self.endEvaluation();
                                        clearInterval(this);
                                }
                        }, 1000);
@@ -231,16 +231,16 @@ new Vue({
                sendOneAnswer: function() {
                        const realIndex = this.answers.indices[this.answers.index];
                        let gotoNext = () => {
-                               if (this.answers.index == assessment.questions.length - 1)
-                                       this.endAssessment();
+                               if (this.answers.index == evaluation.questions.length - 1)
+                                       this.endEvaluation();
                                else
                                        this.answers.index++;
                                this.$children[0].$forceUpdate(); //TODO: bad HACK, and shouldn't be required...
                        };
-                       if (assessment.mode == "open")
+                       if (evaluation.mode == "open")
                                return gotoNext(); //only local
                        let answerData = {
-                               aid: assessment._id,
+                               aid: evaluation._id,
                                answer: JSON.stringify({
                                        index: realIndex.toString(),
                                        input: this.answers.inputs[realIndex]
@@ -251,7 +251,7 @@ new Vue({
                                number: this.student.number,
                                password: this.student.password,
                        };
-                       $.ajax("/assessments/answer", {
+                       $.ajax("/evaluations/answer", {
                                method: "PUT",
                                data: answerData,
                                dataType: "json",
@@ -265,27 +265,27 @@ new Vue({
                },
                // TODO: I don't like that + sending should not be definitive in exam mode with display = all
                sendAnswer: function() {
-                       if (assessment.display == "one")
+                       if (evaluation.display == "one")
                                this.sendOneAnswer();
                        else
-                               assessment.questions.forEach(this.sendOneAnswer);
+                               evaluation.questions.forEach(this.sendOneAnswer);
                },
                // stage 2 --> 3 (or 4)
                // from a message by statements component, or time over
-               endAssessment: function() {
+               endEvaluation: function() {
                        // Set endTime, destroy password
                        $("#leftButton, #rightButton").show();
-                       if (assessment.mode == "open")
+                       if (evaluation.mode == "open")
                        {
                                this.stage = 4;
                                this.answers.showSolution = true;
                                this.answers.displayAll = true;
                                return;
                        }
-                       $.ajax("/assessments/end", {
+                       $.ajax("/evaluations/end", {
                                method: "PUT",
                                data: {
-                                       aid: assessment._id,
+                                       aid: evaluation._id,
                                        number: this.student.number,
                                        password: this.student.password,
                                },
@@ -302,7 +302,7 @@ new Vue({
                setAnswers: function(m) {
                        const answers = JSON.parse(m.answers);
                        for (let i=0; i<answers.length; i++)
-                               assessment.questions[i].answer = answers[i];
+                               evaluation.questions[i].answer = answers[i];
                        this.answers.showSolution = true;
                        this.answers.displayAll = true;
                        this.stage = 4;
index 334b2a3..d0f04cf 100644 (file)
@@ -3,7 +3,7 @@
 new Vue({
        el: '#grade',
        data: {
-               assessmentArray: assessmentArray,
+               evaluationArray: evaluationArray,
                settings: {
                        totalPoints: 20,
                        halfPoints: false,
@@ -29,16 +29,16 @@ new Vue({
                                let gradesCount = 0;
                                if (!!this.grades[s.number])
                                {
-                                       Object.keys(this.grades[s.number]).forEach( assessmentName => {
-                                               s[assessmentName] = this.grades[s.number][assessmentName];
-                                               if (_.isNumeric(s[assessmentName]) && !isNaN(s[assessmentName]))
+                                       Object.keys(this.grades[s.number]).forEach( evaluationName => {
+                                               s[evaluationName] = this.grades[s.number][evaluationName];
+                                               if (_.isNumeric(s[evaluationName]) && !isNaN(s[evaluationName]))
                                                {
-                                                       finalGrade += s[assessmentName];
+                                                       finalGrade += s[evaluationName];
                                                        gradesCount++;
                                                }
                                                if (gradesCount >= 1)
                                                        finalGrade /= gradesCount;
-                                               s["final"] = finalGrade; //TODO: forbid "final" as assessment name
+                                               s["final"] = finalGrade; //TODO: forbid "final" as evaluation name
                                        });
                                }
                                data.push(s); //number,name,group,assessName1...assessNameN,final
@@ -65,10 +65,10 @@ new Vue({
                        });
                        return _.range(1,maxGrp+1);
                },
-               grade: function(assessmentIndex, studentNumber) {
-                       if (!this.grades[assessmentIndex] || !this.grades[assessmentIndex][studentNumber])
+               grade: function(evaluationIndex, studentNumber) {
+                       if (!this.grades[evaluationIndex] || !this.grades[evaluationIndex][studentNumber])
                                return ""; //no grade yet
-                       return this.grades[assessmentIndex][studentNumber];
+                       return this.grades[evaluationIndex][studentNumber];
                },
                groupId: function(group, prefix) {
                        return (prefix || "") + "group" + group;
index 29ce858..9b3964b 100644 (file)
@@ -4,7 +4,7 @@ new Vue({
        el: "#monitor",
        data: {
                password: "", //from password field
-               assessment: { }, //obtained after authentication
+               evaluation: { }, //obtained after authentication
                // Stage 0: unauthenticated (password),
                //       1: authenticated (password hash validated), start monitoring
                stage: 0,
@@ -15,7 +15,7 @@ new Vue({
                        index : -1,
                },
                students: [ ], //to know their names
-               display: "assessment", //or student's answers
+               display: "evaluation", //or student's answers
        },
        methods: {
                // TODO: redundant code, next 4 funcs already exist in course.js
@@ -52,11 +52,11 @@ new Vue({
                        {
                                if (!s.present)
                                        continue;
-                               const paperIdx = this.assessment.papers.findIndex( item => { return item.number == s.number; });
+                               const paperIdx = this.evaluation.papers.findIndex( item => { return item.number == s.number; });
                                if (paperIdx === -1)
                                        return false;
-                               const paper = this.assessment.papers[paperIdx];
-                               if (paper.inputs.length < this.assessment.questions.length)
+                               const paper = this.evaluation.papers[paperIdx];
+                               if (paper.inputs.length < this.evaluation.questions.length)
                                        return false;
                        }
                        return true;
@@ -64,16 +64,16 @@ new Vue({
                getColor: function(number, qIdx) {
                        // For the moment, green if correct and red if wrong; grey if unanswered yet
                        // TODO: in-between color for partially right (especially for multi-questions)
-                       const paperIdx = this.assessment.papers.findIndex( item => { return item.number == number; });
+                       const paperIdx = this.evaluation.papers.findIndex( item => { return item.number == number; });
                        if (paperIdx === -1)
                                return "grey"; //student didn't start yet
-                       const inputIdx = this.assessment.papers[paperIdx].inputs.findIndex( item => {
+                       const inputIdx = this.evaluation.papers[paperIdx].inputs.findIndex( item => {
                                const qNum = parseInt(item.index.split(".")[0]); //indexes separated by dots
                                return qIdx == qNum;
                        });
                        if (inputIdx === -1)
                                return "grey";
-                       if (_.isEqual(this.assessment.papers[paperIdx].inputs[inputIdx].input, this.assessment.questions[qIdx].answer))
+                       if (_.isEqual(this.evaluation.papers[paperIdx].inputs[inputIdx].input, this.evaluation.questions[qIdx].answer))
                                return "green";
                        return "red";
                },
@@ -82,7 +82,7 @@ new Vue({
                },
                // stage 0 --> 1
                startMonitoring: function() {
-                       $.ajax("/assessments/monitor", {
+                       $.ajax("/evaluations/monitor", {
                                method: "GET",
                                data: {
                                        password: Sha1.Compute(this.password),
@@ -94,8 +94,8 @@ new Vue({
                                success: s => {
                                        if (!!s.errmsg)
                                                return alert(s.errmsg);
-                                       this.assessment = s.assessment;
-                                       this.answers.inputs = s.assessment.questions.map( q => {
+                                       this.evaluation = s.evaluation;
+                                       this.answers.inputs = s.evaluation.questions.map( q => {
                                                let input = _(q.options.length).times( _.constant(false) );
                                                q.answer.forEach( idx => { input[idx] = true; });
                                                return input;
@@ -104,7 +104,7 @@ new Vue({
                                        this.students.forEach( s => { s.present = true; }); //a priori...
                                        this.stage = 1;
                                        socket = io.connect("/", {
-                                               query: "aid=" + this.assessment._id + "&secret=" + s.secret
+                                               query: "aid=" + this.evaluation._id + "&secret=" + s.secret
                                        });
                                        socket.on(message.studentBlur, m => {
                                                const sIdx = this.students.findIndex( item => { return item.number == m.number; });
@@ -134,20 +134,20 @@ new Vue({
                                                this.students[sIdx].disco = false;
                                        });
                                        socket.on(message.newAnswer, m => {
-                                               let paperIdx = this.assessment.papers.findIndex( item => {
+                                               let paperIdx = this.evaluation.papers.findIndex( item => {
                                                        return item.number == m.number;
                                                });
                                                if (paperIdx === -1)
                                                {
                                                        // First answer
-                                                       paperIdx = this.assessment.papers.length;
-                                                       this.assessment.papers.push({
+                                                       paperIdx = this.evaluation.papers.length;
+                                                       this.evaluation.papers.push({
                                                                number: m.number,
                                                                inputs: [ ], //other fields irrelevant here
                                                        });
                                                }
                                                // TODO: notations not coherent (input / answer... when, which ?)
-                                               this.assessment.papers[paperIdx].inputs.push(JSON.parse(m.answer)); //input+index
+                                               this.evaluation.papers[paperIdx].inputs.push(JSON.parse(m.answer)); //input+index
                                        });
                                },
                        });
@@ -157,7 +157,7 @@ new Vue({
                        // TODO: disable this button until everyone finished (need ability to mark absents)
                        socket.emit(
                                message.allAnswers,
-                               { answers: JSON.stringify(this.assessment.questions.map( q => { return q.answer; })) }
+                               { answers: JSON.stringify(this.evaluation.questions.map( q => { return q.answer; })) }
                        );
                },
        },
index 625fb42..f604f77 100644 (file)
@@ -2,7 +2,7 @@ try { var _ = require("underscore"); } catch (err) {} //for server
 
 let Validator = { };
 
-// Cell in assessment.questions array
+// Cell in evaluation.questions array
 Validator.Question = {
        "index": "section", //"2.2.1", "3.2", "1" ...etc
        "wording": "string",
@@ -32,7 +32,7 @@ Validator.Paper = {
        "password": "password",
 };
 
-Validator.Assessment = {
+Validator.Evaluation = {
        "_id": "bson",
        "cid": "bson",
        "name": "code",
index 1c0d052..4ca00ea 100644 (file)
@@ -3,7 +3,7 @@ var router = require("express").Router();
 // AJAX requests:
 router.use("/", require("./users"));
 router.use("/", require("./courses"));
-router.use("/", require("./assessments"));
+router.use("/", require("./evaluations"));
 
 // Pages:
 router.use("/", require("./pages"));
similarity index 60%
rename from routes/assessments.js
rename to routes/evaluations.js
index 03e483e..18f57f7 100644 (file)
@@ -1,7 +1,7 @@
 let router = require("express").Router();
 const access = require("../utils/access");
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const CourseModel = require("../models/course");
 const params = require("../config/parameters");
 const validator = require("../public/javascripts/utils/validation");
@@ -17,47 +17,47 @@ const sanitizeOpts = {
        },
 };
 
-router.post("/assessments", access.ajax, access.logged, (req,res) => {
+router.post("/evaluations", access.ajax, access.logged, (req,res) => {
        const name = req.body["name"];
        const cid = req.body["cid"];
-       let error = validator({cid:cid, name:name}, "Assessment");
+       let error = validator({cid:cid, name:name}, "Evaluation");
        if (error.length > 0)
                return res.json({errmsg:error});
-       AssessmentModel.add(req.user._id, ObjectId(cid), name, (err,assessment) => {
-               access.checkRequest(res, err, assessment, "Assessment addition failed", () => {
-                       res.json(assessment);
+       EvaluationModel.add(req.user._id, ObjectId(cid), name, (err,evaluation) => {
+               access.checkRequest(res, err, evaluation, "Evaluation addition failed", () => {
+                       res.json(evaluation);
                });
        });
 });
 
-router.put("/assessments", access.ajax, access.logged, (req,res) => {
-       const assessment = JSON.parse(req.body["assessment"]);
-       let error = validator(assessment, "Assessment");
+router.put("/evaluations", access.ajax, access.logged, (req,res) => {
+       const evaluation = JSON.parse(req.body["evaluation"]);
+       let error = validator(evaluation, "Evaluation");
        if (error.length > 0)
                return res.json({errmsg:error});
-       assessment.introduction = sanitizeHtml(assessment.introduction, sanitizeOpts);
-       assessment.questions.forEach( q => {
+       evaluation.introduction = sanitizeHtml(evaluation.introduction, sanitizeOpts);
+       evaluation.questions.forEach( q => {
                q.wording = sanitizeHtml(q.wording, sanitizeOpts);
                //q.answer = sanitizeHtml(q.answer); //if text (TODO: it's an array in this case?!)
                for (let i=0; i<q.options.length; i++) //if QCM
                        q.options[i] = sanitizeHtml(q.options[i], sanitizeOpts);
        });
-       AssessmentModel.update(req.user._id, assessment, (err,ret) => {
-               access.checkRequest(res, err, ret, "Assessment update failed", () => {
+       EvaluationModel.update(req.user._id, evaluation, (err,ret) => {
+               access.checkRequest(res, err, ret, "Evaluation update failed", () => {
                        res.json({});
                });
        });
 });
 
 // Generate and set student password, return it
-router.put("/assessments/start", access.ajax, (req,res) => {
+router.put("/evaluations/start", access.ajax, (req,res) => {
        let number = req.body["number"];
-       let aid = req.body["aid"];
+       let eid = req.body["eid"];
        let password = req.cookies["password"]; //potentially from cookies, resuming
-       let error = validator({ _id:aid, papers:[{number:number,password:password || "samplePwd"}] }, "Assessment");
+       let error = validator({ _id:eid, papers:[{number:number,password:password || "samplePwd"}] }, "Evaluation");
        if (error.length > 0)
                return res.json({errmsg:error});
-       AssessmentModel.startSession(ObjectId(aid), number, password, (err,ret) => {
+       EvaluationModel.startSession(ObjectId(eid), number, password, (err,ret) => {
                access.checkRequest(res,err,ret,"Failed session initialization", () => {
                        if (!password)
                        {
@@ -72,7 +72,7 @@ router.put("/assessments/start", access.ajax, (req,res) => {
        });
 });
 
-router.get("/assessments/monitor", access.ajax, (req,res) => {
+router.get("/evaluations/monitor", access.ajax, (req,res) => {
        const password = req.query["password"];
        const examName = req.query["aname"];
        const courseCode = req.query["ccode"];
@@ -82,11 +82,11 @@ router.get("/assessments/monitor", access.ajax, (req,res) => {
                access.checkRequest(res,err,course,"Course not found", () => {
                        if (password != course.password)
                                return res.json({errmsg: "Wrong password"});
-                       AssessmentModel.getByRefs(initials, courseCode, examName, (err2,assessment) => {
-                               access.checkRequest(res,err2,assessment,"Assessment not found", () => {
+                       EvaluationModel.getByRefs(initials, courseCode, examName, (err2,evaluation) => {
+                               access.checkRequest(res,err2,evaluation,"Evaluation not found", () => {
                                        res.json({
                                                students: course.students,
-                                               assessment: assessment,
+                                               evaluation: evaluation,
                                                secret: params.secret,
                                        });
                                });
@@ -95,31 +95,31 @@ router.get("/assessments/monitor", access.ajax, (req,res) => {
        });
 });
 
-router.put("/assessments/answer", access.ajax, (req,res) => {
-       let aid = req.body["aid"];
+router.put("/evaluations/answer", access.ajax, (req,res) => {
+       let eid = req.body["eid"];
        let number = req.body["number"];
        let password = req.body["password"];
        let input = JSON.parse(req.body["answer"]);
-       let error = validator({ _id:aid, papers:[{number:number,password:password,inputs:[input]}] }, "Assessment");
+       let error = validator({ _id:eid, papers:[{number:number,password:password,inputs:[input]}] }, "Evaluation");
        if (error.length > 0)
                return res.json({errmsg:error});
-       AssessmentModel.newAnswer(ObjectId(aid), number, password, input, (err,ret) => {
+       EvaluationModel.newAnswer(ObjectId(eid), number, password, input, (err,ret) => {
                access.checkRequest(res,err,ret,"Cannot send answer", () => {
                        res.json({});
                });
        });
 });
 
-router.put("/assessments/end", access.ajax, (req,res) => {
-       let aid = req.body["aid"];
+router.put("/evaluations/end", access.ajax, (req,res) => {
+       let eid = req.body["eid"];
        let number = req.body["number"];
        let password = req.body["password"];
-       let error = validator({ _id:aid, papers:[{number:number,password:password}] }, "Assessment");
+       let error = validator({ _id:eid, papers:[{number:number,password:password}] }, "Evaluation");
        if (error.length > 0)
                return res.json({errmsg:error});
        // Destroy pwd, set endTime
-       AssessmentModel.endAssessment(ObjectId(aid), number, password, (err,ret) => {
-               access.checkRequest(res,err,ret,"Cannot end assessment", () => {
+       EvaluationModel.endEvaluation(ObjectId(eid), number, password, (err,ret) => {
+               access.checkRequest(res,err,ret,"Cannot end evaluation", () => {
                        res.clearCookie('password');
                        res.json({});
                });
index c92f2e7..2acefc0 100644 (file)
@@ -1,12 +1,12 @@
 let router = require("express").Router();
 const access = require("../utils/access");
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const CourseModel = require("../models/course");
 
 // Actual pages (least specific last)
 
-// List initials and count assessments
+// List initials and count evaluations
 router.get("/", (req,res) => {
        UserModel.getAll( (err,userArray) => {
                if (!!err)
@@ -75,7 +75,7 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)", (req,res) => {
        let code = req.params["courseCode"];
        CourseModel.getByRefs(initials, code, (err,course) => {
                access.checkRequest(res, err, course, "Course not found", () => {
-                       AssessmentModel.getByCourse(course._id, (err2,assessmentArray) => {
+                       EvaluationModel.getByCourse(course._id, (err2,evaluationArray) => {
                                if (!!err)
                                        return res.json(err);
                                access.getUser(req, res, (err2,user) => {
@@ -86,7 +86,7 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)", (req,res) => {
                                        res.render("course", {
                                                title: "course " + initials + "/" + code,
                                                course: course,
-                                               assessmentArray: assessmentArray,
+                                               evaluationArray: evaluationArray,
                                                teacher: isTeacher,
                                                initials: initials,
                                        });
@@ -108,17 +108,17 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/grade", (req,res) =>
        });
 });
 
-// Display assessment (exam or open status)
-router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)", (req,res) => {
+// Display evaluation (exam or open status)
+router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:evaluationName([a-z0-9._-]+)", (req,res) => {
        let initials = req.params["initials"];
        let code = req.params["courseCode"];
-       let name = req.params["assessmentName"];
-       AssessmentModel.getByRefs(initials, code, name, (err,assessment) => {
-               access.checkRequest(res, err, assessment, "Assessment not found", () => {
-                       if (!assessment.active)
-                               return res.json({errmsg: "Assessment is idle"});
-                       delete assessment["papers"]; //always remove recorded students answers
-                       if (assessment.mode == "exam")
+       let name = req.params["evaluationName"];
+       EvaluationModel.getByRefs(initials, code, name, (err,evaluation) => {
+               access.checkRequest(res, err, evaluation, "Evaluation not found", () => {
+                       if (!evaluation.active)
+                               return res.json({errmsg: "Evaluation is idle"});
+                       delete evaluation["papers"]; //always remove recorded students answers
+                       if (evaluation.mode == "exam")
                        {
                                if (!!req.headers['user-agent'].match(/(SpecialAgent|HeadlessChrome|PhantomJS)/))
                                {
@@ -126,24 +126,24 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z
                                        return res.json({errmsg: "Headless browser detected"});
                                }
                                // Strip questions if exam mode (stepwise process)
-                               delete assessment["questions"];
+                               delete evaluation["questions"];
                        }
-                       res.render("assessment", {
-                               title: "assessment " + initials + "/" + code + "/" + name,
-                               assessment: assessment,
+                       res.render("evaluation", {
+                               title: "evaluation " + initials + "/" + code + "/" + name,
+                               evaluation: evaluation,
                        });
                });
        });
 });
 
 // Monitor: --> after identification (password), always send secret with requests
-router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)/monitor", (req,res) => {
+router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:evaluationName([a-z0-9._-]+)/monitor", (req,res) => {
        let initials = req.params["initials"];
        let code = req.params["courseCode"];
-       let name = req.params["assessmentName"];
+       let name = req.params["evaluationName"];
        // TODO: if (main) teacher, also send secret, saving one request
        res.render("monitor", {
-               title: "monitor assessment " + code + "/" + name,
+               title: "monitor evaluation " + code + "/" + name,
                initials: initials,
                courseCode: code,
                examName: name,
index b9a392d..2070e71 100644 (file)
@@ -6,8 +6,8 @@
 // courses
 //   unique (code,uid)
 //   index (code,uid)
-// assessments
+// evaluations
 //   unique (cid, name)
 //   index (cid, name)
-// db.assessments.createIndex( { cid: 1, name: 1 } );
+// db.evaluations.createIndex( { cid: 1, name: 1 } );
 // https://docs.mongodb.com/manual/core/index-compound/
index 30beb32..dafe6d9 100644 (file)
@@ -1,6 +1,6 @@
 const message = require("./public/javascripts/utils/socketMessages");
 const params = require("./config/parameters");
-const AssessmentModel = require("./models/assessment");
+const EvaluationModel = require("./models/evaluation");
 const ObjectId = require("bson-objectid");
 
 module.exports = function(io)
@@ -20,10 +20,10 @@ module.exports = function(io)
                {
                        const number = socket.handshake.query.number;
                        const password = socket.handshake.query.password;
-                       AssessmentModel.checkPassword(ObjectId(aid), number, password, (err,ret) => {
+                       EvaluationModel.checkPassword(ObjectId(aid), number, password, (err,ret) => {
                                if (!!err || !ret)
                                        return; //wrong password, or some unexpected error...
-                               AssessmentModel.newConnection(ObjectId(aid), number);
+                               EvaluationModel.newConnection(ObjectId(aid), number);
                                socket.broadcast.to(aid + "_teacher").emit(message.studentConnect, {number: number});
                                socket.join(aid + "_student");
                                socket.on(message.newAnswer, m => { //got answer from student client
@@ -42,7 +42,7 @@ module.exports = function(io)
                                        socket.broadcast.to(aid + "_teacher").emit(message.studentFullscreen, m);
                                });
                                socket.on("disconnect", () => { //notify monitor + server
-                                       AssessmentModel.setDiscoTime(ObjectId(aid), number);
+                                       EvaluationModel.setDiscoTime(ObjectId(aid), number);
                                        socket.broadcast.to(aid + "_teacher").emit(message.studentDisconnect, {number: number});
                                });
                        });
index 34bf462..9d84018 100644 (file)
@@ -7,74 +7,19 @@ block append stylesheets
 block content
        .container#course
                if teacher
-                       #newAssessment.modal
+                       #newevaluation.modal
                                .modal-content
-                                       form(@submit.prevent="addAssessment")
+                                       form(@submit.prevent="addevaluation")
                                                .input-field
-                                                       input#assessmentName(type="text" v-model="newAssessment.name" required)
-                                                       label(for="assessmentName") Name
+                                                       input#evaluationName(type="text" v-model="newEvaluation.name" required)
+                                                       label(for="evaluationName") Name
                                .modal-footer
                                        .center-align
-                                               a.waves-effect.waves-light.btn(href="#!" @click="addAssessment()")
+                                               a.waves-effect.waves-light.btn(href="#!" @click="addEvaluation()")
                                                        span Submit
                                                        i.material-icons.right send
-               .row(v-show="mode=='view'")
-                       
-                       
-                       
-                       
-                       
-                       
-                       
-                       
-                       #assessmentEdit
-                               form
-                                       p
-                                               input#active(type="checkbox" v-model="assessment.active")
-                                               label(for="active") Assessment is active
-                                       div
-                                               h4 Questions mode:
-                                               span(title="Exam mode, secured (class only): students cannot lose focus or exit fullscreen")
-                                                       input#secure(name="status" type="radio" value="secure" v-model="assessment.mode")
-                                                       label(for="secure") secure
-                                               span(title="Exam mode, watched (class only): teachers are notified when students lose focus or resize window")
-                                                       input#watch(name="status" type="radio" value="watch" v-model="assessment.mode")
-                                                       label(for="watch") watch
-                                               span(title="Exam mode, unwatched: students can browse the web freely")
-                                                       input#exam(name="status" type="radio" value="exam" v-model="assessment.mode")
-                                                       label(for="exam") exam
-                                               span(title="Questions list open to the world (useful mode after an exam, or for a 'questions bank'")
-                                                       input#open(name="status" type="radio" value="open" v-model="assessment.mode")
-                                                       label(for="open") open
-                                       p
-                                               input#fixed(type="checkbox" v-model="assessment.fixed")
-                                               label(for="fixed") Fixed questions order
-                                       div
-                                               h4 Display type:
-                                               span(title="Show only one question at a time (with potential sub-questions)")
-                                                       input#displayOne(name="display" type="radio" value="one" v-model="assessment.display")
-                                                       label(for="displayOne") one
-                                               span(title="Always show all questions (with an optional navigator)")
-                                                       input#displayAll(name="display" type="radio" value="all" v-model="assessment.display")
-                                                       label(for="displayAll") all
-                                       .input-field
-                                               input#time(type="number" v-model.number="assessment.time")
-                                               label(for="time") Time (minutes)
-                                       .input-field
-                                               textarea#introduction.materialize-textarea(v-model="assessment.introduction")
-                                               label(for="introduction") Introduction
-                                       .input-field
-                                               textarea#assessmentEdition.materialize-textarea(v-model="assessmentText")
-                                               label(for="assessmentEdition") Assessment in text format
-                       
-                       
-                       
-                       
-                       
-                       
-                       
-                       .col.s12.m10.offset-m1
-                               if teacher
+                       .row
+                               .col.s12.m10.offset-m1
                                        h4.title(@click="toggleDisplay('students')") Students
                                        .card(v-show="display=='students'")
                                                .center-align
@@ -91,11 +36,13 @@ block content
                                                                        td {{ student.number }}
                                                                        td {{ student.name }}
                                                                        td {{ student.group }}
-                               h4.title(@click="toggleDisplay('assessments')") Assessments
-                               .card(v-show="display=='assessments'")
+               .row
+                       .col.s12.m10.offset-m1
+                               h4.title(@click="toggleDisplay('evaluations')") evaluations
+                               .card(v-show="display=='evaluations'")
                                        if teacher
                                                .center-align
-                                                       a.on-left.waves-effect.waves-light.btn.modal-trigger(href="#newAssessment") New assessment
+                                                       a.on-left.waves-effect.waves-light.btn.modal-trigger(href="#newevaluation") New evaluation
                                                        input#password(type="password" v-model="monitorPwd" @keyup.enter="setPassword"
                                                                        placeholder="Password" title="Monitoring password")
                                        table
@@ -104,54 +51,74 @@ block content
                                                                th Name
                                                                th Mode
                                                                th #Questions
-                                                               th Time
                                                tbody
-                                                       tr.assessment(v-for="(assessment,i) in assessmentArray" :class="{idle:!assessment.active}"
-                                                                       @click.left="actionAssessment(i)" @contextmenu.prevent="deleteAssessment(assessment)")
-                                                               td {{ assessment.name }}
-                                                               td {{ assessment.mode }}
-                                                               td {{ assessment.questions.reduce( (a,b) => { return b.active ? a+1 : a; }, 0) }}
-                                                               td {{ assessment.time }}
+                                                       tr.evaluation(v-for="(evaluation,i) in evaluationArray" :class="{idle:!evaluation.active}"
+                                                                       @click.left="actionevaluation(i)" @contextmenu.prevent="deleteevaluation(evaluation)")
+                                                               td {{ evaluation.name }}
+                                                               td {{ evaluation.mode }}
+                                                               td {{ evaluation.questions.length }}
                if teacher
-                       .row(v-show="mode=='edit'")
+                       .row
                                .col.s12.m10.offset-m1
-
-
-
-
-                                       // TODO: always edit mode, with a modal preview
-
-
-
-                                       h4 {{ assessment.name }}
-                                       .card
-                                               .center-align
-                                                       button.waves-effect.waves-light.btn.on-left(@click="materialOpenModal('assessmentSettings')") Settings
-                                                       button.waves-effect.waves-light.btn.on-left(@click="materialOpenModal('assessmentEdit')") Content
-                                                       button.waves-effect.waves-light.btn(@click="redirect(assessment.name)") View
-                                               #questionList
-                                                       .introduction(v-html="assessment.introduction")
-                                                       .question(v-for="(question,i) in assessment.questions" :class="{questionInactive:!question.active}")
-                                                               .wording(v-html="question.wording")
-                                                               .option(v-for="(option,j) in question.options" :class="{choiceCorrect:question.answer.includes(j)}" v-html="option")
-                                                               p
-                                                                       input(:id="checkboxFixedId(i)" type="checkbox" v-model="question.fixed")
-                                                                       label.on-left(:for="checkboxFixedId(i)") Fixed
-                                                                       input(:id="checkboxActiveId(i)" type="checkbox" v-model="question.active")
-                                                                       label(:for="checkboxActiveId(i)") Active
-                                                                       input(time default 0 = untimed)
-                                                                       label Time for the question
+                                       h4 {{ evaluation.name }}
+                                       .card(v-show="mode=='view'")
                                                .center-align
-                                                       button.waves-effect.waves-light.btn.on-left(@click="mode='view'") Cancel
-                                                       button.waves-effect.waves-light.btn(@click="updateAssessment") Send
+                                                       button.waves-effect.waves-light.btn.on-left(@click="mode='edit'") Edit
+                                                       button.waves-effect.waves-light.btn(@click="redirect(evaluation.name)") View
+                                               div
+                                                       .introduction(v-html="evaluation.introduction")
+                                                       statements(:questions="evaluation.questions" :display="solution")
+                                       .card(v-show="mode=='edit'")
+                                               form(@submit.prevent)
+                                                       p
+                                                               input#active(type="checkbox" v-model="evaluation.active")
+                                                               label(for="active") evaluation is active
+                                                       div
+                                                               h4 Questions mode:
+                                                               span(title="Exam mode, secured (class only): students cannot lose focus or exit fullscreen")
+                                                                       input#secure(name="status" type="radio" value="secure" v-model="evaluation.mode")
+                                                                       label(for="secure") secure
+                                                               span(title="Exam mode, watched (class only): teachers are notified when students lose focus or resize window")
+                                                                       input#watch(name="status" type="radio" value="watch" v-model="evaluation.mode")
+                                                                       label(for="watch") watch
+                                                               span(title="Exam mode, unwatched: students can browse the web freely")
+                                                                       input#exam(name="status" type="radio" value="exam" v-model="evaluation.mode")
+                                                                       label(for="exam") exam
+                                                               span(title="Questions list open to the world (useful mode after an exam, or for a 'questions bank'")
+                                                                       input#open(name="status" type="radio" value="open" v-model="evaluation.mode")
+                                                                       label(for="open") open
+                                                       p
+                                                               input#fixed(type="checkbox" v-model="evaluation.fixed")
+                                                               label(for="fixed") Fixed questions order
+                                                       div
+                                                               h4 Display type:
+                                                               span(title="Show only one question at a time (with potential sub-questions)")
+                                                                       input#displayOne(name="display" type="radio" value="one" v-model="evaluation.display")
+                                                                       label(for="displayOne") one
+                                                               span(title="Always show all questions (with an optional navigator)")
+                                                                       input#displayAll(name="display" type="radio" value="all" v-model="evaluation.display")
+                                                                       label(for="displayAll") all
+                                                       .input-field
+                                                               input#time(type="number" v-model.number="evaluation.time")
+                                                               label(for="time") Time (minutes)
+                                                       .input-field
+                                                               textarea#introduction.materialize-textarea(v-model="evaluation.introduction")
+                                                               label(for="introduction") Introduction
+                                                       .input-field
+                                                               textarea#evaluationEdition.materialize-textarea(v-model="evaluationText")
+                                                               label(for="evaluationEdition") evaluation in text format
+                                                       .center-align
+                                                               button.waves-effect.waves-light.btn.on-left(@click="updateEvaluation()") Send
+                                                               button.waves-effect.waves-light.btn(@click="mode='view'") Cancel
 
 block append javascripts
        script(src="//cdnjs.cloudflare.com/ajax/libs/PapaParse/4.3.6/papaparse.min.js")
        script.
-               let assessmentArray = !{JSON.stringify(assessmentArray)};
+               let evaluationArray = !{JSON.stringify(evaluationArray)};
                const course = !{JSON.stringify(course)};
                const initials = "#{initials}";
                const admin = #{teacher};
        script(src="/javascripts/utils/sha1.js")
        script(src="/javascripts/utils/validation.js")
+       script(src="/javascripts/components/statements.js")
        script(src="/javascripts/course.js")
similarity index 100%
rename from views/assessment.pug
rename to views/evaluation.pug
index d38032a..2c5c03e 100644 (file)
@@ -32,11 +32,11 @@ block rightMenu
                                                thead
                                                        tr
                                                                th Number
-                                                               th(v-for="assessment in assessmentArray") {{ assessment.name }}
+                                                               th(v-for="evaluation in evaluationArray") {{ evaluation.name }}
                                                tbody
                                                        tr.grade(v-for="student in studentList(group)")
                                                                td {{ student.number }}
-                                                               td(v-for="(assessment,i) in assessmentArray" @click="togglePresence(student.number,i)")
+                                                               td(v-for="(evaluation,i) in evaluationArray" @click="togglePresence(student.number,i)")
                                                                        | {{ grade(i,student.number) }}
                                .modal-footer
                                        .center-align
@@ -59,17 +59,17 @@ block content
                                                thead
                                                        tr
                                                                th Name
-                                                               th(v-for="(q,i) in assessment.questions") Q.{{ (i+1) }}
+                                                               th(v-for="(q,i) in evaluation.questions") Q.{{ (i+1) }}
                                                tbody
-                                                       tr.assessment(v-for="s in studentList(group)")
+                                                       tr.evaluation(v-for="s in studentList(group)")
                                                                td {{ s.name }}
-                                                               td(v-for="(q,i) in assessment.questions" :style="{background-color: getColor(number,i)}" @click="seeDetails(number,i)") &nbsp;
-                               h4.title(@click="toggleDisplay('assessment')") Assessment
-                               div(v-show="display=='assessment'")
+                                                               td(v-for="(q,i) in evaluation.questions" :style="{background-color: getColor(number,i)}" @click="seeDetails(number,i)") &nbsp;
+                               h4.title(@click="toggleDisplay('evaluation')") evaluation
+                               div(v-show="display=='evaluation'")
                                        .card
-                                               .introduction(v-html="assessment.introduction")
+                                               .introduction(v-html="evaluation.introduction")
                                        .card
-                                               statements(:questions="assessment.questions" :answers:"answers")
+                                               statements(:questions="evaluation.questions" :answers:"answers")
 
 
 
index 671b136..c904f00 100644 (file)
@@ -29,17 +29,17 @@ block content
                                                        thead
                                                                tr
                                                                        th Name
-                                                                       th(v-for="(q,i) in assessment.questions") Q.{{ (i+1) }}
+                                                                       th(v-for="(q,i) in evaluation.questions") Q.{{ (i+1) }}
                                                        tbody
-                                                               tr.assessment(v-for="s in studentList(group)" :class="{absent:!s.present}")
+                                                               tr.evaluation(v-for="s in studentList(group)" :class="{absent:!s.present}")
                                                                        td(:class="{blur:!!s.blur,resize:!!s.resize,disconnect:!!s.disco}" @click="togglePresence(s)") {{ s.name }}
-                                                                       td(v-for="(q,i) in assessment.questions" :style="{backgroundColor: getColor(s.number,i)}" @click="seeDetails(s.number,i)") &nbsp;
-                                       h4.title(@click="toggleDisplay('assessment')") Assessment
-                                       div(v-show="display=='assessment'")
+                                                                       td(v-for="(q,i) in evaluation.questions" :style="{backgroundColor: getColor(s.number,i)}" @click="seeDetails(s.number,i)") &nbsp;
+                                       h4.title(@click="toggleDisplay('evaluation')") evaluation
+                                       div(v-show="display=='evaluation'")
                                                .card
-                                                       .introduction(v-html="assessment.introduction")
+                                                       .introduction(v-html="evaluation.introduction")
                                                .card
-                                                       statements(:questions="assessment.questions" :answers="answers")
+                                                       statements(:questions="evaluation.questions" :answers="answers")
 
 block append javascripts
        script.