Commit 0a96984cde48d2c23d83b0cb8648e3b5391d7123

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

database file is now selected as a command line option, defaults to students.db

@@ -129,8 +129,10 @@ class StudentKnowledge(object): @@ -129,8 +129,10 @@ class StudentKnowledge(object):
129 129
130 if grade > 0.999: 130 if grade > 0.999:
131 self.correct_answers += 1 131 self.correct_answers += 1
132 - self.next_question()  
133 - action = 'new_question' 132 + if self.next_question() is None:
  133 + action = 'finished_topic'
  134 + else:
  135 + action = 'new_question'
134 136
135 else: 137 else:
136 self.wrong_answers += 1 138 self.wrong_answers += 1
@@ -140,13 +142,15 @@ class StudentKnowledge(object): @@ -140,13 +142,15 @@ class StudentKnowledge(object):
140 if self.current_question['tries'] <= 0: 142 if self.current_question['tries'] <= 0:
141 logger.debug("Appending new instance of this question to the end") 143 logger.debug("Appending new instance of this question to the end")
142 self.questions.append(self.factory[q['ref']].generate()) 144 self.questions.append(self.factory[q['ref']].generate())
143 - self.next_question()  
144 - action = 'new_question' 145 + if self.next_question() is None:
  146 + action = 'finished_topic'
  147 + else:
  148 + action = 'new_question' # FIXME show comments
145 149
146 else: 150 else:
147 - action = 'wrong' 151 + action = 'try_again'
148 152
149 - # returns answered and corrected question (not new one) 153 + # returns corrected question (not new one) which might include comments
150 return q, action 154 return q, action
151 155
152 156
@@ -58,8 +58,8 @@ class LearnApp(object): @@ -58,8 +58,8 @@ class LearnApp(object):
58 session.close() 58 session.close()
59 59
60 # ------------------------------------------------------------------------ 60 # ------------------------------------------------------------------------
61 - def __init__(self, config_files, prefix):  
62 - self.db_setup() # setup database and check students 61 + def __init__(self, config_files, prefix, db):
  62 + self.db_setup(db) # setup database and check students
63 self.online = dict() # online students 63 self.online = dict() # online students
64 64
65 self.deps = nx.DiGraph(prefix=prefix) 65 self.deps = nx.DiGraph(prefix=prefix)
@@ -152,7 +152,7 @@ class LearnApp(object): @@ -152,7 +152,7 @@ class LearnApp(object):
152 topic_id=topic)) 152 topic_id=topic))
153 logger.debug(f'Saved "{q["ref"]}" into database') 153 logger.debug(f'Saved "{q["ref"]}" into database')
154 154
155 - if knowledge.get_current_question() is None: 155 + if action == 'finished_topic':
156 # finished topic, save into database 156 # finished topic, save into database
157 logger.info(f'User "{uid}" finished "{topic}"') 157 logger.info(f'User "{uid}" finished "{topic}"')
158 level = knowledge.get_topic_level(topic) 158 level = knowledge.get_topic_level(topic)
@@ -176,9 +176,8 @@ class LearnApp(object): @@ -176,9 +176,8 @@ class LearnApp(object):
176 s.add(a) 176 s.add(a)
177 177
178 logger.debug(f'Saved topic "{topic}" into database') 178 logger.debug(f'Saved topic "{topic}" into database')
179 - action = 'finished_topic' # FIXME  
180 179
181 - return action 180 + return q, action
182 181
183 182
184 # ------------------------------------------------------------------------ 183 # ------------------------------------------------------------------------
@@ -208,7 +207,7 @@ class LearnApp(object): @@ -208,7 +207,7 @@ class LearnApp(object):
208 # ------------------------------------------------------------------------ 207 # ------------------------------------------------------------------------
209 # setup and check database 208 # setup and check database
210 # ------------------------------------------------------------------------ 209 # ------------------------------------------------------------------------
211 - def db_setup(self, db='students.db'): 210 + def db_setup(self, db):
212 logger.info(f'Checking database "{db}":') 211 logger.info(f'Checking database "{db}":')
213 engine = create_engine(f'sqlite:///{db}', echo=False) 212 engine = create_engine(f'sqlite:///{db}', echo=False)
214 self.Session = sessionmaker(bind=engine) 213 self.Session = sessionmaker(bind=engine)
@@ -42,10 +42,6 @@ class Question(dict): @@ -42,10 +42,6 @@ class Question(dict):
42 'files': {}, 42 'files': {},
43 }) 43 })
44 44
45 - # FIXME unused. do childs need do override this?  
46 - # def updateAnswer(answer=None):  
47 - # self['answer'] = answer  
48 -  
49 def correct(self): 45 def correct(self):
50 self['comments'] = '' 46 self['comments'] = ''
51 self['grade'] = 0.0 47 self['grade'] = 0.0
@@ -248,16 +248,17 @@ class QuestionHandler(BaseHandler): @@ -248,16 +248,17 @@ class QuestionHandler(BaseHandler):
248 answer = answer[0] 248 answer = answer[0]
249 249
250 # check answer in another thread (nonblocking) 250 # check answer in another thread (nonblocking)
251 - action = await self.learn.check_answer(user, answer) 251 + # and get corrected question
  252 + q, action = await self.learn.check_answer(user, answer)
