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
,
56 "initials": "unchecked", //not a user input
57 "loginToken": "unchecked",
58 "sessionTokens": "unchecked",
59 "token": "alphanumeric", //exception: for the purpose of user registration
66 "group": "positiveInteger",
73 "description": "string",
75 "students": Validator
.Student
,
78 Object
.assign(Validator
,
80 // Recurse into sub-documents
81 checkObject_aux: function(obj
, model
)
83 for (let key
of Object
.keys(obj
))
86 return "Unknown field";
87 if (model
[key
] == "unchecked") //not a user input (ignored)
89 if (_
.isObject(model
[key
]))
91 // TODO: next loop seems too heavy... (only a concern if big class import?)
92 for (let item
of obj
[key
])
94 let error
= Validator
.checkObject_aux(item
, model
[key
]);
101 let error
= Validator
[ "check_" + model
[key
] ](obj
[key
]);
102 if (error
.length
> 0)
103 return key
+ ": " + error
;
109 // Always check top-level object
110 checkObject: function(obj
, name
)
112 return Validator
.checkObject_aux(obj
, Validator
[name
]);
115 "check_string": function(arg
)
117 return ""; //strings are unchecked, but sanitized
120 "check_section": function(arg
)
122 if (!_
.isString(arg
))
123 return "not a string";
124 if (!/^[0-9.]+$/.test(arg
))
125 return "digits and dot only";
129 "check_stringArray": function(arg
)
131 return !_
.isArray(arg
) ? "not an array" : "";
134 "check_alphanumeric": function(arg
)
136 return arg
.match(/^[\w]{1,32}$/) === null ? "[1,32] alphanumerics" : "";
139 "check_bson": function(arg
)
141 return arg
.match(/^[a-z0-9]{24}$/) === null ? "not a BSON id" : "";
144 "check_name": function(arg
)
146 if (!_
.isString(arg
))
147 return "not a string";
148 if (!/^[a
-zA
-Z
\u00C0-\u024F -]{1,32}$/.test(arg
))
149 return "[1,32] letters + hyphen/space";
153 "check_email": function(arg
)
155 if (!_
.isString(arg
))
156 return "not a string";
158 return "string too long: max. 64 characters";
159 // Regexp used in "type='email'" inputs ( http://emailregex.com/ )
160 if (!/^[a-zA-Z0-9.!#$%&’*+/=?^_
`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(arg))
161 return "X@Y, alphanumerics and . _ - +(X)";
165 "check_code": function(arg)
167 if (!_.isString(arg))
168 return "not a string";
169 if (!/^[\w.-]{1,16}$/.test(arg))
170 return "[1,16] alphanumerics and . _ -";
174 "check_number": function(arg)
176 if (!_.isNumber(arg))
177 arg = parseFloat(arg);
179 return "not a number";
183 "check_integer": function(arg)
185 if (!_.isNumber(arg))
187 if (isNaN(arg) || arg % 1 != 0)
188 return "not an integer";
192 "check_positiveInteger": function(arg)
194 return Validator["check_integer"](arg) || (arg<0 ? "not positive" : "");
197 "check_boolean": function(arg)
199 if (!_.isBoolean(arg))
200 return "not a boolean";
204 "check_password": function(arg)
206 if (!_.isString(arg))
207 return "not a string";
208 if (!/^[\x21-\x7E]{1,16}$/.test(arg))
209 return "[1,16] ASCII characters with code in [33,126]";
213 // Sha-1 hash: length 40, hexadecimal
214 "check_hash": function(arg)
216 if (!_.isString(arg))
217 return "not a string";
218 if (!/^[a-f0-9]{40}$/.test(arg))
219 return "not a sha-1 hash";
223 "check_integerArray": function(arg)
226 return "not an array";
227 for (let i=0; i<arg.length; i++)
229 let error = Validator["check_integer"](arg[i]);
230 if (error.length > 0)
236 "check_stringOrIntegerArray": function(arg)
238 if (!_.isString(arg))
239 return Validator["check_integerArray"](arg);
244 try { module.exports = Validator.checkObject; } catch (err) {} //for server