Commit 8c25db5a0e1e21c40032405400edb10ccf8fe9e1

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

- handle focus/unfocus events

- handle resize event
- report initial screen and window size
- simplified run_script() function in tools.py
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.04.dev2' 35 +APP_VERSION = '2020.04.dev3'
36 APP_DESCRIPTION = __doc__ 36 APP_DESCRIPTION = __doc__
37 37
38 __author__ = 'Miguel Barão' 38 __author__ = 'Miguel Barão'
perguntations/app.py
@@ -257,6 +257,17 @@ class App(): @@ -257,6 +257,17 @@ class App():
257 return test 257 return test
258 258
259 # ------------------------------------------------------------------------ 259 # ------------------------------------------------------------------------
  260 + def event_test(self, uid, cmd, value):
  261 + '''handle browser events the occur during the test'''
  262 + if cmd == 'focus':
  263 + logger.info('Student %s: focus %s', uid, value)
  264 + elif cmd == 'size':
  265 + scr_y, scr_x, win_y, win_x = value
  266 + area = win_x * win_y / (scr_x * scr_y) * 100
  267 + logger.info('Student %s: area=%g%%, window=%dx%d, screen=%dx%d',
  268 + uid, area, win_x, win_y, scr_x, scr_y)
  269 +
  270 + # ------------------------------------------------------------------------
260 271
261 # --- helpers (getters) 272 # --- helpers (getters)
262 # def get_student_name(self, uid): 273 # def get_student_name(self, uid):
perguntations/serve.py
@@ -42,6 +42,7 @@ class WebApplication(tornado.web.Application): @@ -42,6 +42,7 @@ class WebApplication(tornado.web.Application):
42 (r'/file', FileHandler), 42 (r'/file', FileHandler),
43 # (r'/root', MainHandler), # FIXME 43 # (r'/root', MainHandler), # FIXME
44 # (r'/ws', AdminSocketHandler), 44 # (r'/ws', AdminSocketHandler),
  45 + (r'/studentwebservice', StudentWebservice),
45 (r'/', RootHandler), 46 (r'/', RootHandler),
46 ] 47 ]
47 48
@@ -152,13 +153,24 @@ class BaseHandler(tornado.web.RequestHandler): @@ -152,13 +153,24 @@ class BaseHandler(tornado.web.RequestHandler):
152 # AdminSocketHandler.update_cache(chat) # store msgs 153 # AdminSocketHandler.update_cache(chat) # store msgs
153 # AdminSocketHandler.send_updates(chat) # send to clients 154 # AdminSocketHandler.send_updates(chat) # send to clients
154 155
  156 +class StudentWebservice(BaseHandler):
  157 + '''
  158 + Receive ajax from students in the test:
  159 + focus, unfocus
  160 + '''
  161 +
  162 + @tornado.web.authenticated
  163 + def post(self):
  164 + '''handle ajax post'''
  165 + uid = self.current_user
  166 + cmd = self.get_body_argument('cmd', None)
  167 + value = json.loads(self.get_body_argument('value', None))
  168 + self.testapp.event_test(uid, cmd, value)