252 253
253 # get next question (same, new or None) 254 # get next question (same, new or None)
254 question = self.learn.get_current_question(user) 255 question = self.learn.get_current_question(user)
255 256
256 - if action == 'wrong': 257 + if action == 'try_again':
257 comments_html = self.render_string('comments.html', 258 comments_html = self.render_string('comments.html',
258 comments=question['comments'], md=md_to_html) 259 comments=question['comments'], md=md_to_html)
259 self.write({ 260 self.write({
260 - 'method': action, 261 + 'method': 'try_again', # FIXME js
261 'params': { 262 'params': {
262 'progress': self.learn.get_student_progress(user), 263 'progress': self.learn.get_student_progress(user),
263 'comments': tornado.escape.to_unicode(comments_html), # FIXME 264 'comments': tornado.escape.to_unicode(comments_html), # FIXME
@@ -265,14 +266,20 @@ class QuestionHandler(BaseHandler): @@ -265,14 +266,20 @@ class QuestionHandler(BaseHandler):
265 } 266 }
266 }) 267 })
267 268
268 - elif action == 'finished_topic': # right answer, finished topic  
269 - finished_topic_html = self.render_string('finished_topic.html')  
270 - self.write({  
271 - 'method': 'finished_topic',  
272 - 'params': {  
273 - 'question': tornado.escape.to_unicode(finished_topic_html)  
274 - }  
275 - }) 269 + # if action == 'wrong':
  270 + # comments_html = self.render_string('comments.html',
  271 + # comments=question['comments'], md=md_to_html)
  272 + # template = self.templates[question['type']]
  273 + # question_html = self.render_string(template, question=question, md=md_to_html)
  274 + # self.write({
  275 + # 'method': 'wrong', # FIXME js
  276 + # 'params': {
  277 + # 'question': tornado.escape.to_unicode(question_html),
  278 + # 'progress': self.learn.get_student_progress(user),
  279 + # 'comments': tornado.escape.to_unicode(comments_html), # FIXME
  280 + # 'tries': question['tries'],
  281 + # }
  282 + # })
276 283
277 elif action == 'new_question': # get next question in the topic 284 elif action == 'new_question': # get next question in the topic
278 template = self.templates[question['type']] 285 template = self.templates[question['type']]
@@ -287,6 +294,15 @@ class QuestionHandler(BaseHandler): @@ -287,6 +294,15 @@ class QuestionHandler(BaseHandler):
287 } 294 }
288 }) 295 })
289 296
  297 + elif action == 'finished_topic': # right answer, finished topic
  298 + finished_topic_html = self.render_string('finished_topic.html')
  299 + self.write({
  300 + 'method': 'finished_topic',
  301 + 'params': {
  302 + 'question': tornado.escape.to_unicode(finished_topic_html)
  303 + }
  304 + })
  305 +
290 else: 306 else:
291 logger.error(f'Unknown action {action}') 307 logger.error(f'Unknown action {action}')
292 308
@@ -316,6 +332,8 @@ def main(): @@ -316,6 +332,8 @@ def main():
316 help='Path prefix under which the topic directories can be found, e.g. ~/topics') 332 help='Path prefix under which the topic directories can be found, e.g. ~/topics')
317 argparser.add_argument('--port', type=int, default=8443, 333 argparser.add_argument('--port', type=int, default=8443,
318 help='Port to be used by the HTTPS server, e.g. 8443') 334 help='Port to be used by the HTTPS server, e.g. 8443')
  335 + argparser.add_argument('--db', type=str, default='students.db',
  336 + help='SQLite3 database file, e.g. students.db')
