Commit 987cf2893945b1f49c5fa56cefbf68ad8922fc72

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

- trying to fix knowledge.py and GET response. not yet done...

app.py
... ... @@ -136,6 +136,10 @@ class LearnApp(object):
136 136 return self.online[uid]['state'].get_topic_progress()
137 137  
138 138 # ------------------------------------------------------------------------
  139 + def get_student_question(self, uid):
  140 + return self.online[uid]['state'].get_current_question() # dict
  141 +
  142 + # ------------------------------------------------------------------------
139 143 def get_title(self):
140 144 return self.depgraph.graph['title']
141 145  
... ... @@ -150,11 +154,8 @@ class LearnApp(object):
150 154 return path.join(p, topic, 'public')
151 155  
152 156 # ------------------------------------------------------------------------
153   - # def get_current_question(self, uid):
154   - # return self.online[uid]['state'].current_question
155   -
156   - # ------------------------------------------------------------------------
157 157 # check answer and if correct returns new question, otherwise returns None
  158 + # ------------------------------------------------------------------------
158 159 def check_answer(self, uid, answer):
159 160 knowledge = self.online[uid]['state']
160 161 current_question = knowledge.check_answer(answer)
... ...
knowledge.py
... ... @@ -14,31 +14,34 @@ import questions
14 14 logger = logging.getLogger(__name__)
15 15  
16 16 # ----------------------------------------------------------------------------
17   -# contains the kowledge state of each student.
  17 +# kowledge state of each student....??
  18 +# ----------------------------------------------------------------------------
18 19 class Knowledge(object):
19 20 def __init__(self, depgraph, state={}, student=''):
20   - self.student = student
21 21 self.depgraph = depgraph
22   - self.topic_sequence = nx.topological_sort(self.depgraph) # FIXME
  22 + self.state = state # {'topic_id': {'level':0.5, 'date': datetime}, ...}
  23 + self.student = student
23 24  
24   - # state = {'topic_id': {'level':0.5, 'date': datetime}, ...}
25   - self.state = state
  25 + # compute recommended sequence of topics (FIXME)
  26 + self.topic_sequence = nx.topological_sort(self.depgraph)
26 27  
27 28 # select a topic to do
28 29 self.new_topic()
29 30  
30 31 # ------------------------------------------------------------------------
  32 + # Start a new topic. If not provided, selects the first with level < 0.8
  33 + # If all levels > 0.8, will stay in the last one forever...
  34 + # ------------------------------------------------------------------------
31 35 def new_topic(self, topic=None):
32 36 if topic is None:
33   - # select the first topic that has level < 0.8
34 37 for topic in self.topic_sequence:
35 38 if topic not in self.state or self.state[topic]['level'] < 0.8:
36 39 break
37   - logger.debug(f'Student {self.student}: new_topic({topic})')
38 40  
39   - # FIXME if all are > 0.9, will stay in the last one forever...
  41 + logger.info(f'Student {self.student} new topic "{topic}"')
  42 +
40 43 self.current_topic = topic
41   - self.current_topic_idx = self.topic_sequence.index(topic)
  44 + # self.current_topic_idx = self.topic_sequence.index(topic)
42 45 self.questions = self.generate_questions_for_topic(topic)
43 46 self.current_question = None
44 47 self.finished_questions = []
... ... @@ -47,10 +50,8 @@ class Knowledge(object):
47 50  
48 51 # ------------------------------------------------------------------------
49 52 def generate_questions_for_topic(self, topic):
50   - logger.debug(f'Student {self.student}: generate_questions_for_topic "{topic}"')
51   -
52   - factory_list = self.depgraph.node[topic]['factory']
53   - return [q.generate() for q in factory_list]
  53 + factory = self.depgraph.node[topic]['factory']
  54 + return [q.generate() for q in factory]
54 55  
55 56 # ------------------------------------------------------------------------
56 57 def get_current_question(self):
... ... @@ -62,7 +63,7 @@ class Knowledge(object):
62 63  
63 64 # ------------------------------------------------------------------------
64 65 def get_knowledge_state(self):
65   - ts = []
  66 + ts = [] # FIXME why list??
66 67 for t in self.topic_sequence:
67 68 if t in self.state:
68 69 ts.append((t, self.state[t]['level']))
... ... @@ -97,8 +98,9 @@ class Knowledge(object):
97 98 logger.debug(f'Student {self.student}: new_question({self.current_question["ref"]})')
98 99 return self.current_question
99 100  
100   - # --- checks answer ------------------------------------------------------
101   - # returns current question with correction, time and comments updated
  101 + # ------------------------------------------------------------------------
  102 + # returns the current question with correction, time and comments updated
  103 + # ------------------------------------------------------------------------
