1 try { var _
= require("underscore"); } catch (err
) {} //for server
5 // Cell in assessment.questions array
7 "index": "section", //"2.2.1", "3.2", "1" ...etc
9 "options": "stringArray", //only for quiz
11 "answer": "string", //both this and next are mutually exclusive
12 "choice": "integerArray",
19 "input": "stringOrIntegerArray",
22 // One student response to an exam
25 // (array of) strings for open questions, arrays of integers for quizzes:
26 "inputs": Validator
.Input
,
27 "startTime": "positiveInteger",
28 "endTime": "positiveInteger",
29 "discoTime": "positiveInteger",
30 "discoCount": "positiveInteger",
31 "totalDisco": "positiveInteger",
32 "password": "password",
35 Validator
.Assessment
= {
39 "mode": "alphanumeric", //"open" or "exam", but alphanumeric is good enough
42 "display": "alphanumeric", //"one" or "all"
44 "introduction": "string",
45 "conclusion": "string",
46 "coefficient": "number",
47 "questions": Validator
.Question
,
48 "papers": Validator
.Paper
,
55 "initials": "unchecked", //not a user input
56 "loginToken": "unchecked",
57 "sessionTokens": "unchecked",
58 "token": "alphanumeric", //exception: for the purpose of user registration
64 "group": "positiveInteger",
71 "description": "string",
73 "students": Validator
.Student
,
76 Object
.assign(Validator
,
78 // Recurse into sub-documents
79 checkObject_aux: function(obj
, model
)
81 for (let key
of Object
.keys(obj
))
84 return "Unknown field";
85 if (model
[key
] == "unchecked") //not a user input (ignored)
87 if (_
.isObject(model
[key
]))
89 // TODO: next loop seems too heavy... (only a concern if big class import?)
90 for (let item
of obj
[key
])
92 let error
= Validator
.checkObject_aux(item
, model
[key
]);
99 let error
= Validator
[ "check_" + model
[key
] ](obj
[key
]);
100 if (error
.length
> 0)
101 return key
+ ": " + error
;
107 // Always check top-level object
108 checkObject: function(obj
, name
)
110 return Validator
.checkObject_aux(obj
, Validator
[name
]);
113 "check_string": function(arg
)
115 return ""; //strings are unchecked, but sanitized
118 "check_section": function(arg
)
120 if (!_
.isString(arg
))
121 return "not a string";
122 if (!/^[0-9.]+$/.test(arg
))
123 return "digits and dot only";
127 "check_stringArray": function(arg
)
129 return !_
.isArray(arg
) ? "not an array" : "";
132 "check_alphanumeric": function(arg
)
134 return arg
.match(/^[\w]{1,32}$/) === null ? "[1,32] alphanumerics" : "";
137 "check_bson": function(arg
)
139 return arg
.match(/^[a-z0-9]{24}$/) === null ? "not a BSON id" : "";
142 "check_name": function(arg
)
144 if (!_
.isString(arg
))
145 return "not a string";
146 if (!/^[a
-zA
-Z
\u00C0-\u024F -]{1,32}$/.test(arg
))
147 return "[1,32] letters + hyphen/space";
151 "check_email": function(arg
)
153 if (!_
.isString(arg
))
154 return "not a string";
156 return "string too long: max. 64 characters";
157 // Regexp used in "type='email'" inputs ( http://emailregex.com/ )
158 if (!/^[a-zA-Z0-9.!#$%&’*+/=?^_
`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(arg))
159 return "X@Y, alphanumerics and . _ - +(X)";
163 "check_code": function(arg)
165 if (!_.isString(arg))
166 return "not a string";
167 if (!/^[\w.-]{1,16}$/.test(arg))
168 return "[1,16] alphanumerics and . _ -";
172 "check_number": function(arg)
174 if (!_.isNumber(arg))
175 arg = parseFloat(arg);
177 return "not a number";
181 "check_integer": function(arg)
183 if (!_.isNumber(arg))
185 if (isNaN(arg) || arg % 1 != 0)
186 return "not an integer";
190 "check_positiveInteger": function(arg)
192 return Validator["check_integer"](arg) || (arg<0 ? "not positive" : "");
195 "check_boolean": function(arg)
197 if (!_.isBoolean(arg))
198 return "not a boolean";
202 "check_password": function(arg)
204 if (!_.isString(arg))
205 return "not a string";
206 if (!/^[\x21-\x7E]{1,16}$/.test(arg))
207 return "[1,16] ASCII characters with code in [33,126]";
211 // Sha-1 hash: length 40, hexadecimal
212 "check_hash": function(arg)
214 if (!_.isString(arg))
215 return "not a string";
216 if (!/^[a-f0-9]{40}$/.test(arg))
217 return "not a sha-1 hash";
221 "check_integerArray": function(arg)
224 return "not an array";
225 for (let i=0; i<arg.length; i++)
227 let error = Validator["check_integer"](arg[i]);
228 if (error.length > 0)
234 "check_stringOrIntegerArray": function(arg)
236 if (!_.isString(arg))
237 return Validator["check_integerArray"](arg);
242 try { module.exports = Validator.checkObject; } catch (err) {} //for server