319 argparser.add_argument('--debug', action='store_true', 337 argparser.add_argument('--debug', action='store_true',
320 help='Enable debug messages') 338 help='Enable debug messages')
321 arg = argparser.parse_args() 339 arg = argparser.parse_args()
@@ -336,7 +354,7 @@ def main(): @@ -336,7 +354,7 @@ def main():
336 # --- start application 354 # --- start application
337 logging.info('Starting App') 355 logging.info('Starting App')
338 try: 356 try:
339 - learnapp = LearnApp(arg.conffile, prefix=arg.prefix) 357 + learnapp = LearnApp(arg.conffile, prefix=arg.prefix, db=arg.db)
340 except Exception as e: 358 except Exception as e:
341 logging.critical('Failed to start backend application') 359 logging.critical('Failed to start backend application')
342 raise e 360 raise e
static/js/topic.js
@@ -7,31 +7,34 @@ $.fn.extend({ @@ -7,31 +7,34 @@ $.fn.extend({
7 } 7 }
8 }); 8 });
9 9
  10 +
  11 +function new_question(question, tries, progress) {
  12 + $("#question_div").html(question);
  13 + $("#comments").html("");
  14 + $("#tries").html(tries);
  15 + $('#topic_progress').css('width', (100*progress)+'%').attr('aria-valuenow', 100*progress);
  16 + MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]);
  17 + $('#question_div').animateCSS('bounceInDown');
  18 +
  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 + }});
  26 +}
  27 +
10 // updates question according to the response given by the server 28 // updates question according to the response given by the server
11 function updateQuestion(response){ 29 function updateQuestion(response){
12 30
13 switch (response["method"]) { 31 switch (response["method"]) {
14 case "new_question": 32 case "new_question":
15 - $("#question_div").html(response["params"]["question"]);  
16 - $("#comments").html("");  
17 - $("#tries").html(response["params"]["tries"]);  
18 -  
19 - $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]);  
20 -  
21 - MathJax.Hub.Queue(["Typeset",MathJax.Hub,"question_div"]);  
22 -  
23 - // enable shift+enter to submit and tab to spaces conversion  
24 - $("input:text, input:radio, input:checkbox").keydown(function (e) {  
25 - if (e.keyCode == 13) {  
26 - e.preventDefault();  
27 - if (e.shiftKey) postQuestion();  
28 - return false;  
29 - }});  
30 -  
31 - $('#question_div').animateCSS('bounceInDown'); 33 + params = response["params"];
  34 + new_question(params["question"], params["tries"], params["progress"]);
32 break; 35 break;
33 36
34 - case "wrong": 37 + case "try_again":
35 $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]); 38 $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]);
36 $('#question_div').animateCSS('shake'); 39 $('#question_div').animateCSS('shake');
37 $('#comments').html(response['params']['comments']); 40 $('#comments').html(response['params']['comments']);
@@ -39,6 +42,20 @@ function updateQuestion(response){ @@ -39,6 +42,20 @@ function updateQuestion(response){
39 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]); 42 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]);
40 break; 43 break;
41 44
  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 +
  58 +
42 case "finished_topic": 59 case "finished_topic":
43 $('#submit').css("visibility", "hidden"); 60 $('#submit').css("visibility", "hidden");
44 $("#content").html(response["params"]["question"]); 61 $("#content").html(response["params"]["question"]);
@@ -62,7 +79,7 @@ function getQuestion() { @@ -62,7 +79,7 @@ function getQuestion() {
62 79
63 // Send answer and receive a response. 80 // Send answer and receive a response.
64 // The response can be a new_question or a shake if the answer is wrong, which 81 // The response can be a new_question or a shake if the answer is wrong, which
65 -// is then passed to updateQuestion() 82 +// is then passed to updateQuestion()
66 function postQuestion() { 83 function postQuestion() {
67 if (typeof editor === 'object') 84 if (typeof editor === 'object')
68 editor.save(); 85 editor.save();