Commit 9aeb5485618afee8d771f689cf68305cfc76af77
1 parent
dbdd58fe
Exists in
master
and in
1 other branch
- modified how post questions behave: wait feedback then move to next question.
not yet functional!
Showing
11 changed files
with
157 additions
and
112 deletions
Show diff stats
BUGS.md
1 | 1 | |
2 | 2 | # BUGS |
3 | 3 | |
4 | +- errar no ultimo topico nao mostra solucao? | |
4 | 5 | - nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido. |
5 | 6 | - ocorreu uma vez o sqlalchemy dar mesg erro a indicar que as threads sao diferents quando se faz o get da primeira pergunta do topico. Muitas vezes nao mostar erro, mas a pagina da erro ou fica em branco... |
6 | 7 | ... | ... |
demo/solar_system/questions.yaml
... | ... | @@ -19,32 +19,32 @@ |
19 | 19 | shuffle: False |
20 | 20 | discount: True |
21 | 21 | |
22 | -# # --------------------------------------------------------------------------- | |
23 | -# - | |
24 | -# ref: home-planet | |
25 | -# type: text | |
26 | -# title: Sistema solar | |
27 | -# text: O nosso planeta chama-se planeta... | |
28 | -# correct: ['Terra', 'terra'] | |
29 | -# # opcional | |
30 | -# answer: Não é Marte... | |
22 | +# --------------------------------------------------------------------------- | |
23 | +- | |
24 | + ref: home-planet | |
25 | + type: text | |
26 | + title: Sistema solar | |
27 | + text: O nosso planeta chama-se planeta... | |
28 | + correct: ['Terra', 'terra'] | |
29 | + # opcional | |
30 | + answer: Não é Marte... | |
31 | 31 | |
32 | -# # --------------------------------------------------------------------------- | |
33 | -# - | |
34 | -# ref: saturn | |
35 | -# type: text-regex | |
36 | -# title: Sistema solar | |
37 | -# text: O planeta do sistema solar conhecido por ter aneis é o planeta... | |
38 | -# correct: !regex '[Ss]aturno' | |
32 | +# --------------------------------------------------------------------------- | |
33 | +- | |
34 | + ref: saturn | |
35 | + type: text-regex | |
36 | + title: Sistema solar | |
37 | + text: O planeta do sistema solar conhecido por ter aneis é o planeta... | |
38 | + correct: !regex '[Ss]aturno' | |
39 | 39 | |
40 | 40 | # --------------------------------------------------------------------------- |
41 | -# - ref: first_3_planets | |
42 | -# type: textarea | |
43 | -# title: Sistema solar | |
44 | -# text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | |
45 | -# correct: correct-first_3_planets.py | |
46 | -# # correct: correct-timeout.py | |
47 | -# # opcional | |
48 | -# answer: Vulcano, Krypton, Plutão | |
49 | -# lines: 3 | |
50 | -# timeout: 50 | |
41 | +- ref: first_3_planets | |
42 | + type: textarea | |
43 | + title: Sistema solar | |
44 | + text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | |
45 | + correct: correct-first_3_planets.py | |
46 | + # correct: correct-timeout.py | |
47 | + # opcional | |
48 | + answer: Vulcano, Krypton, Plutão | |
49 | + lines: 3 | |
50 | + timeout: 50 | ... | ... |
http-redirect.py
... | ... | @@ -16,7 +16,7 @@ from tornado import ioloop, web, httpserver |
16 | 16 | class WebRedirectApplication(web.Application): |
17 | 17 | def __init__(self, target='https://localhost'): |
18 | 18 | handlers = [ |
19 | - (r'/*', RootHandler), # redirect to https | |
19 | + (r'/', RootHandler), # redirect to https | |
20 | 20 | ] |
21 | 21 | super().__init__(handlers) |
22 | 22 | self.target = target |
... | ... | @@ -28,7 +28,7 @@ class RootHandler(web.RequestHandler): |
28 | 28 | SUPPORTED_METHODS = ['GET'] |
29 | 29 | |
30 | 30 | def get(self): |
31 | - print('Redirecting...') | |
31 | + # print('Redirecting...') | |
32 | 32 | self.redirect(self.application.target) |
33 | 33 | |
34 | 34 | ... | ... |
knowledge.py
... | ... | @@ -153,7 +153,7 @@ class StudentKnowledge(object): |
153 | 153 | if self.next_question() is None: |
154 | 154 | action = 'finished_topic' |
155 | 155 | else: |
156 | - action = 'new_question' # FIXME show comments | |
156 | + action = 'wrong' # FIXME show comments | |
157 | 157 | |
158 | 158 | else: |
159 | 159 | action = 'try_again' | ... | ... |
learnapp.py
... | ... | @@ -191,7 +191,7 @@ class LearnApp(object): |
191 | 191 | logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"') |
192 | 192 | raise e |
193 | 193 | else: |
194 | - logger.info(f'User "{uid}" started "{topic}"') | |
194 | + logger.info(f'User "{uid}" started topic "{topic}"') | |
195 | 195 | |
196 | 196 | # ------------------------------------------------------------------------ |
197 | 197 | # Fill db table 'Topic' with topics from the graph if not already there. | ... | ... |
questions.py
... | ... | @@ -363,11 +363,6 @@ class QuestionTextArea(Question): |
363 | 363 | |
364 | 364 | # =========================================================================== |
365 | 365 | class QuestionInformation(Question): |
366 | - '''An instance of QuestionInformation will always have the keys: | |
367 | - type (str) | |
368 | - text (str) | |
369 | - points (0.0) | |
370 | - ''' | |
371 | 366 | #------------------------------------------------------------------------ |
372 | 367 | def __init__(self, q): |
373 | 368 | super().__init__(q) | ... | ... |
serve.py
... | ... | @@ -44,7 +44,7 @@ class WebApplication(tornado.web.Application): |
44 | 44 | (r'/logout', LogoutHandler), |
45 | 45 | (r'/change_password', ChangePasswordHandler), |
46 | 46 | (r'/question', QuestionHandler), # renders each question |
47 | - (r'/topic/(.+)', TopicHandler), # page for exercising a topic | |
47 | + (r'/topic/(.+)', TopicHandler), # start a topic | |
48 | 48 | (r'/file/(.+)', FileHandler), # serve files, images, etc |
49 | 49 | (r'/', RootHandler), # show list of topics |
50 | 50 | ] |
... | ... | @@ -200,6 +200,8 @@ class FileHandler(BaseHandler): |
200 | 200 | # respond to AJAX to get a JSON question |
201 | 201 | # ---------------------------------------------------------------------------- |
202 | 202 | class QuestionHandler(BaseHandler): |
203 | + SUPPORTED_METHODS = ['GET', 'POST'] | |
204 | + | |
203 | 205 | templates = { |
204 | 206 | 'checkbox': 'question-checkbox.html', |
205 | 207 | 'radio': 'question-radio.html', |
... | ... | @@ -218,20 +220,20 @@ class QuestionHandler(BaseHandler): |
218 | 220 | def get(self): |
219 | 221 | logging.debug('QuestionHandler.get()') |
220 | 222 | user = self.current_user |
223 | + q = self.learn.get_current_question(user) | |
224 | + question_html = self.render_string(self.templates[q['type']], | |
225 | + question=q, md=md_to_html) | |
221 | 226 | |
222 | - question = self.learn.get_current_question(user) | |
223 | - | |
224 | - question_html = self.render_string(self.templates[question['type']], | |
225 | - question=question, md=md_to_html) | |
226 | - | |
227 | - self.write({ | |
227 | + response = { | |
228 | 228 | 'method': 'new_question', |
229 | 229 | 'params': { |
230 | + 'type': q['type'], | |
230 | 231 | 'question': tornado.escape.to_unicode(question_html), |
231 | 232 | 'progress': self.learn.get_student_progress(user), |
232 | - 'tries': question['tries'], | |
233 | + 'tries': q['tries'], | |
233 | 234 | }, |
234 | - }) | |
235 | + } | |
236 | + self.write(response) | |
235 | 237 | |
236 | 238 | # --- post answer, returns what to do next: shake, new_question, finished |
237 | 239 | @tornado.web.authenticated |
... | ... | @@ -253,57 +255,72 @@ class QuestionHandler(BaseHandler): |
253 | 255 | # and get corrected question |
254 | 256 | q, action = await self.learn.check_answer(user, answer) |
255 | 257 | |
256 | - # get next question (same, new or None) | |
257 | - question = self.learn.get_current_question(user) | |
258 | + print(action) | |
258 | 259 | |
259 | 260 | if action == 'try_again': |
260 | 261 | comments_html = self.render_string('comments.html', |
261 | - comments=question['comments'], md=md_to_html) | |
262 | - self.write({ | |
263 | - 'method': 'try_again', # FIXME js | |
262 | + comments=q['comments'], md=md_to_html) | |
263 | + | |
264 | + response = { | |
265 | + 'method': 'try_again', | |
264 | 266 | 'params': { |
265 | 267 | 'progress': self.learn.get_student_progress(user), |
266 | 268 | 'comments': tornado.escape.to_unicode(comments_html), # FIXME |
267 | - 'tries': question['tries'], | |
269 | + 'tries': q['tries'], | |
268 | 270 | } |
269 | - }) | |
270 | - | |
271 | - # if action == 'wrong': | |
272 | - # comments_html = self.render_string('comments.html', | |
273 | - # comments=question['comments'], md=md_to_html) | |
274 | - # template = self.templates[question['type']] | |
275 | - # question_html = self.render_string(template, question=question, md=md_to_html) | |
276 | - # self.write({ | |
277 | - # 'method': 'wrong', # FIXME js | |
278 | - # 'params': { | |
279 | - # 'question': tornado.escape.to_unicode(question_html), | |
280 | - # 'progress': self.learn.get_student_progress(user), | |
281 | - # 'comments': tornado.escape.to_unicode(comments_html), # FIXME | |
282 | - # 'tries': question['tries'], | |
283 | - # } | |
284 | - # }) | |
271 | + } | |
272 | + print(response) | |
273 | + self.write(response) | |
285 | 274 | |
286 | - elif action == 'new_question': # get next question in the topic | |
287 | - template = self.templates[question['type']] | |
288 | - question_html = self.render_string(template, | |
289 | - question=question, md=md_to_html) | |
290 | - self.write({ | |
291 | - 'method': 'new_question', | |
275 | + elif action == 'wrong': # no more tries | |
276 | + comments_html = self.render_string('comments.html', | |
277 | + comments=q['comments'], md=md_to_html) | |
278 | + solution_html = self.render_string('solution.html', | |
279 | + solution=q['solution'], md=md_to_html) | |
280 | + | |
281 | + # template = self.templates[question['type']] | |
282 | + # question_html = self.render_string(template, question=question, md=md_to_html) | |
283 | + response = { | |
284 | + 'method': 'wrong', # FIXME js | |
292 | 285 | 'params': { |
293 | - 'question': tornado.escape.to_unicode(question_html), | |
286 | + # 'question': tornado.escape.to_unicode(question_html), | |
294 | 287 | 'progress': self.learn.get_student_progress(user), |
295 | - 'tries': question['tries'], | |
288 | + 'comments': tornado.escape.to_unicode(comments_html), # FIXME | |
289 | + 'solution': tornado.escape.to_unicode(solution_html), # FIXME | |
290 | + 'tries': q['tries'], | |
296 | 291 | } |
297 | - }) | |
292 | + } | |
293 | + print(response) | |
294 | + self.write(response) | |
295 | + | |
296 | + elif action == 'new_question': # get next question in the topic | |
297 | + self.get() | |
298 | + # question = self.learn.get_current_question(user) | |
299 | + | |
300 | + # template = self.templates[question['type']] | |
301 | + # question_html = self.render_string(template, | |
302 | + # question=question, md=md_to_html) | |
303 | + # response = { | |
304 | + # 'method': 'new_question', | |
305 | + # 'params': { | |
306 | + # 'type': question['type'], | |
307 | + # 'question': tornado.escape.to_unicode(question_html), | |
308 | + # 'progress': self.learn.get_student_progress(user), | |
309 | + # 'tries': question['tries'], | |
310 | + # } | |
311 | + # } | |
312 | + # print(response) | |
313 | + # self.write(response) | |
298 | 314 | |
299 | 315 | elif action == 'finished_topic': # right answer, finished topic |
300 | 316 | finished_topic_html = self.render_string('finished_topic.html') |
301 | - self.write({ | |
317 | + response = { | |
302 | 318 | 'method': 'finished_topic', |
303 | 319 | 'params': { |
304 | 320 | 'question': tornado.escape.to_unicode(finished_topic_html) |
305 | 321 | } |
306 | - }) | |
322 | + } | |
323 | + self.write(response) | |
307 | 324 | |
308 | 325 | else: |
309 | 326 | logger.error(f'Unknown action {action}') | ... | ... |
static/js/topic.js
... | ... | @@ -8,56 +8,76 @@ $.fn.extend({ |
8 | 8 | }); |
9 | 9 | |
10 | 10 | |
11 | -function new_question(question, tries, progress) { | |
11 | +function new_question(type, question, tries, progress) { | |
12 | + console.log("new_question " + type); | |
13 | + | |
12 | 14 | $("#question_div").html(question); |
13 | 15 | $("#comments").html(""); |
16 | + $("#solution").html(""); | |
17 | + if (type == "info") { | |
18 | + $("#submit").html("Continuar"); | |
19 | + } | |
20 | + else { | |
21 | + $("#submit").html("Responder"); | |
22 | + } | |
23 | + $("#submit").off(); | |
24 | + $("#submit").click(postAnswer); | |
25 | + | |
14 | 26 | $("#tries").html(tries); |
15 | 27 | $('#topic_progress').css('width', (100*progress)+'%').attr('aria-valuenow', 100*progress); |
16 | 28 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]); |
29 | + | |
17 | 30 | $('#question_div').animateCSS('bounceInDown'); |
18 | 31 | |
19 | - // enable shift+enter to submit and tab to spaces conversion | |
20 | - $("input:text, input:radio, input:checkbox").keydown(function (e) { | |
21 | - if (e.keyCode == 13) { | |
22 | - e.preventDefault(); | |
23 | - if (e.shiftKey) postQuestion(); | |
24 | - return false; | |
25 | - }}); | |
32 | + // enable shift+enter to submit | |
33 | + // $("input:text, input:radio, input:checkbox").keydown(function (e) { | |
34 | + // if (e.keyCode == 13) { | |
35 | + // e.preventDefault(); | |
36 | + // if (e.shiftKey) postQuestion(); | |
37 | + // return false; | |
38 | + // }}); | |
26 | 39 | } |
27 | 40 | |
41 | + | |
42 | + | |
28 | 43 | // updates question according to the response given by the server |
29 | 44 | function updateQuestion(response){ |
45 | + console.log('updateQuestion '+response["method"]); | |
46 | + | |
47 | + var method = response["method"]; | |
48 | + var params = response["params"]; | |
49 | + | |
30 | 50 | |
31 | - switch (response["method"]) { | |
51 | + switch (method) { | |
32 | 52 | case "new_question": |
33 | - params = response["params"]; | |
34 | - new_question(params["question"], params["tries"], params["progress"]); | |
53 | + console.log(params["type"]); | |
54 | + new_question(params["type"], params["question"], params["tries"], params["progress"]); | |
35 | 55 | break; |
36 | 56 | |
37 | 57 | case "try_again": |
38 | - $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); | |
39 | 58 | $('#question_div').animateCSS('shake'); |
40 | - $('#comments').html(response['params']['comments']); | |
41 | - $("#tries").html(response["params"]["tries"]); | |
59 | + $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); | |
60 | + $("#tries").html(params["tries"]); | |
61 | + $('#comments').html(params['comments']); | |
42 | 62 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); |
43 | 63 | break; |
44 | 64 | |
45 | - // case "wrong": | |
46 | - // $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); | |
47 | - // $('#question_div').animateCSS('shake'); | |
48 | - // $('#comments').html(response['params']['comments']); | |
49 | - // $("#tries").html(response["params"]["tries"]); | |
50 | - // MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); | |
51 | - | |
52 | - // // setTimeout(function(){ | |
53 | - // new_question(response["params"]["question"], response["params"]["tries"], response["params"]["progress"]); | |
54 | - // // }, 5000); | |
55 | - // break; | |
56 | - | |
57 | - | |
65 | + case "wrong": | |
66 | + $('#question_div').animateCSS('shake'); | |
67 | + $('#topic_progress').css('width', (100*params["progress"])+'%').attr('aria-valuenow', 100*params["progress"]); | |
68 | + $("#tries").html(params["tries"]); | |
69 | + $('#comments').html(params['comments']); | |
70 | + MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#comments"]); | |
71 | + $('#solution').html(params['solution']); | |
72 | + MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#solution"]); | |
73 | + $("fieldset").attr("disabled", "disabled"); | |
74 | + $("#submit").html("Continuar"); | |
75 | + $("#submit").off(); | |
76 | + $("#submit").click(getQuestion); | |
77 | + break; | |
58 | 78 | |
59 | 79 | case "finished_topic": |
60 | - $('#submit').css("visibility", "hidden"); | |
80 | + $('#submit').hide(); //css("visibility", "hidden"); | |
61 | 81 | $("#content").html(response["params"]["question"]); |
62 | 82 | $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100); |
63 | 83 | $("#content").animateCSS('tada'); |
... | ... | @@ -68,6 +88,8 @@ function updateQuestion(response){ |
68 | 88 | |
69 | 89 | // Get current question |
70 | 90 | function getQuestion() { |
91 | + console.log("getQuestion"); | |
92 | + | |
71 | 93 | $.ajax({ |
72 | 94 | type: "GET", |
73 | 95 | url: "/question", |
... | ... | @@ -80,7 +102,9 @@ function getQuestion() { |
80 | 102 | // Send answer and receive a response. |
81 | 103 | // The response can be a new_question or a shake if the answer is wrong, which |
82 | 104 | // is then passed to updateQuestion() |
83 | -function postQuestion() { | |
105 | +function postAnswer() { | |
106 | + console.log("postAnswer"); | |
107 | + | |
84 | 108 | if (typeof editor === 'object') |
85 | 109 | editor.save(); |
86 | 110 | |
... | ... | @@ -94,7 +118,8 @@ function postQuestion() { |
94 | 118 | }); |
95 | 119 | } |
96 | 120 | |
121 | + | |
97 | 122 | $(document).ready(function() { |
98 | 123 | getQuestion(); |
99 | - $("#submit").click(postQuestion); | |
124 | + $("#submit").click(postAnswer); | |
100 | 125 | }); | ... | ... |
templates/comments.html
templates/topic.html
... | ... | @@ -79,13 +79,14 @@ |
79 | 79 | </form> |
80 | 80 | |
81 | 81 | <div id="comments"></div> |
82 | + <div id="solution"></div> | |
82 | 83 | |
83 | 84 | </div> |
84 | 85 | </div> |
85 | 86 | |
86 | 87 | <footer class="footer"> |
87 | 88 | <div class="container"> |
88 | - <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
89 | + <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Responder</button> | |
89 | 90 | </div> |
90 | 91 | </footer> |
91 | 92 | ... | ... |