// Affiché si (hash du) mdp du cours est correctement entré
// Doit reprendre les données en base si refresh (sinon : sockets)
-// Also buttons "start exam", "end exam" for logged in teacher
-
let socket = null; //monitor answers in real time
new Vue({
// Stage 0: unauthenticated (password),
// 1: authenticated (password hash validated), start monitoring
stage: 0,
+ answers: {
+ displayAll: true,
+ showSolution: true, //TODO: allow to hide, to let teachers search too
+ inputs: [ ],
+ index : -1,
+ },
},
methods: {
// stage 0 --> 1
$.ajax("/start/monitoring", {
method: "GET",
data: {
- password: this.,
+ password: this.password,
aname: examName,
cname: courseName,
+ initials: initials,
},
dataType: "json",
success: s => {
if (!!s.errmsg)
return this.warning(s.errmsg);
+ this.assessment = JSON.parse(s.assessment);
this.stage = 1;
- },
- });
- },
- // TODO: 2-level sockets, for prof and monitors
- socket = io.connect("/" + assessment.name, {
- query: "number=" + this.student.number + "&password=" + this.password
+ socket = io.connect("/", {
+ query: "aid=" + this.assessment._id + "&secret=" + s.secret
+ });
+ socket.on(message.newAnswer, m => {
+ let paperIdx = this.assessment.papers.findIndex( item => {
+ return item.number == m.number;
+ });
+ this.assessment.papers[paperIdx].inputs.push(m.input); //answer+index
});
- socket.on(message.allAnswers, this.setAnswers);
- initializeStage2(s.questions, s.paper);
- },
- });
- },
- // stage 2 --> 3 (or 4)
- // from a message by statements component, or time over
- // TODO: also function startAssessment (for main teacher only)
- endAssessment: function() {
- // Set endTime, destroy password
- $("#leftButton, #rightButton").show();
- if (assessment.mode == "open")
- {
- this.stage = 4;
- return;
- }
- $.ajax("/end/assessment", {
- method: "GET",
- data: {
- aid: assessment._id,
- number: this.student.number,
- password: this.student.password,
- },
- dataType: "json",
- success: ret => {
- if (!!ret.errmsg)
- return this.warning(ret.errmsg);
- assessment.conclusion = ret.conclusion;
- this.stage = 3;
- delete this.student["password"]; //unable to send new answers now
- socket.disconnect();
- socket = null;
},
});
},
const AssessmentEntity = require("./entities/assessment");
const ObjectId = require("bson-objectid");
-// TODO: when teacher connect on monitor, io.of("appropriate namespace").on(connect student) { ... }
-// --> 2 sockets on monitoring page: one with ns "/" et one dedicated to the exam, triggered after the first
-// --> The monitoring page should not be closed during exam (otherwise monitors won't receive any more data)
-
-// TOOD need to re-introduce disconnections count + time (showed in monitoring and stored
-
-function examRoom(socket) {
- let students = { };
- const aid = ObjectId(socket.handshake.query.aid);
-
- // Student or monitor stuff
- const isTeacher = !!socket.handshake.query.secret && socket.handshake.query.secret == params.secret;
-
- if (isTeacher)
- {
- socket.on(message.newAnswer, m => { //got answer from student
- socket.emit(message.newAnswer, m);
- });
- socket.on(message.allAnswers, m => { //send feedback to student (answers)
- if (!!students[m.number]) //TODO: namespace here... room quiz
- socket.broadcast.to(students[m.number]).emit(message.allAnswers, m);
- });
- socket.on("disconnect", m => {
- // Reset student array if no more active teacher connections (TODO: condition)
- students = { };
- });
- }
-
- else //student
- {
- const number = socket.handshake.query.number;
- const password = socket.handshake.query.password;
- AssessmentEntity.checkPassword(aid, number, password, (err,ret) => {
- if (!!err || !ret)
- return; //wrong password, or some unexpected error...
- // Prevent socket connection (just ignore) if student already connected
- if (!!students[number])
- return;
- students[number] = {
- sid: socket.id,
- password: password,
- };
- socket.on(message.allAnswers, () => { //got all answers from teacher
- socket.emit(message.allAnswers, m);
+module.exports = function(io)
+{
+ io.of("/").on("connection", socket => {
+ const aid = socket.handshake.query.aid;
+ socket.join(aid);
+ // Student or monitor connexion
+ const isTeacher = !!socket.handshake.query.secret && socket.handshake.query.secret == params.secret;
+ if (isTeacher)
+ {
+ socket.on(message.newAnswer, m => { //got answer from student
+ socket.emit(message.newAnswer, m);
});
- socket.on("disconnect", () => {
- // ..
- //TODO: notify monitor (highlight red), redirect
+ socket.on(message.allAnswers, m => { //send feedback to student (answers)
+ if (!!students[m.number]) //TODO: namespace here... room quiz
+ socket.broadcast.to(aid).emit(message.allAnswers, m);
});
- // NOTE: nothing on disconnect --> teacher disconnect trigger students cleaning
- });
- }
-}
-
-module.exports = function(io) {
-
- // NOTE: if prof connected with 2 tabs and close 1, quizz should not break, thus following counter
- let namespaces = { };
-
- io.of("/").on("connection", socketProf => {
- function closeQuizz(fullPath) {
- namespaces[fullPath].counter--;
- if (namespaces[fullPath].counter == 0)
- {
- // https://stackoverflow.com/questions/26400595/socket-io-how-do-i-remove-a-namespace
- const connectedSockets = Object.keys(namespaces[fullPath].nsp.connected);
- connectedSockets.forEach( sid => {
- namespaces[fullPath].nsp.connected[sid].disconnect();
- });
- namespaces[fullPath].nsp.removeAllListeners();
- delete io.nsps[fullPath];
- }
}
- // Only prof account can connect default namespace
- socketProf.on(message.startQuizz, m => {
- // m contient quizz ID + fullPath (initials+path+name)
- const quizzNamespace = io.of(m.fullPath);
- if (!namespaces[m.fullPath])
- {
- namespaces[m.fullPath] = { nsp:quizzNamespace, counter:1 };
- quizzNamespace.on("connection", quizzRoom); //après ça : prof can connect in quizz too
- socketProf.emit(message.quizzReady);
- socketProf.on(message.endQuizz, m2 => {
- closeQuizz(m.fullPath);
+ else //student
+ {
+ const number = socket.handshake.query.number;
+ const password = socket.handshake.query.password;
+ AssessmentEntity.checkPassword(ObjectId(aid), number, password, (err,ret) => {
+ if (!!err || !ret)
+ return; //wrong password, or some unexpected error...
+ // TODO: Prevent socket connection (just ignore) if student already connected
+// io.of('/').in(aid).clients((error, clients) => {
+// if (error)
+// throw error;
+// if (clients.some( c => { return c. .. == number; }))
+// // Problem: we just have a list of socket IDs (not handshakes)
+// });
+ // TODO: next is conditional to "student not already taking the exam"
+ socket.on(message.allAnswers, () => { //got all answers from teacher
+ socket.emit(message.allAnswers, m);
});
- socketProf.on("disconnect", m2 => {
- closeQuizz(m.fullPath); //TODO: this should delete all students in array
+ socket.on("disconnect", () => {
+ //TODO: notify monitor (grey low opacity background)
+ //Also send to server: discoTime in assessment.papers ...
});
- }
- else
- namespaces[m.fullPath]++;
- });
+ });
+ }
});
}