Commit 0a96984cde48d2c23d83b0cb8648e3b5391d7123
1 parent
e447d0c2
Exists in
master
and in
1 other branch
database file is now selected as a command line option, defaults to students.db
Showing
5 changed files
with
81 additions
and
47 deletions
Show diff stats
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
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(); | ... | ... |