Commit bbe90cadaea87632f8df2251a493f1cd720c82ae
1 parent
62e18fdc
Exists in
master
and in
1 other branch
- fix crash when topic has no questions (but not yet ok).
- shows comments on wrong answer.
Showing
9 changed files
with
56 additions
and
55 deletions
Show diff stats
BUGS.md
| 1 | 1 | |
| 2 | 2 | # BUGS |
| 3 | 3 | |
| 4 | +- image brand da universidade está esbatida. | |
| 4 | 5 | - generators e correct scripts que durem muito tempo podem bloquear o loop do tornado? |
| 5 | 6 | - detect questions in questions.yaml without ref -> error ou generate default. |
| 6 | 7 | - topicos virtuais nao deveriam aparecer. na construção da árvore os sucessores seriam ligados directamente aos predecessores. |
| 7 | 8 | - Criar outra estrutura organizada em capítulos (conjuntos de tópicos). Permitir capítulos de capítulos, etc. talvez usar grafos de grafos... |
| 8 | -- error if demo.yaml has no topics | |
| 9 | 9 | - session management. close after inactive time. |
| 10 | 10 | - generators not working: bcrypt (ver blog) |
| 11 | 11 | - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. |
| ... | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | - each topic only loads a sample of K questions (max) in random order. |
| 17 | 17 | - servir imagens/ficheiros. |
| 18 | 18 | - pertuntas tipo tristate: (sim, não, não sei |
| 19 | -- forçar reload das perguntas sem ter de deitar abaixo o servidor. | |
| 20 | 19 | - reload das perguntas enquanto online. |
| 21 | 20 | - tabela de progresso de todos os alunos por topico. |
| 22 | 21 | - tabela com perguntas / quantidade de respostas certas/erradas. |
| ... | ... | @@ -31,6 +30,7 @@ |
| 31 | 30 | |
| 32 | 31 | # FIXED |
| 33 | 32 | |
| 33 | +- error if demo.yaml has no topics | |
| 34 | 34 | - update de fontawesome para versão 5.0.6. |
| 35 | 35 | - remover learn.css uma vez que nao é usado em lado nenhum? |
| 36 | 36 | - check if user already logged in | ... | ... |
knowledge.py
| ... | ... | @@ -32,7 +32,7 @@ class StudentKnowledge(object): |
| 32 | 32 | now = datetime.now() |
| 33 | 33 | for s in state.values(): |
| 34 | 34 | dt = now - s['date'] |
| 35 | - s['level'] *= 0.975 ** dt.days # forgetting factor | |
| 35 | + s['level'] *= 0.8 ** dt.days # forgetting factor 0.95 | |
| 36 | 36 | |
| 37 | 37 | # compute recommended sequence of topics ['a', 'b', ...] |
| 38 | 38 | self.topic_sequence = list(nx.topological_sort(self.deps)) |
| ... | ... | @@ -45,7 +45,7 @@ class StudentKnowledge(object): |
| 45 | 45 | def unlock_topics(self): |
| 46 | 46 | # minimum level that the dependencies of a topic must have |
| 47 | 47 | # for the topic to be unlocked. |
| 48 | - min_level = 0.01 | |
| 48 | + min_level = 0.2 | |
| 49 | 49 | |
| 50 | 50 | for topic in self.topic_sequence: |
| 51 | 51 | if topic not in self.state: # if locked |
| ... | ... | @@ -75,7 +75,6 @@ class StudentKnowledge(object): |
| 75 | 75 | return False |
| 76 | 76 | |
| 77 | 77 | self.current_topic = topic |
| 78 | - # logger.info(f'Topic set to "{topic}"') | |
| 79 | 78 | |
| 80 | 79 | # generate question instances for current topic |
| 81 | 80 | factory = self.deps.node[topic]['factory'] |
| ... | ... | @@ -84,9 +83,14 @@ class StudentKnowledge(object): |
| 84 | 83 | self.questions = [factory[qref].generate() for qref in questionlist] |
| 85 | 84 | self.finished_questions = [] |
| 86 | 85 | |
| 87 | - self.current_question = self.questions.pop(0) # FIXME crash if empty | |
| 88 | - self.current_question['start_time'] = datetime.now() | |
| 89 | - return True | |
| 86 | + try: | |
| 87 | + self.current_question = self.questions.pop(0) # FIXME crash if empty | |
| 88 | + except IndexError: | |
| 89 | + self.finish_topic() | |
| 90 | + return False | |
| 91 | + else: | |
| 92 | + self.current_question['start_time'] = datetime.now() | |
| 93 | + return True | |
| 90 | 94 | |
| 91 | 95 | # ------------------------------------------------------------------------ |
| 92 | 96 | # The topic has finished and there are no more questions. | ... | ... |
learnapp.py
| ... | ... | @@ -305,6 +305,6 @@ def build_dependency_graph(config={}): |
| 305 | 305 | q['path'] = fullpath # fullpath added to each question |
| 306 | 306 | tnode['factory'][q['ref']] = QFactory(q) |
| 307 | 307 | |
| 308 | - logger.info(f'{len(tnode["questions"]):6} from {ref}') | |
| 308 | + logger.info(f'{len(tnode["questions"]):6} {ref}') | |
| 309 | 309 | |
| 310 | 310 | return g | ... | ... |
serve.py
| ... | ... | @@ -142,6 +142,7 @@ class TopicHandler(BaseHandler): |
| 142 | 142 | self.redirect('/') |
| 143 | 143 | |
| 144 | 144 | # ---------------------------------------------------------------------------- |
| 145 | +# FIXME | |
| 145 | 146 | class FileHandler(BaseHandler): |
| 146 | 147 | @tornado.web.authenticated |
| 147 | 148 | def get(self, filename): |
| ... | ... | @@ -176,36 +177,6 @@ class QuestionHandler(BaseHandler): |
| 176 | 177 | # 'alert': '', FIXME |
| 177 | 178 | } |
| 178 | 179 | |
| 179 | - def new_question(self, user): | |
| 180 | - question = self.learn.get_student_question(user) # Question | |
| 181 | - template = self.templates[question['type']] | |
| 182 | - question_html = self.render_string(template, question=question, md=md_to_html) | |
| 183 | - | |
| 184 | - return { | |
| 185 | - 'method': 'new_question', | |
| 186 | - 'params': { | |
| 187 | - 'question': tornado.escape.to_unicode(question_html), | |
| 188 | - 'progress': self.learn.get_student_progress(user), | |
| 189 | - } | |
| 190 | - } | |
| 191 | - | |
| 192 | - def wrong_answer(self, user): | |
| 193 | - progress = self.learn.get_student_progress(user) # in the current topic | |
| 194 | - return { | |
| 195 | - 'method': 'shake', | |
| 196 | - 'params': { | |
| 197 | - 'progress': progress, | |
| 198 | - } | |
| 199 | - } | |
| 200 | - | |
| 201 | - def finished_topic(self, user): # FIXME user unused | |
| 202 | - return { | |
| 203 | - 'method': 'finished_topic', | |
| 204 | - 'params': { # FIXME no html here please! | |
| 205 | - 'question': f'<img src="/static/trophy.svg" alt="trophy" class="img-fluid mx-auto d-block" width="35%">' | |
| 206 | - } | |
| 207 | - } | |
| 208 | - | |
| 209 | 180 | @tornado.web.authenticated |
| 210 | 181 | def get(self): |
| 211 | 182 | logging.debug('QuestionHandler.get()') |
| ... | ... | @@ -236,7 +207,7 @@ class QuestionHandler(BaseHandler): |
| 236 | 207 | else: |
| 237 | 208 | # answers returned in a list. fix depending on question type |
| 238 | 209 | qtype = self.learn.get_student_question_type(user) |
| 239 | - if qtype in ('success', 'information', 'info'): # FIXME danger... | |
| 210 | + if qtype in ('success', 'information', 'info'): # FIXME unused? | |
| 240 | 211 | answer = None |
| 241 | 212 | elif qtype != 'checkbox': # radio, text, textarea, ... |
| 242 | 213 | answer = answer[0] |
| ... | ... | @@ -244,13 +215,35 @@ class QuestionHandler(BaseHandler): |
| 244 | 215 | grade = self.learn.check_answer(user, answer) |
| 245 | 216 | question = self.learn.get_student_question(user) |
| 246 | 217 | |
| 247 | - if question is None: | |
| 248 | - self.write(self.finished_topic(user)) | |
| 249 | - elif grade > 0.999: | |
| 250 | - self.write(self.new_question(user)) | |
| 251 | - else: | |
| 252 | - self.write(self.wrong_answer(user)) | |
| 253 | - | |
| 218 | + if grade <= 0.999: # wrong answer | |
| 219 | + comments_html = self.render_string('comments.html', comments=question['comments'], md=md_to_html) | |
| 220 | + self.write({ | |
| 221 | + 'method': 'shake', | |
| 222 | + 'params': { | |
| 223 | + 'progress': self.learn.get_student_progress(user), | |
| 224 | + 'comments': tornado.escape.to_unicode(comments_html), # FIXME | |
| 225 | + } | |
| 226 | + }) | |
| 227 | + else: # answer is correct | |
| 228 | + if question is None: # finished topic | |
| 229 | + finished_topic_html = self.render_string('finished_topic.html') | |
| 230 | + self.write({ | |
| 231 | + 'method': 'finished_topic', | |
| 232 | + 'params': { | |
| 233 | + 'question': tornado.escape.to_unicode(finished_topic_html) | |
| 234 | + } | |
| 235 | + }) | |
| 236 | + | |
| 237 | + else: # continue with a new question | |
| 238 | + template = self.templates[question['type']] | |
| 239 | + question_html = self.render_string(template, question=question, md=md_to_html) | |
| 240 | + self.write({ | |
| 241 | + 'method': 'new_question', | |
| 242 | + 'params': { | |
| 243 | + 'question': tornado.escape.to_unicode(question_html), | |
| 244 | + 'progress': self.learn.get_student_progress(user), | |
| 245 | + } | |
| 246 | + }) | |
| 254 | 247 | |
| 255 | 248 | # ------------------------------------------------------------------------- |
| 256 | 249 | # Tornado web server | ... | ... |
static/css/topic.css
| ... | ... | @@ -7,16 +7,16 @@ |
| 7 | 7 | body { |
| 8 | 8 | margin: 0; |
| 9 | 9 | padding-top: 0px; |
| 10 | - margin-bottom: 60px; /* Margin bottom by footer height */ | |
| 10 | + margin-bottom: 90px; /* Margin bottom by footer height */ | |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | 13 | .footer { |
| 14 | 14 | position: absolute; |
| 15 | 15 | bottom: 0; |
| 16 | 16 | width: 100%; |
| 17 | - height: 40px; | |
| 17 | + height: 70px; | |
| 18 | 18 | line-height: 60px; |
| 19 | - background-color: #f5f5f5; | |
| 19 | + /*background-color: #f5f5f5;*/ | |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | html { | ... | ... |
static/js/maintopics.js
static/js/topic.js
| ... | ... | @@ -12,6 +12,7 @@ function updateQuestion(response){ |
| 12 | 12 | switch (response["method"]) { |
| 13 | 13 | case "new_question": |
| 14 | 14 | $("#question_div").html(response["params"]["question"]); |
| 15 | + $("#comments").html(""); | |
| 15 | 16 | $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); |
| 16 | 17 | |
| 17 | 18 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]); |
| ... | ... | @@ -46,6 +47,8 @@ function updateQuestion(response){ |
| 46 | 47 | case "shake": |
| 47 | 48 | $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); |
| 48 | 49 | $('#question_div').animateCSS('shake'); |
| 50 | + $('#comments').html(response['params']['comments']); | |
| 51 | + MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); | |
| 49 | 52 | break; |
| 50 | 53 | |
| 51 | 54 | case "finished_topic": | ... | ... |
templates/notification.html
templates/topic.html
| ... | ... | @@ -83,14 +83,17 @@ |
| 83 | 83 | <div id="question_div"></div> |
| 84 | 84 | </form> |
| 85 | 85 | |
| 86 | - <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
| 86 | + <div id="comments"></div> | |
| 87 | + | |
| 87 | 88 | </div> |
| 88 | 89 | </div> |
| 89 | 90 | |
| 90 | 91 | <footer class="footer"> |
| 91 | 92 | <div class="container"> |
| 93 | + <button class="btn btn-primary btn-lg btn-block my-3" id="submit" data-toggle="tooltip" data-placement="right" title="Shift-Enter">Continuar</button> | |
| 94 | +<!-- | |
| 92 | 95 | <span class="text-muted"></span> |
| 93 | - </div> | |
| 96 | + --> </div> | |
| 94 | 97 | </footer> |
| 95 | 98 | |
| 96 | 99 | </body> | ... | ... |