155 169
156 # ---------------------------------------------------------------------------- 170 # ----------------------------------------------------------------------------
157 class AdminHandler(BaseHandler): 171 class AdminHandler(BaseHandler):
158 '''Handle /admin''' 172 '''Handle /admin'''
159 173
160 - # SUPPORTED_METHODS = ['GET', 'POST']  
161 -  
162 @tornado.web.authenticated 174 @tornado.web.authenticated
163 @admin_only 175 @admin_only
164 async def get(self): 176 async def get(self):
@@ -405,7 +417,9 @@ class TestHandler(BaseHandler): @@ -405,7 +417,9 @@ class TestHandler(BaseHandler):
405 417
406 # --- REVIEW ----------------------------------------------------------------- 418 # --- REVIEW -----------------------------------------------------------------
407 class ReviewHandler(BaseHandler): 419 class ReviewHandler(BaseHandler):
408 - # SUPPORTED_METHODS = ['GET'] 420 + '''
  421 + Show test for review
  422 + '''
409 423
410 _templates = { 424 _templates = {
411 'radio': 'review-question-radio.html', 425 'radio': 'review-question-radio.html',
@@ -445,7 +459,6 @@ class ReviewHandler(BaseHandler): @@ -445,7 +459,6 @@ class ReviewHandler(BaseHandler):
445 templ=self._templates) 459 templ=self._templates)
446 460
447 461
448 -  
449 # ---------------------------------------------------------------------------- 462 # ----------------------------------------------------------------------------
450 def signal_handler(sig, frame): 463 def signal_handler(sig, frame):
451 ''' 464 '''
perguntations/static/js/detect_unfocus.js
  1 +// from: https://www.tornadoweb.org/en/stable/guide/security.html
  2 +// with changes: removed datatype and callback from original postJSON
  3 +function getCookie(name) {
  4 + var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
  5 + return r ? r[1] : undefined;
  6 +}
  7 +
  8 +jQuery.postJSON = function(url, args) {
  9 + args._xsrf = getCookie("_xsrf");
  10 + $.ajax({url: url, data: $.param(args), type: "POST"});
  11 +};
  12 +
  13 +
1 $(document).ready(function() { 14 $(document).ready(function() {
  15 + $.postJSON("/studentwebservice", {
  16 + "cmd": "size",
  17 + "value": JSON.stringify([screen.height, screen.width, $(window).height(), $(window).width()]),
  18 + });
  19 +
2 $(window).focus(function(){ 20 $(window).focus(function(){
3 - $.ajax({  
4 - type: "POST",  
5 - url: "/studentwebservice",  
6 - data: {  
7 - "cmd": "focus",  
8 - "number": $("#number").text(),  
9 - "value": true  
10 - } 21 + $.postJSON("/studentwebservice", {
  22 + "cmd": "focus",
  23 + "value": true,
11 }); 24 });
12 }); 25 });
13 26
14 - $(window).blur(function(e){  
15 - $.ajax({  
16 - type: "POST",  
17 - url: "/studentwebservice",  
18 - data: {  
19 - "cmd": "focus",  
20 - "number": $("#number").text(),  
21 - "value": false  
22 - } 27 + $(window).blur(function(){
  28 + $.postJSON("/studentwebservice", {
  29 + "cmd": "focus",
  30 + "value": false,
23 }); 31 });
24 }); 32 });
25 33
26 $(window).resize(function(){ 34 $(window).resize(function(){
27 - var n = $(window).scrollTop();  
28 - $.ajax({  
29 - type: "POST",  
30 - url: "/adminwebservice",  
31 - data: {  
32 - "cmd": "resize",  
33 - "name": $("#number").text(),  
34 - "scroll": n  
35 - } 35 + $.postJSON("/studentwebservice", {
  36 + "cmd": "size",
  37 + "value": JSON.stringify([screen.height, screen.width, $(window).height(), $(window).width()]),
36 }); 38 });
  39 +
  40 +
  41 + // // var n = $(window).scrollTop();
  42 + // $.postJSON({"/studentwebservice", {
  43 + // "cmd": "size",
  44 + // "value": JSON.stringify([screen.height, screen.width, $(window).height(), $(window).width()]),
  45 + // }});
  46 + // // data: {
  47 + // // "cmd": "resize",
  48 + // // "name": $("#number").text(),
  49 + // // "scroll": n
  50 + // // }
  51 + // // });
37 }); 52 });
38 -});  
39 \ No newline at end of file 53 \ No newline at end of file
  54 +
  55 +});
perguntations/templates/test.html
@@ -38,6 +38,7 @@ @@ -38,6 +38,7 @@
38 <!-- My scripts --> 38 <!-- My scripts -->
39 <script defer src="/static/js/question_disabler.js"></script> 39 <script defer src="/static/js/question_disabler.js"></script>
40 <script defer src="/static/js/prevent_enter_submit.js"></script> 40 <script defer src="/static/js/prevent_enter_submit.js"></script>
  41 + <script defer src="/static/js/detect_unfocus.js"></script>
41 </head> 42 </head>
42 <!-- ===================================================================== --> 43 <!-- ===================================================================== -->
43 <body> 44 <body>
perguntations/tools.py
@@ -67,21 +67,16 @@ def run_script(script: str, @@ -67,21 +67,16 @@ def run_script(script: str,
67 stderr=subprocess.STDOUT, 67 stderr=subprocess.STDOUT,
68 universal_newlines=True, 68 universal_newlines=True,
69 timeout=timeout, 69 timeout=timeout,
70 - check=False, 70 + check=True,
71 ) 71 )
72 - except OSError:  
73 - logger.error('Can not execute script "%s".', script)  
74 - return output  
75 except subprocess.TimeoutExpired: 72 except subprocess.TimeoutExpired:
76 logger.error('Timeout %ds exceeded running "%s".', timeout, script) 73 logger.error('Timeout %ds exceeded running "%s".', timeout, script)
77 return output 74 return output
78 - except Exception:  
79 - logger.error('An Exception ocurred running "%s".', script) 75 + except subprocess.CalledProcessError as exc:
  76 + logger.error('Return code %d running "%s".', exc.returncode, script)
80 return output 77 return output
81 -  
82 - # --- check return code  
83 - if proc.returncode != 0:  
84 - logger.error('Return code %d running "%s".', proc.returncode, script) 78 + except OSError:
  79 + logger.error('Can not execute script "%s".', script)
85 return output 80 return output
86 81
87 # --- parse yaml 82 # --- parse yaml