Commit 9aeb5485618afee8d771f689cf68305cfc76af77

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

- modified how post questions behave: wait feedback then move to next question.

not yet functional!
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
1 1 {% autoescape %}
2 2  
3 3 {% if comments %}
4   -<div class="card border-danger mb-3">
5   - <div class="card-body text-danger">
6   - <p class="card-text">{{ md(comments) }}</p>
7   - </div>
  4 +<div class="alert alert-warning">
  5 + {{ md(comments) }}
8 6 </div>
9 7 {% end %}
... ...
templates/solution.html 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +{% autoescape %}
  2 +
  3 +{% if solution %}
  4 +<div class="alert alert-danger">
  5 + <h4 class="alert-heading">Solução</h4>
  6 + {{ md(solution) }}
  7 +</div>
  8 +{% end %}
... ...
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  
... ...