| 1 | let router = require("express").Router(); |
| 2 | const access = require("../utils/access"); |
| 3 | const UserEntity = require("../entities/user"); |
| 4 | const AssessmentEntity = require("../entities/assessment"); |
| 5 | const CourseModel = require("../models/course"); |
| 6 | const AssessmentModel = require("../models/assessment"); |
| 7 | |
| 8 | // Actual pages (least specific last) |
| 9 | |
| 10 | // List initials and count assessments |
| 11 | router.get("/", (req,res) => { |
| 12 | UserEntity.getAll( (err,userArray) => { |
| 13 | if (!!err) |
| 14 | return res.json(err); |
| 15 | res.render("index", { |
| 16 | title: "home", |
| 17 | userArray: userArray, |
| 18 | }); |
| 19 | }); |
| 20 | }); |
| 21 | |
| 22 | // Login screen |
| 23 | router.get("/login", access.unlogged, (req,res) => { |
| 24 | res.render("login", { |
| 25 | title: "login", |
| 26 | }); |
| 27 | }); |
| 28 | |
| 29 | // Redirection screens when possible cheating attempt detected in exam |
| 30 | router.get("/enablejs", (req,res) => { |
| 31 | res.render("enable-js", { |
| 32 | title: "JS disabled", |
| 33 | }); |
| 34 | }); |
| 35 | |
| 36 | router.get("/nodevtools", (req,res) => { |
| 37 | res.render("no-devtools", { |
| 38 | title: "Devtools enabled", |
| 39 | }); |
| 40 | }); |
| 41 | |
| 42 | // List courses of some user (should be [a-z]+[0-9]* but fails...) |
| 43 | router.get("/:initials([a-z0-9]+)", (req,res) => { |
| 44 | let initials = req.params["initials"]; |
| 45 | CourseModel.getByInitials(initials, (err,courseArray) => { |
| 46 | if (!!err) |
| 47 | return res.json(err); |
| 48 | access.getUser(req, res, (err2,user) => { |
| 49 | const isTeacher = !!user && user.initials == initials; |
| 50 | // Strip students from courses if not course admin (TODO: not required in any case) |
| 51 | if (!isTeacher) |
| 52 | { |
| 53 | courseArray.forEach( c => { |
| 54 | delete c["students"]; |
| 55 | }); |
| 56 | } |
| 57 | res.render("course-list", { |
| 58 | title: initials + " courses", |
| 59 | courseArray: courseArray, |
| 60 | teacher: isTeacher, |
| 61 | initials: initials, |
| 62 | }); |
| 63 | }); |
| 64 | }); |
| 65 | }); |
| 66 | |
| 67 | // Detailed content of one course |
| 68 | router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)", (req,res) => { |
| 69 | let initials = req.params["initials"]; |
| 70 | let code = req.params["courseCode"]; |
| 71 | CourseModel.getByRefs(initials, code, (err,course) => { |
| 72 | access.checkRequest(res, err, course, "Course not found", () => { |
| 73 | AssessmentEntity.getByCourse(course._id, (err2,assessmentArray) => { |
| 74 | if (!!err) |
| 75 | return res.json(err); |
| 76 | access.getUser(req, res, (err2,user) => { |
| 77 | const isTeacher = !!user && user.initials == initials; |
| 78 | // Strip students from course if not course admin |
| 79 | if (!isTeacher) |
| 80 | delete course["students"]; |
| 81 | res.render("course", { |
| 82 | title: "course " + initials + "/" + code, |
| 83 | course: course, |
| 84 | assessmentArray: assessmentArray, |
| 85 | teacher: isTeacher, |
| 86 | initials: initials, |
| 87 | }); |
| 88 | }); |
| 89 | }); |
| 90 | }); |
| 91 | }); |
| 92 | }); |
| 93 | |
| 94 | // Display assessment (exam or open status) |
| 95 | router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)", (req,res) => { |
| 96 | let initials = req.params["initials"]; |
| 97 | let code = req.params["courseCode"]; |
| 98 | let name = req.params["assessmentName"]; |
| 99 | AssessmentModel.getByRefs(initials, code, name, (err,assessment) => { |
| 100 | access.checkRequest(res, err, assessment, "Assessment not found", () => { |
| 101 | if (!assessment.active) |
| 102 | return res.json({errmsg: "Assessment is idle"}); |
| 103 | delete assessment["papers"]; //always remove recorded students answers |
| 104 | if (assessment.mode == "exam") |
| 105 | { |
| 106 | if (!!req.headers['user-agent'].match(/(SpecialAgent|HeadlessChrome|PhantomJS)/)) |
| 107 | { |
| 108 | // Basic headless browser detection |
| 109 | return res.json({errmsg: "Headless browser detected"}); |
| 110 | } |
| 111 | // Strip conclusion + questions if exam mode (stepwise process) |
| 112 | delete assessment["conclusion"]; |
| 113 | delete assessment["questions"]; |
| 114 | } |
| 115 | res.render("assessment", { |
| 116 | title: "assessment " + initials + "/" + code + "/" + name, |
| 117 | assessment: assessment, |
| 118 | }); |
| 119 | }); |
| 120 | }); |
| 121 | }); |
| 122 | |
| 123 | // Monitor: --> after identification (password), always send password hash with requests |
| 124 | router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)/monitor", (req,res) => { |
| 125 | let initials = req.params["initials"]; |
| 126 | let code = req.params["courseCode"]; |
| 127 | let name = req.params["assessmentName"]; |
| 128 | res.render("monitor", { |
| 129 | title: "monitor assessment " + code + "/" + name, |
| 130 | initials: initials, |
| 131 | code: code, |
| 132 | name: name, |
| 133 | }); |
| 134 | }); |
| 135 | |
| 136 | module.exports = router; |