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...

@@ -136,6 +136,10 @@ class LearnApp(object): @@ -136,6 +136,10 @@ class LearnApp(object):
136 return self.online[uid]['state'].get_topic_progress() 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 def get_title(self): 143 def get_title(self):
140 return self.depgraph.graph['title'] 144 return self.depgraph.graph['title']
141 145
@@ -150,11 +154,8 @@ class LearnApp(object): @@ -150,11 +154,8 @@ class LearnApp(object):
150 return path.join(p, topic, 'public') 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 # check answer and if correct returns new question, otherwise returns None 157 # check answer and if correct returns new question, otherwise returns None
  158 + # ------------------------------------------------------------------------
158 def check_answer(self, uid, answer): 159 def check_answer(self, uid, answer):
159 knowledge = self.online[uid]['state'] 160 knowledge = self.online[uid]['state']
160 current_question = knowledge.check_answer(answer) 161 current_question = knowledge.check_answer(answer)
@@ -14,31 +14,34 @@ import questions @@ -14,31 +14,34 @@ import questions
14 logger = logging.getLogger(__name__) 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 class Knowledge(object): 19 class Knowledge(object):
19 def __init__(self, depgraph, state={}, student=''): 20 def __init__(self, depgraph, state={}, student=''):
20 - self.student = student  
21 self.depgraph = depgraph 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 # select a topic to do 28 # select a topic to do
28 self.new_topic() 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 def new_topic(self, topic=None): 35 def new_topic(self, topic=None):
32 if topic is None: 36 if topic is None:
33 - # select the first topic that has level < 0.8  
34 for topic in self.topic_sequence: 37 for topic in self.topic_sequence:
35 if topic not in self.state or self.state[topic]['level'] < 0.8: 38 if topic not in self.state or self.state[topic]['level'] < 0.8:
36 break 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 self.current_topic = topic 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 self.questions = self.generate_questions_for_topic(topic) 45 self.questions = self.generate_questions_for_topic(topic)
43 self.current_question = None 46 self.current_question = None
44 self.finished_questions = [] 47 self.finished_questions = []
@@ -47,10 +50,8 @@ class Knowledge(object): @@ -47,10 +50,8 @@ class Knowledge(object):
47 50
48 # ------------------------------------------------------------------------ 51 # ------------------------------------------------------------------------
49 def generate_questions_for_topic(self, topic): 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 def get_current_question(self): 57 def get_current_question(self):
@@ -62,7 +63,7 @@ class Knowledge(object): @@ -62,7 +63,7 @@ class Knowledge(object):
62 63
63 # ------------------------------------------------------------------------ 64 # ------------------------------------------------------------------------
64 def get_knowledge_state(self): 65 def get_knowledge_state(self):
65 - ts = [] 66 + ts = [] # FIXME why list??
66 for t in self.topic_sequence: 67 for t in self.topic_sequence:
67 if t in self.state: 68 if t in self.state:
68 ts.append((t, self.state[t]['level'])) 69 ts.append((t, self.state[t]['level']))
@@ -97,8 +98,9 @@ class Knowledge(object): @@ -97,8 +98,9 @@ class Knowledge(object):
97 logger.debug(f'Student {self.student}: new_question({self.current_question["ref"]})') 98 logger.debug(f'Student {self.student}: new_question({self.current_question["ref"]})')
98 return self.current_question 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 def check_answer(self, answer): 104 def check_answer(self, answer):
103 question = self.current_question 105 question = self.current_question
104 if question is not None: 106 if question is not None:
@@ -161,6 +161,35 @@ class QuestionHandler(BaseHandler): @@ -161,6 +161,35 @@ class QuestionHandler(BaseHandler):
161 } 161 }
162 162
163 @tornado.web.authenticated 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 def post(self): 193 def post(self):
165 user = self.current_user 194 user = self.current_user
166 answer = self.get_body_arguments('answer') 195 answer = self.get_body_arguments('answer')
templates/learn.html
@@ -163,20 +163,20 @@ function updateQuestion(response){ @@ -163,20 +163,20 @@ function updateQuestion(response){
163 163
164 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]); 164 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]);
165 165
166 - 166 + // enable shift+enter to submit and tab to spaces conversion
167 $("input:text, input:radio, input:checkbox").keydown(function (e) { 167 $("input:text, input:radio, input:checkbox").keydown(function (e) {
168 if (e.keyCode == 13 && e.shiftKey) { 168 if (e.keyCode == 13 && e.shiftKey) {
169 e.preventDefault(); 169 e.preventDefault();
170 - getQuestion(); 170 + postQuestion();
171 } 171 }
172 }); 172 });
173 -  
174 $("textarea").keydown(function (e) { 173 $("textarea").keydown(function (e) {
175 if (e.keyCode == 13 && e.shiftKey) { // shift enter 174 if (e.keyCode == 13 && e.shiftKey) { // shift enter
176 e.preventDefault(); 175 e.preventDefault();
177 - getQuestion(); 176 + postQuestion();
178 } 177 }
179 else if (e.keyCode === 9) { // tab 178 else if (e.keyCode === 9) { // tab
  179 + e.preventDefault(); // prevent loosing focus
180 // get caret position/selection 180 // get caret position/selection
181 var start = this.selectionStart; 181 var start = this.selectionStart;
182 var end = this.selectionEnd; 182 var end = this.selectionEnd;
@@ -187,9 +187,9 @@ function updateQuestion(response){ @@ -187,9 +187,9 @@ function updateQuestion(response){
187 187
188 // put caret at right position again (add one for the tab) 188 // put caret at right position again (add one for the tab)
189 this.selectionStart = this.selectionEnd = start + 4; 189 this.selectionStart = this.selectionEnd = start + 4;
190 - e.preventDefault(); // prevent the focus lose  
191 } 190 }
192 }); 191 });
  192 +
193 // var audio = new Audio('/static/sounds/correct.mp3'); 193 // var audio = new Audio('/static/sounds/correct.mp3');
194 // audio.play(); 194 // audio.play();
195 $('#question_div').animateCSS('zoomIn'); 195 $('#question_div').animateCSS('zoomIn');
@@ -205,7 +205,7 @@ function updateQuestion(response){ @@ -205,7 +205,7 @@ function updateQuestion(response){
205 205
206 // Send answer and receive a response. 206 // Send answer and receive a response.
207 // The response can be a new_question or a shake if the answer is wrong. 207 // The response can be a new_question or a shake if the answer is wrong.
208 -function getQuestion() { 208 +function postQuestion() {
209 $.ajax({ 209 $.ajax({
210 type: "POST", 210 type: "POST",
211 url: "/question", 211 url: "/question",
@@ -217,6 +217,20 @@ function getQuestion() { @@ -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 function change_password() { 234 function change_password() {
221 $.ajax({ 235 $.ajax({
222 type: "POST", 236 type: "POST",
@@ -240,7 +254,7 @@ $(document).ready(function() { @@ -240,7 +254,7 @@ $(document).ready(function() {
240 // var audio = new Audio('/static/sounds/intro.mp3'); 254 // var audio = new Audio('/static/sounds/intro.mp3');
241 // audio.play(); 255 // audio.play();
242 getQuestion(); 256 getQuestion();
243 - $("#submit").click(getQuestion); 257 + $("#submit").click(postQuestion);
244 $('[data-toggle=offcanvas]').click(function() { 258 $('[data-toggle=offcanvas]').click(function() {
245 $('.row-offcanvas').toggleClass('active'); 259 $('.row-offcanvas').toggleClass('active');
246 }); 260 });