Commit b1b7a3fd8f185093fb79f19619b2d9332dc660dc

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

- fixed showing images in /review.

BUGS.md
1 1  
2 2 # BUGS
3 3  
4   -- /review não mostra imagens porque precisa que teste esteja a decorrer...
5 4 - usar thread.Lock para aceder a variaveis de estado?
6 5  
7 6 # TODO
... ... @@ -23,6 +22,7 @@
23 22  
24 23 # FIXED
25 24  
  25 +- /review não mostra imagens porque precisa que teste esteja a decorrer...
26 26 - visualizar um teste ja realizado na página de administração
27 27 - Depois da correcção, mostra testes realizados que não foram realizados pelo próprio
28 28 - detectar se janela perde focus e alertar o prof (http://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active)
... ...
app.py
... ... @@ -175,6 +175,8 @@ class App(object):
175 175 return self.online[uid]['student']['name']
176 176 def get_test(self, uid, default=None):
177 177 return self.online[uid].get('test', default)
  178 + def get_questions_path(self):
  179 + return self.testfactory['questions_dir']
178 180 def get_test_qtypes(self, uid):
179 181 return {q['ref']:q['type'] for q in self.online[uid]['test']['questions']}
180 182 def get_student_grades_from_all_tests(self, uid):
... ...
serve.py
... ... @@ -256,6 +256,7 @@ class Root(object):
256 256 @require()
257 257 def file(self, ref, name):
258 258 # serve a static file: userid, question ref, file name
  259 + # only works for users running a test
259 260 uid = cherrypy.session.get(SESSION_KEY)
260 261 filename = self.app.get_file(uid, ref, name)
261 262 return cherrypy.lib.static.serve_file(filename)
... ... @@ -275,6 +276,12 @@ class Root(object):
275 276 t = json.load(f)
276 277 return self.template['review'].render(t=t)
277 278  
  279 + @cherrypy.expose
  280 + @require(name_is('0'))
  281 + def absfile(self, name):
  282 + filename = path.abspath(path.join(self.app.get_questions_path(), name))
  283 + return cherrypy.lib.static.serve_file(filename)
  284 +
278 285 # ============================================================================
279 286 def parse_arguments():
280 287 argparser = argparse.ArgumentParser(description='Server for online tests. Enrolled students and tests have to be previously configured. Please read the documentation included with this software before running the server.')
... ...
templates/review.html
... ... @@ -89,7 +89,7 @@
89 89 </div>
90 90  
91 91 <%!
92   - from tools import md_to_html
  92 + from tools import md_to_html_review
93 93 %>
94 94 <%
95 95 total_points = sum(q['points'] for q in t['questions'])
... ... @@ -105,7 +105,7 @@
105 105 ${q['title']}
106 106 </h4>
107 107 <p>
108   - ${md_to_html(q['text'], q['ref'], q['files'])}
  108 + ${md_to_html_review(q['text'], q)}
109 109 </p>
110 110 </div>
111 111 % elif q['type'] == 'warning':
... ... @@ -115,7 +115,7 @@
115 115 ${q['title']}
116 116 </h4>
117 117 <p>
118   - ${md_to_html(q['text'], q['ref'], q['files'])}
  118 + ${md_to_html_review(q['text'], q)}
119 119 </p>
120 120 </div>
121 121 % elif q['type'] == 'alert':
... ... @@ -125,7 +125,7 @@
125 125 ${q['title']}
126 126 </h4>
127 127 <p>
128   - ${md_to_html(q['text'], q['ref'], q['files'])}
  128 + ${md_to_html_review(q['text'], q)}
129 129 </p>
130 130 </div>
131 131  
... ... @@ -146,15 +146,15 @@
146 146 </div>
147 147 <div class="panel-body" id="example${i}">
148 148 <div class="question">
149   - ${md_to_html(q['text'], q['ref'], q['files'])}
  149 + ${md_to_html_review(q['text'], q)}
150 150 </div>
151 151  
152 152 % if q['type'] == 'radio':
153 153 % for opt in q['options']:
154 154 % if q['answer'] is not None and str(loop.index) == q['answer']:
155   - ${md_to_html('<i class="fa fa-dot-circle-o" aria-hidden="true"></i> ' + opt, q['ref'], q['files'])}
  155 + ${md_to_html_review('<i class="fa fa-dot-circle-o" aria-hidden="true"></i> ' + opt, q)}
156 156 % else:
157   - ${md_to_html('<i class="fa fa-circle-o" aria-hidden="true"></i> ' + opt, q['ref'], q['files'])}
  157 + ${md_to_html_review('<i class="fa fa-circle-o" aria-hidden="true"></i> ' + opt, q)}
158 158 % endif
159 159  
160 160 % endfor
... ... @@ -162,9 +162,9 @@
162 162 % elif q['type'] == 'checkbox':
163 163 % for opt in q['options']:
164 164 % if q['answer'] is not None and str(loop.index) in q['answer']:
165   - ${md_to_html('<i class="fa fa-check-square-o" aria-hidden="true"></i> ' + opt, q['ref'], q['files'])}
  165 + ${md_to_html_review('<i class="fa fa-check-square-o" aria-hidden="true"></i> ' + opt, q)}
166 166 % else:
167   - ${md_to_html('<i class="fa fa-square-o" aria-hidden="true"></i> ' + opt, q['ref'], q['files'])}
  167 + ${md_to_html_review('<i class="fa fa-square-o" aria-hidden="true"></i> ' + opt, q)}
168 168 % endif
169 169 % endfor
170 170  
... ... @@ -179,7 +179,7 @@
179 179 </button>
180 180 <div class="collapse" id="hint-${q['ref']}">
181 181 <div class="well">
182   - ${md_to_html(q['hint'], q['ref'], q['files'])}
  182 + ${md_to_html_review(q['hint'], q)}
183 183 </div>
184 184 </div>
185 185 % endif # hint
... ...
tools.py
1 1  
2   -
3 2 import subprocess
4 3 import logging
5 4 import yaml
... ... @@ -58,7 +57,9 @@ def run_script(script, stdin=&#39;&#39;, timeout=5):
58 57  
59 58 def md_to_html(text, ref=None, files={}):
60 59 if ref is not None:
61   - for k,f in files.items():
  60 + # given q['ref'] and q['files'] replaces references to files by a
  61 + # GET to /file?ref=???;name=???
  62 + for k in files:
62 63 text = text.replace(k, '/file?ref={};name={}'.format(ref, k))
63 64 return markdown.markdown(text, extensions=[
64 65 'markdown.extensions.tables',
... ... @@ -67,3 +68,14 @@ def md_to_html(text, ref=None, files={}):
67 68 'markdown.extensions.def_list',
68 69 'markdown.extensions.sane_lists'
69 70 ])
  71 +
  72 +def md_to_html_review(text, q):
  73 + for k,f in q['files'].items():
  74 + text = text.replace(k, '/absfile?name={}'.format(q['files'][k]))
  75 + return markdown.markdown(text, extensions=[
  76 + 'markdown.extensions.tables',
  77 + 'markdown.extensions.fenced_code',
  78 + 'markdown.extensions.codehilite',
  79 + 'markdown.extensions.def_list',
  80 + 'markdown.extensions.sane_lists'
  81 + ])
... ...