Commit b1b7a3fd8f185093fb79f19619b2d9332dc660dc
1 parent
4f49f07b
Exists in
master
and in
1 other branch
- fixed showing images in /review.
Showing
5 changed files
with
34 additions
and
13 deletions
Show diff stats
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='', 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 | + ]) | ... | ... |