102 104 def check_answer(self, answer):
103 105 question = self.current_question
104 106 if question is not None:
... ...
serve.py
... ... @@ -161,6 +161,35 @@ class QuestionHandler(BaseHandler):
161 161 }
162 162  
163 163 @tornado.web.authenticated
  164 + def get(self):
  165 + user = self.current_user
  166 + state = self.learn.get_student_state(user) # all topics
  167 + progress = self.learn.get_student_progress(user) # float
  168 + question = self.learn.get_current_question(user)
  169 + print(question) # FIXME cant get current question
  170 +
  171 + question_html = self.render_string(
  172 + self.templates[question['type']],
  173 + question=question, # dictionary with the question
  174 + md=md, # function that renders markdown to html
  175 + )
  176 + topics_html = self.render_string('topics.html',
  177 + state=state,
  178 + topicname=self.learn.get_topic_name, # translate ref to names
  179 + )
  180 + print(topics_html)
  181 + print(question_html)
  182 + self.write({
  183 + 'method': 'new_question',
  184 + 'params': {
  185 + 'question': tornado.escape.to_unicode(question_html),
  186 + 'state': tornado.escape.to_unicode(topics_html),
  187 + 'progress': progress,
  188 + }
  189 + })
  190 +
  191 + # posting can change state and return new question
  192 + @tornado.web.authenticated
164 193 def post(self):
165 194 user = self.current_user
166 195 answer = self.get_body_arguments('answer')
... ...
templates/learn.html
... ... @@ -163,20 +163,20 @@ function updateQuestion(response){
163 163  
164 164 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]);
165 165  
166   -
  166 + // enable shift+enter to submit and tab to spaces conversion
167 167 $("input:text, input:radio, input:checkbox").keydown(function (e) {
168 168 if (e.keyCode == 13 && e.shiftKey) {
169 169 e.preventDefault();
170   - getQuestion();
  170 + postQuestion();
171 171 }
172 172 });
173   -
174 173 $("textarea").keydown(function (e) {
175 174 if (e.keyCode == 13 && e.shiftKey) { // shift enter
176 175 e.preventDefault();
177   - getQuestion();
  176 + postQuestion();
178 177 }
179 178 else if (e.keyCode === 9) { // tab
  179 + e.preventDefault(); // prevent loosing focus
180 180 // get caret position/selection
181 181 var start = this.selectionStart;
182 182 var end = this.selectionEnd;
... ... @@ -187,9 +187,9 @@ function updateQuestion(response){
187 187  
188 188 // put caret at right position again (add one for the tab)
189 189 this.selectionStart = this.selectionEnd = start + 4;
190   - e.preventDefault(); // prevent the focus lose
191 190 }
192 191 });
  192 +
193 193 // var audio = new Audio('/static/sounds/correct.mp3');
194 194 // audio.play();
195 195 $('#question_div').animateCSS('zoomIn');
... ... @@ -205,7 +205,7 @@ function updateQuestion(response){
205 205  
206 206 // Send answer and receive a response.
207 207 // The response can be a new_question or a shake if the answer is wrong.
208   -function getQuestion() {
  208 +function postQuestion() {
209 209 $.ajax({
210 210 type: "POST",
211 211 url: "/question",
... ... @@ -217,6 +217,20 @@ function getQuestion() {
217 217 });
218 218 }
219 219  
  220 +// Send answer and receive a response.
  221 +// The response can be a new_question or a shake if the answer is wrong.
  222 +function getQuestion() {
  223 + $.ajax({
  224 + // type: "GET",
  225 + url: "/question",
  226 + // headers: {"X-XSRFToken": token},
  227 + // data: $("#question_form").serialize(), // {'a':10,'b':20},
  228 + dataType: "json", // expected from server
  229 + success: updateQuestion,
  230 + error: function() {alert("O servidor não responde.");}
  231 + });
  232 +}
  233 +
220 234 function change_password() {
221 235 $.ajax({
222 236 type: "POST",
... ... @@ -240,7 +254,7 @@ $(document).ready(function() {
240 254 // var audio = new Audio('/static/sounds/intro.mp3');
241 255 // audio.play();
242 256 getQuestion();
243   - $("#submit").click(getQuestion);
  257 + $("#submit").click(postQuestion);
244 258 $('[data-toggle=offcanvas]').click(function() {
245 259 $('.row-offcanvas').toggleClass('active');
246 260 });
... ...