From: Benjamin Auder <benjamin.auder@somewhere>
Date: Sat, 3 Feb 2018 21:27:30 +0000 (+0100)
Subject: Simplify draft monitoring + sockets logic
X-Git-Url: https://git.auder.net/doc/html/app_dev.php/img/mini-custom.min.css?a=commitdiff_plain;h=f6648c37a3c13efbbc3b8c03c6ff725984c98843;p=qomet.git

Simplify draft monitoring + sockets logic
---

diff --git a/public/javascripts/monitor.js b/public/javascripts/monitor.js
index 9f43ce0..5d5f237 100644
--- a/public/javascripts/monitor.js
+++ b/public/javascripts/monitor.js
@@ -6,8 +6,6 @@
 // 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({
@@ -18,6 +16,12 @@ 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
@@ -25,54 +29,26 @@ new Vue({
 			$.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;
 				},
 			});
 		},
diff --git a/sockets.js b/sockets.js
index d743a10..eeda127 100644
--- a/sockets.js
+++ b/sockets.js
@@ -3,97 +3,46 @@ const params = require("./config/parameters");
 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]++;
-		});
+			});
+		}
 	});
 }
diff --git a/views/monitor.pug b/views/monitor.pug
index f4f2e3c..5a64e89 100644
--- a/views/monitor.pug
+++ b/views/monitor.pug
@@ -19,11 +19,11 @@ block content
 							label(for="password") Password
 							input#password(type="password" v-model="password" @keyup.enter="startMonitoring()")
 						button.waves-effect.waves-light.btn(@click="startMonitoring()") Send
-				#stage2(v-show="stage==1")
+				#stage1(v-show="stage==1")
 					.card
 						.introduction(v-html="assessment.introduction")
 					.card
-						statements(:assessment="assessment" :student="student" :stage="stage" :inputs="inputs" @gameover="endAssessment" @warning="warning")
+						statements(:questions="assessment.questions" :answers:"answers")
 					.card
 						.conclusion(v-html="assessment.conclusion")