Commit da470fc69ac16b213de6ed508ae84b6d243c70fc
1 parent
a81c2241
Exists in
master
and in
1 other branch
- show browser/screen area and focus state on admin page.
Showing
4 changed files
with
42 additions
and
14 deletions
Show diff stats
perguntations/__init__.py
| @@ -32,7 +32,7 @@ proof of submission and for review. | @@ -32,7 +32,7 @@ proof of submission and for review. | ||
| 32 | ''' | 32 | ''' |
| 33 | 33 | ||
| 34 | APP_NAME = 'perguntations' | 34 | APP_NAME = 'perguntations' |
| 35 | -APP_VERSION = '2020.05.dev5' | 35 | +APP_VERSION = '2020.05.dev6' |
| 36 | APP_DESCRIPTION = __doc__ | 36 | APP_DESCRIPTION = __doc__ |
| 37 | 37 | ||
| 38 | __author__ = 'Miguel Barão' | 38 | __author__ = 'Miguel Barão' |
perguntations/app.py
| @@ -86,6 +86,8 @@ class App(): | @@ -86,6 +86,8 @@ class App(): | ||
| 86 | def __init__(self, conf): | 86 | def __init__(self, conf): |
| 87 | self.online = dict() # {uid: {'student':{...}, 'test': {...}}, ...} | 87 | self.online = dict() # {uid: {'student':{...}, 'test': {...}}, ...} |
| 88 | self.allowed = set() # '0' is hardcoded to allowed elsewhere | 88 | self.allowed = set() # '0' is hardcoded to allowed elsewhere |
| 89 | + self.unfocus = set() # set of students that have no browser focus | ||
| 90 | + self.area = dict() # {uid: percent_area} | ||
| 89 | 91 | ||
| 90 | logger.info('Loading test configuration "%s".', conf["testfile"]) | 92 | logger.info('Loading test configuration "%s".', conf["testfile"]) |
| 91 | try: | 93 | try: |
| @@ -268,12 +270,12 @@ class App(): | @@ -268,12 +270,12 @@ class App(): | ||
| 268 | def event_test(self, uid, cmd, value): | 270 | def event_test(self, uid, cmd, value): |
| 269 | '''handles browser events the occur during the test''' | 271 | '''handles browser events the occur during the test''' |
| 270 | if cmd == 'focus': | 272 | if cmd == 'focus': |
| 271 | - logger.info('"%s": focus %s', uid, value) | 273 | + if value: |
| 274 | + self.focus_student(uid) | ||
| 275 | + else: | ||
| 276 | + self.unfocus_student(uid) | ||
| 272 | elif cmd == 'size': | 277 | elif cmd == 'size': |
| 273 | - scr_y, scr_x, win_y, win_x = value | ||
| 274 | - area = win_x * win_y / (scr_x * scr_y) * 100 | ||
| 275 | - logger.info('"%s": area=%g%%, window=%dx%d, screen=%dx%d', | ||
| 276 | - uid, area, win_x, win_y, scr_x, scr_y) | 278 | + self.set_screen_area(uid, value) |
| 277 | 279 | ||
| 278 | # ------------------------------------------------------------------------ | 280 | # ------------------------------------------------------------------------ |
| 279 | # --- GETTERS | 281 | # --- GETTERS |
| @@ -374,6 +376,8 @@ class App(): | @@ -374,6 +376,8 @@ class App(): | ||
| 374 | 'start_time': self.online.get(uid, {}).get('test', {}) | 376 | 'start_time': self.online.get(uid, {}).get('test', {}) |
| 375 | .get('start_time', ''), | 377 | .get('start_time', ''), |
| 376 | 'password_defined': pw != '', | 378 | 'password_defined': pw != '', |
| 379 | + 'unfocus': uid in self.unfocus, | ||
| 380 | + 'area': self.area.get(uid, None), | ||
| 377 | 'grades': self.get_student_grades_from_test( | 381 | 'grades': self.get_student_grades_from_test( |
| 378 | uid, self.testfactory['ref']) | 382 | uid, self.testfactory['ref']) |
| 379 | } for uid, name, pw in self.get_all_students()] | 383 | } for uid, name, pw in self.get_all_students()] |
| @@ -406,12 +410,30 @@ class App(): | @@ -406,12 +410,30 @@ class App(): | ||
| 406 | def allow_all_students(self): | 410 | def allow_all_students(self): |
| 407 | '''allow all students to login''' | 411 | '''allow all students to login''' |
| 408 | logger.info('Allowing all students...') | 412 | logger.info('Allowing all students...') |
| 409 | - self.allowed = set(s[0] for s in self.get_all_students()) | 413 | + self.allowed.update(s[0] for s in self.get_all_students()) |
| 410 | 414 | ||
| 411 | def deny_all_students(self): | 415 | def deny_all_students(self): |
| 412 | '''deny all students to login''' | 416 | '''deny all students to login''' |
| 413 | logger.info('Denying all students...') | 417 | logger.info('Denying all students...') |
| 414 | - self.allowed = set() | 418 | + self.allowed.clear() |
| 419 | + | ||
| 420 | + def focus_student(self, uid): | ||
| 421 | + '''set student in focus state''' | ||
| 422 | + self.unfocus.discard(uid) | ||
| 423 | + logger.info('"%s" focus', uid) | ||
| 424 | + | ||
| 425 | + def unfocus_student(self, uid): | ||
| 426 | + '''set student in unfocus state''' | ||
| 427 | + self.unfocus.add(uid) | ||
| 428 | + logger.info('"%s" unfocus', uid) | ||
| 429 | + | ||
| 430 | + def set_screen_area(self, uid, sizes): | ||
| 431 | + '''set current browser area as detected in resize event''' | ||
| 432 | + scr_y, scr_x, win_y, win_x = sizes | ||
| 433 | + area = win_x * win_y / (scr_x * scr_y) * 100 | ||
| 434 | + self.area[uid] = area | ||
| 435 | + logger.info('"%s": area=%g%%, window=%dx%d, screen=%dx%d', | ||
| 436 | + uid, area, win_x, win_y, scr_x, scr_y) | ||
| 415 | 437 | ||
| 416 | async def update_student_password(self, uid, password=''): | 438 | async def update_student_password(self, uid, password=''): |
| 417 | '''change password on the database''' | 439 | '''change password on the database''' |
perguntations/static/js/admin.js
| @@ -16,11 +16,9 @@ $(document).ready(function() { | @@ -16,11 +16,9 @@ $(document).ready(function() { | ||
| 16 | // button handlers (runs once) | 16 | // button handlers (runs once) |
| 17 | $("#allow_all").click(function() { | 17 | $("#allow_all").click(function() { |
| 18 | $.postJSON("/admin", {"cmd": "allow_all"}); | 18 | $.postJSON("/admin", {"cmd": "allow_all"}); |
| 19 | - // $(":checkbox").prop("checked", true).trigger('change'); | ||
| 20 | }); | 19 | }); |
| 21 | $("#deny_all").click(function() { | 20 | $("#deny_all").click(function() { |
| 22 | $.postJSON("/admin", {"cmd": "deny_all"}); | 21 | $.postJSON("/admin", {"cmd": "deny_all"}); |
| 23 | - // $(":checkbox").prop("checked", false).trigger('change'); | ||
| 24 | }); | 22 | }); |
| 25 | $("#reset_password").click(function () { | 23 | $("#reset_password").click(function () { |
| 26 | $.postJSON("/admin", { | 24 | $.postJSON("/admin", { |
| @@ -120,7 +118,15 @@ $(document).ready(function() { | @@ -120,7 +118,15 @@ $(document).ready(function() { | ||
| 120 | var uid = d['uid']; | 118 | var uid = d['uid']; |
| 121 | var checked = d['allowed'] ? 'checked' : ''; | 119 | var checked = d['allowed'] ? 'checked' : ''; |
| 122 | var password_defined = d['password_defined'] ? ' <span class="badge badge-secondary"><i class="fa fa-key" aria-hidden="true"></i></span>' : ''; | 120 | var password_defined = d['password_defined'] ? ' <span class="badge badge-secondary"><i class="fa fa-key" aria-hidden="true"></i></span>' : ''; |
| 123 | - var hora_inicio = d['start_time'] ? ' <span class="badge badge-success">' + d['start_time'].slice(11,19) + '</span>': ''; | 121 | + var hora_inicio = d['start_time'] ? ' <span class="badge badge-success"><i class="fas fa-hourglass-start"></i> ' + d['start_time'].slice(11,16) + '</span>': ''; |
| 122 | + var unfocus = d['unfocus']? ' <span class="badge badge-danger">unfocus</span>' : ''; | ||
| 123 | + var area = ''; | ||
| 124 | + if (d['start_time'] ) { | ||
| 125 | + if (d['area'] > 75) | ||
| 126 | + area = ' <span class="badge badge-success"><i class="fas fa-desktop"></i> ' + Math.round(d['area']) + '%</span>'; | ||
| 127 | + else | ||
| 128 | + area = ' <span class="badge badge-danger"><i class="fas fa-desktop"></i> ' + Math.round(d['area']) + '%</span>'; | ||
| 129 | + }; | ||
| 124 | var g = d['grades']; | 130 | var g = d['grades']; |
| 125 | 131 | ||
| 126 | t[i] = []; | 132 | t[i] = []; |
| @@ -128,7 +134,7 @@ $(document).ready(function() { | @@ -128,7 +134,7 @@ $(document).ready(function() { | ||
| 128 | t[i][1] = '<input type="checkbox" name="' + uid + '" value="true"' + checked + '> '; | 134 | t[i][1] = '<input type="checkbox" name="' + uid + '" value="true"' + checked + '> '; |
| 129 | t[i][2] = uid; | 135 | t[i][2] = uid; |
| 130 | t[i][3] = d['name']; | 136 | t[i][3] = d['name']; |
| 131 | - t[i][4] = password_defined + hora_inicio; | 137 | + t[i][4] = password_defined + hora_inicio + area + unfocus; |
| 132 | 138 | ||
| 133 | var gbar = ''; | 139 | var gbar = ''; |
| 134 | for (var j=0; j < g.length; j++) | 140 | for (var j=0; j < g.length; j++) |
perguntations/templates/review.html
| @@ -74,9 +74,9 @@ | @@ -74,9 +74,9 @@ | ||
| 74 | <h1 class="display-5">{{ t['title'] }}</h1> | 74 | <h1 class="display-5">{{ t['title'] }}</h1> |
| 75 | <h5> | 75 | <h5> |
| 76 | <div class="row"> | 76 | <div class="row"> |
| 77 | - <label for="duracao" class="col-sm-2">Duração (minutos):</label> | 77 | + <label for="duracao" class="col-sm-2">Duração:</label> |
| 78 | <div class="col-sm-10" id="duracao"> | 78 | <div class="col-sm-10" id="duracao"> |
| 79 | - {{ t.get('duration', 0) if t.get('duration', 0) > 0 else '+'+chr(8734) }} | 79 | + {{ str(t.get('duration', 0)) + ' minutos' if t.get('duration', 0) > 0 else '+'+chr(8734) }} |
| 80 | </div> | 80 | </div> |
| 81 | </div> | 81 | </div> |
| 82 | </h5> | 82 | </h5> |