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

knowledge.py
... ... @@ -129,8 +129,10 @@ class StudentKnowledge(object):
129 129  
130 130 if grade > 0.999:
131 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 137 else:
136 138 self.wrong_answers += 1
... ... @@ -140,13 +142,15 @@ class StudentKnowledge(object):
140 142 if self.current_question['tries'] <= 0:
141 143 logger.debug("Appending new instance of this question to the end")
142 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 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 154 return q, action
151 155  
152 156  
... ...
learnapp.py
... ... @@ -58,8 +58,8 @@ class LearnApp(object):
58 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 63 self.online = dict() # online students
64 64  
65 65 self.deps = nx.DiGraph(prefix=prefix)
... ... @@ -152,7 +152,7 @@ class LearnApp(object):
152 152 topic_id=topic))
153 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 156 # finished topic, save into database
157 157 logger.info(f'User "{uid}" finished "{topic}"')
158 158 level = knowledge.get_topic_level(topic)
... ... @@ -176,9 +176,8 @@ class LearnApp(object):
176 176 s.add(a)
177 177  
178 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 207 # ------------------------------------------------------------------------
209 208 # setup and check database
210 209 # ------------------------------------------------------------------------
211   - def db_setup(self, db='students.db'):
  210 + def db_setup(self, db):
212 211 logger.info(f'Checking database "{db}":')
213 212 engine = create_engine(f'sqlite:///{db}', echo=False)
214 213 self.Session = sessionmaker(bind=engine)
... ...
questions.py
... ... @@ -42,10 +42,6 @@ class Question(dict):
42 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 45 def correct(self):
50 46 self['comments'] = ''
51 47 self['grade'] = 0.0
... ...
serve.py
... ... @@ -248,16 +248,17 @@ class QuestionHandler(BaseHandler):
248 248 answer = answer[0]
249 249  
250 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 254 # get next question (same, new or None)
254 255 question = self.learn.get_current_question(user)
255 256  
256   - if action == 'wrong':
  257 + if action == 'try_again':
257 258 comments_html = self.render_string('comments.html',
258 259 comments=question['comments'], md=md_to_html)
259 260 self.write({
260   - 'method': action,
  261 + 'method': 'try_again', # FIXME js
261 262 'params': {
262 263 'progress': self.learn.get_student_progress(user),
263 264 'comments': tornado.escape.to_unicode(comments_html), # FIXME
... ... @@ -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 284 elif action == 'new_question': # get next question in the topic
278 285 template = self.templates[question['type']]
... ... @@ -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 306 else:
291 307 logger.error(f'Unknown action {action}')
292 308  
... ... @@ -316,6 +332,8 @@ def main():
316 332 help='Path prefix under which the topic directories can be found, e.g. ~/topics')
317 333 argparser.add_argument('--port', type=int, default=8443,
318 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 337 argparser.add_argument('--debug', action='store_true',
320 338 help='Enable debug messages')
321 339 arg = argparser.parse_args()
... ... @@ -336,7 +354,7 @@ def main():
336 354 # --- start application
337 355 logging.info('Starting App')
338 356 try:
339   - learnapp = LearnApp(arg.conffile, prefix=arg.prefix)
  357 + learnapp = LearnApp(arg.conffile, prefix=arg.prefix, db=arg.db)
340 358 except Exception as e:
341 359 logging.critical('Failed to start backend application')
342 360 raise e
... ...
static/js/topic.js
... ... @@ -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 28 // updates question according to the response given by the server
11 29 function updateQuestion(response){
12 30  
13 31 switch (response["method"]) {
14 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 35 break;
33 36  
34   - case "wrong":
  37 + case "try_again":
35 38 $('#topic_progress').css('width', (100*response["params"]["progress"])+'%').attr('aria-valuenow', 100*response["params"]["progress"]);
36 39 $('#question_div').animateCSS('shake');
37 40 $('#comments').html(response['params']['comments']);
... ... @@ -39,6 +42,20 @@ function updateQuestion(response){
39 42 MathJax.Hub.Queue(["Typeset",MathJax.Hub,"#comments"]);
40 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 59 case "finished_topic":
43 60 $('#submit').css("visibility", "hidden");
44 61 $("#content").html(response["params"]["question"]);
... ... @@ -62,7 +79,7 @@ function getQuestion() {
62 79  
63 80 // Send answer and receive a response.
64 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 83 function postQuestion() {
67 84 if (typeof editor === 'object')
68 85 editor.save();
... ...