Commit deb94ec762808cf5714ac8b014930211d1741675

Authored by Miguel Barão
1 parent fb7a9089
Exists in master and in 1 other branch dev

- show browser/screen area and focus state on admin page.

- minor cosmetic changes.
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>