Prevent student from re-starting the same quiz, implement resuming logic (still buggish)
[qomet.git] / entities / assessment.js
1 const db = require("../utils/database");
2
3 const AssessmentEntity =
4 {
5 /*
6 * Structure:
7 * _id: BSON id
8 * cid: course ID
9 * name: varchar
10 * active: boolean true/false
11 * mode: secure | exam | open (decreasing security)
12 * fixed: bool (questions in fixed order; default: false)
13 * display: "one" or "all" (generally "all" for open questions, but...)
14 * time: 0, //<=0 means "untimed"; otherwise, time in seconds
15 * introduction: "",
16 * conclusion: "https://www.youtube.com/watch?v=6-9AjToJYuw",
17 * coefficient: number, default 1
18 * questions: array of
19 * index: for paper test, like 2.1.a (?!); and quiz: 0, 1, 2, 3...
20 * wording: varchar (HTML)
21 * options: array of varchar --> if present, question type == quiz!
22 * fixed: bool, options in fixed order (default: false)
23 * answer: array of integers (for quiz) or html text (for paper); striped in exam mode
24 * active: boolean, is question in current assessment? --> striped if inactive!
25 * points: points for this question (default 1)
26 * papers : array of
27 * number: student number
28 * inputs: array of indexed arrays of integers (or html text if not quiz)
29 * startTime, endTime
30 * password: random string identifying student for exam session TEMPORARY
31 */
32
33 getById: function(aid, callback)
34 {
35 db.assessments.findOne(
36 { _id: aid },
37 callback
38 );
39 },
40
41 getByPath: function(cid, name, callback)
42 {
43 db.assessments.findOne(
44 {
45 cid: cid,
46 name: name,
47 },
48 callback
49 );
50 },
51
52 insert: function(cid, name, callback)
53 {
54 db.assessments.insert(
55 {
56 name: name,
57 cid: cid,
58 active: false,
59 mode: "exam",
60 fixed: false,
61 display: "one",
62 time: 0,
63 introduction: "",
64 conclusion: "",
65 coefficient: 1,
66 questions: [ ],
67 papers: [ ],
68 },
69 callback
70 );
71 },
72
73 getByCourse: function(cid, callback)
74 {
75 db.assessments.find(
76 { cid: cid },
77 callback
78 );
79 },
80
81 // arg: full assessment without _id field
82 replace: function(aid, assessment, cb)
83 {
84 // Should be: (but unsupported by mongojs)
85 // db.assessments.replaceOne(
86 // { _id: aid },
87 // assessment,
88 // cb
89 // );
90 // Temporary workaround:
91 db.assessments.update(
92 { _id: aid },
93 { $set: assessment },
94 cb
95 );
96 },
97
98 getQuestions: function(aid, callback)
99 {
100 db.assessments.findOne(
101 { _id: aid },
102 { questions: 1},
103 (err,res) => {
104 callback(err, !!res ? res.questions : null);
105 }
106 );
107 },
108
109 getPaperByNumber: function(aid, number, callback)
110 {
111 db.assessments.findOne(
112 {
113 _id: aid,
114 "papers.number": number,
115 },
116 (err,a) => {
117 if (!!err || !a)
118 return callback(err,a);
119 for (let p of a.papers)
120 {
121 if (p.number == number)
122 return callback(null,p); //reached for sure
123 }
124 }
125 );
126 },
127
128 startSession: function(aid, number, password, callback)
129 {
130 // TODO: security, do not re-do tasks if already done
131 db.assessments.update(
132 { _id: aid },
133 { $push: { papers: {
134 number: number,
135 startTime: Date.now(),
136 endTime: undefined,
137 password: password,
138 inputs: [ ], //TODO: this is stage 1, stack indexed answers.
139 // then build JSON tree for easier access / correct
140 }}},
141 callback
142 );
143 },
144
145
146 hasInput: function(aid, number, password, idx, cb)
147 {
148 db.assessments.findOne(
149 {
150 _id: aid,
151 "papers.number": number,
152 "papers.password": password,
153 },
154 (err,a) => {
155 if (!!err || !a)
156 return cb(err,a);
157 for (let p of a.papers)
158 {
159 for (let i of p.inputs)
160 {
161 if (i.index == idx)
162 return cb(null,true);
163 }
164 }
165 cb(null,false);
166 }
167 );
168 },
169
170 // https://stackoverflow.com/questions/27874469/mongodb-push-in-nested-array
171 setInput: function(aid, number, password, input, callback) //input: index + arrayOfInt (or txt)
172 {
173 db.assessments.update(
174 {
175 _id: aid,
176 "papers.number": number,
177 "papers.password": password,
178 },
179 { $push: { "papers.$.inputs": input } },
180 callback
181 );
182 },
183
184 endAssessment: function(aid, number, password, callback)
185 {
186 db.assessments.update(
187 {
188 _id: aid,
189 "papers.number": number,
190 "papers.password": password,
191 },
192 { $set: {
193 "papers.$.endTime": Date.now(),
194 "papers.$.password": "",
195 } },
196 callback
197 );
198 },
199
200 getConclusion: function(aid, callback)
201 {
202 db.assessments.findOne(
203 { _id: aid },
204 { conclusion: 1},
205 (err,res) => {
206 callback(err, !!res ? res.conclusion : null);
207 }
208 );
209 },
210
211 remove: function(aid, cb)
212 {
213 db.assessments.remove(
214 { _id: aid },
215 cb
216 );
217 },
218
219 removeGroup: function(cid, cb)
220 {
221 db.assessments.remove(
222 { cid: cid },
223 cb
224 );
225 },
226 }
227
228 module.exports = AssessmentEntity;