Commit 4f21e22aa2809b58662a64bb70bd114952abbbd4

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

- changed debug logs to show student id

- fixed enter in textarea, tabs still need fix
BUGS.md
1 1  
2 2 BUGS:
3 3  
  4 +- pymips: activar/desactivar instruções
  5 +- tabs em textarea nao funcionam correctamente (insere 1 espaco em vez de 4)
  6 +- reportar comentarios após submeter.
  7 +- logs debug mostrar user
  8 +- logs mostrar fim de topico
4 9 - textarea, text devem mostrar no html os valores iniciais de ans, se existir
5 10 - detect questions in questions.yaml without ref -> error ou generate default.
6 11 - error if demo.yaml has no topics
7   -- pymips a funcionar
8 12 - reload da página rebenta o estado.
9 13 - guardar state cada vez que topico termina
10 14 - indicar o topico actual no sidebar
11 15 - session management. close after inactive time.
12 16 - implementar xsrf. Ver [http://www.tornadoweb.org/en/stable/guide/security.html#cross-site-request-forgery-protection]()
  17 +- titulos das perguntas não suportam markdown
13 18  
14 19 TODO:
15 20  
... ... @@ -21,6 +26,7 @@ TODO:
21 26  
22 27 FIXED:
23 28  
  29 +- pymips a funcionar
24 30 - logs mostram que está a gerar cada pergunta 2 vezes...??
25 31 - letsencrypt.org
26 32 - alterar password.
... ...
app.py
... ... @@ -69,7 +69,7 @@ class LearnApp(object):
69 69 self.online[uid] = {
70 70 'name': student.name,
71 71 'number': student.id,
72   - 'state': Knowledge(self.depgraph, state),
  72 + 'state': Knowledge(self.depgraph, state=state, student=student.id)
73 73 }
74 74 logger.info(f'User "{uid}" logged in')
75 75 return True
... ...
knowledge.py
... ... @@ -16,7 +16,8 @@ logger = logging.getLogger(__name__)
16 16 # ----------------------------------------------------------------------------
17 17 # contains the kowledge state of each student.
18 18 class Knowledge(object):
19   - def __init__(self, depgraph, state={}):
  19 + def __init__(self, depgraph, state={}, student=''):
  20 + self.student = student
20 21 self.depgraph = depgraph
21 22 self.topic_sequence = nx.topological_sort(self.depgraph) # FIXME
22 23  
... ... @@ -28,12 +29,12 @@ class Knowledge(object):
28 29  
29 30 # ------------------------------------------------------------------------
30 31 def new_topic(self, topic=None):
31   - logger.debug(f'-> Knowledge.new_topic({topic})')
32 32 if topic is None:
33 33 # select the first topic that has level < 0.9
34 34 for topic in self.topic_sequence:
35 35 if topic not in self.state or self.state[topic]['level'] < 0.9:
36 36 break
  37 + logger.debug(f'Student {self.student}: new_topic({topic})')
37 38  
38 39 # FIXME if all are > 0.9, will stay in the last one forever...
39 40 self.current_topic = topic
... ... @@ -44,7 +45,8 @@ class Knowledge(object):
44 45  
45 46 # ------------------------------------------------------------------------
46 47 def generate_questions_for_topic(self, topic):
47   - logger.debug(f'-> Knowledge.generate_questions_for_topic({topic})')
  48 + logger.debug(f'Student {self.student}: generate_questions_for_topic "{topic}"')
  49 +
48 50 factory_list = self.depgraph.node[topic]['factory']
49 51 return [q.generate() for q in factory_list]
50 52  
... ... @@ -58,7 +60,7 @@ class Knowledge(object):
58 60  
59 61 # ------------------------------------------------------------------------
60 62 def get_knowledge_state(self):
61   - logger.debug('-> Knowledge.get_knowledge_state()')
  63 + # logger.debug('-> Knowledge.get_knowledge_state()')
62 64 ts = []
63 65 for t in self.topic_sequence:
64 66 if t in self.state:
... ... @@ -69,15 +71,13 @@ class Knowledge(object):
69 71  
70 72 # ------------------------------------------------------------------------
71 73 def get_topic_progress(self):
72   - logger.debug('-> Knowledge.get_topic_progress()')
  74 + # logger.debug('-> Knowledge.get_topic_progress()')
73 75 return len(self.finished_questions) / (len(self.finished_questions) + len(self.questions))
74 76  
75 77 # ------------------------------------------------------------------------
76 78 # if answer to current question is correct generates a new question
77   - # otherwise returns none
  79 + # otherwise returns None
78 80 def new_question(self):
79   - logger.debug('-> Knowledge.new_question()')
80   -
81 81 if self.current_question is None or \
82 82 self.current_question.get('grade', 0.0) > 0.9:
83 83  
... ... @@ -85,7 +85,7 @@ class Knowledge(object):
85 85 # keep going if there are no questions in the next topics
86 86 while not self.questions:
87 87 self.state[self.current_topic] = {
88   - 'level': 1.0,
  88 + 'level': 1.0, # FIXME depends on how many are correct
89 89 'date': datetime.now()
90 90 }
91 91 self.new_topic()
... ... @@ -94,15 +94,17 @@ class Knowledge(object):
94 94 self.current_question['start_time'] = datetime.now()
95 95 self.finished_questions.append(self.current_question)
96 96  
  97 + logger.debug(f'Student {self.student}: new_question({self.current_question["ref"]})')
97 98 return self.current_question
98 99  
99 100 # --- checks answer ------------------------------------------------------
100 101 # returns current question with correction, time and comments updated
101 102 def check_answer(self, answer):
102   - logger.debug(f'-> Knowledge.check_answer({answer})')
103 103 question = self.current_question
104 104 if question is not None:
105 105 question['finish_time'] = datetime.now()
106 106 question.correct(answer)
107 107  
  108 + logger.debug(f'Student {self.student}: check_answer({answer}) = {question["grade"]}')
  109 +
108 110 return question
... ...
questions.py
... ... @@ -316,7 +316,7 @@ class QuestionTextArea(Question):
316 316  
317 317 #------------------------------------------------------------------------
318 318 def __init__(self, q):
319   - logger.debug('QuestionTextArea.__init__()')
  319 + # logger.debug('QuestionTextArea.__init__()')
320 320 super().__init__(q)
321 321  
322 322 self.set_defaults({
... ...
templates/learn.html
... ... @@ -163,17 +163,32 @@ function updateQuestion(response){
163 163  
164 164 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]);
165 165  
166   - $("textarea, input:text, input:radio, input:checkbox").keydown(function (e) {
  166 +
  167 + $("input:text, input:radio, input:checkbox").keydown(function (e) {
167 168 if (e.keyCode == 13 && e.shiftKey) {
168 169 e.preventDefault();
169 170 getQuestion();
170 171 }
171   - // if (e.keyCode == 13) {
172   - // e.preventDefault();
173   - // if (e.shiftKey) {
174   - // getQuestion();
175   - // }
176   - // }
  172 + });
  173 +
  174 + $("textarea").keydown(function (e) {
  175 + if (e.keyCode == 13 && e.shiftKey) { // shift enter
  176 + e.preventDefault();
  177 + getQuestion();
  178 + }
  179 + else if (e.keyCode === 9) { // tab
  180 + // get caret position/selection
  181 + var start = this.selectionStart;
  182 + var end = this.selectionEnd;
  183 + var value = $(this).val();
  184 +
  185 + // set textarea value to: text before caret + tab + text after caret
  186 + $(this).val(value.substring(0, start) + " " + value.substring(end));
  187 +
  188 + // put caret at right position again (add one for the tab)
  189 + this.selectionStart = this.selectionEnd = start + 4;
  190 + e.preventDefault(); // prevent the focus lose
  191 + }
177 192 });
178 193 // var audio = new Audio('/static/sounds/correct.mp3');
179 194 // audio.play();
... ...