Commit dbdd58fe15e1cd88fb28cf6a13f13b5447cdca79
1 parent
bf8ade7a
Exists in
master
and in
1 other branch
- added option 'append_wrong' to enable/disable appending new instance of questi…
…ons when answered wrong. - added option 'max_tries'. - added option 'shuffle' to que order of the questions in a topic. - images are no longer in a html figure tag, and are now centered.
Showing
6 changed files
with
41 additions
and
21 deletions
Show diff stats
BUGS.md
1 | 1 | |
2 | 2 | # BUGS |
3 | 3 | |
4 | +- nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido. | |
5 | +- ocorreu uma vez o sqlalchemy dar mesg erro a indicar que as threads sao diferents quando se faz o get da primeira pergunta do topico. Muitas vezes nao mostar erro, mas a pagina da erro ou fica em branco... | |
6 | + | |
7 | +- mathjax, formulas $$f(x)$$ nas opções de escolha multipla, não ficam centradas em toda a coluna mas apenas na largura do parágrafo. | |
4 | 8 | - mostrar feedback/solucoes quando acerta, ou excede max tries. |
5 | 9 | - default prefix should be obtained from each course (yaml conf)? |
6 | 10 | - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. | ... | ... |
knowledge.py
... | ... | @@ -71,13 +71,14 @@ class StudentKnowledge(object): |
71 | 71 | # questions: list of generated questions to do in the topic |
72 | 72 | # current_question: the current question to be presented |
73 | 73 | # ------------------------------------------------------------------------ |
74 | - async def init_topic(self, topic): | |
75 | - logger.debug(f'StudentKnowledge.init_topic({topic})') | |
74 | + # FIXME async mas nao tem awaits... | |
75 | + async def start_topic(self, topic): | |
76 | + logger.debug(f'StudentKnowledge.start_topic({topic})') | |
76 | 77 | |
77 | 78 | # do not allow locked topics |
78 | 79 | if self.is_locked(topic): |
79 | 80 | logger.debug(f'Topic {topic} is locked') |
80 | - return | |
81 | + return False | |
81 | 82 | |
82 | 83 | # starting new topic |
83 | 84 | self.current_topic = topic |
... | ... | @@ -85,7 +86,11 @@ class StudentKnowledge(object): |
85 | 86 | self.wrong_answers = 0 |
86 | 87 | |
87 | 88 | t = self.deps.node[topic] |
88 | - questions = random.sample(t['questions'], k=t['choose']) | |
89 | + k = t['choose'] | |
90 | + if t['shuffle']: | |
91 | + questions = random.sample(t['questions'], k=k) | |
92 | + else: | |
93 | + questions = t['questions'][:k] | |
89 | 94 | logger.debug(f'Questions: {", ".join(questions)}') |
90 | 95 | |
91 | 96 | # generate instances of questions |
... | ... | @@ -94,6 +99,7 @@ class StudentKnowledge(object): |
94 | 99 | |
95 | 100 | # get first question |
96 | 101 | self.next_question() |
102 | + return True | |
97 | 103 | |
98 | 104 | |
99 | 105 | # ------------------------------------------------------------------------ |
... | ... | @@ -140,8 +146,10 @@ class StudentKnowledge(object): |
140 | 146 | logger.debug(f'Wrong answers = {self.wrong_answers}; Tries = {self.current_question["tries"]}') |
141 | 147 | |
142 | 148 | if self.current_question['tries'] <= 0: |
143 | - logger.debug("Appending new instance of this question to the end") | |
144 | - self.questions.append(self.factory[q['ref']].generate()) | |
149 | + if self.current_question['append_wrong']: | |
150 | + logger.debug("Appending new instance of this question to the end") | |
151 | + self.questions.append(self.factory[q['ref']].generate()) | |
152 | + | |
145 | 153 | if self.next_question() is None: |
146 | 154 | action = 'finished_topic' |
147 | 155 | else: |
... | ... | @@ -165,7 +173,8 @@ class StudentKnowledge(object): |
165 | 173 | self.finish_topic() |
166 | 174 | else: |
167 | 175 | self.current_question['start_time'] = datetime.now() |
168 | - self.current_question['tries'] = self.current_question.get('max_tries', 3) # FIXME hardcoded 3 | |
176 | + default_maxtries = self.deps.nodes[self.current_topic]['max_tries'] | |
177 | + self.current_question['tries'] = self.current_question.get('max_tries', default_maxtries) | |
169 | 178 | logger.debug(f'Next question is "{self.current_question["ref"]}"') |
170 | 179 | |
171 | 180 | return self.current_question # question or None | ... | ... |
learnapp.py
... | ... | @@ -186,7 +186,7 @@ class LearnApp(object): |
186 | 186 | async def start_topic(self, uid, topic): |
187 | 187 | student = self.online[uid]['state'] |
188 | 188 | try: |
189 | - await student.init_topic(topic) | |
189 | + await student.start_topic(topic) | |
190 | 190 | except KeyError as e: |
191 | 191 | logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"') |
192 | 192 | raise e |
... | ... | @@ -242,6 +242,8 @@ class LearnApp(object): |
242 | 242 | default_shuffle = config.get('shuffle', True) |
243 | 243 | default_choose = config.get('choose', 9999) |
244 | 244 | default_forgetting_factor = config.get('forgetting_factor', 1.0) |
245 | + default_maxtries = config.get('max_tries', 3) | |
246 | + default_append_wrong = config.get('append_wrong', True) | |
245 | 247 | |
246 | 248 | # iterate over topics and populate graph |
247 | 249 | topics = config.get('topics', {}) |
... | ... | @@ -257,8 +259,10 @@ class LearnApp(object): |
257 | 259 | t['path'] = path.join(g.graph['prefix'], tref) # prefix/topic |
258 | 260 | t['file'] = attr.get('file', default_file) # questions.yaml |
259 | 261 | t['shuffle'] = attr.get('shuffle', default_shuffle) |
262 | + t['max_tries'] = attr.get('max_tries', default_maxtries) | |
260 | 263 | t['forgetting_factor'] = attr.get('forgetting_factor', default_forgetting_factor) |
261 | 264 | t['choose'] = attr.get('choose', default_choose) |
265 | + t['append_wrong'] = attr.get('append_wrong', default_append_wrong) | |
262 | 266 | t['questions'] = attr.get('questions', []) |
263 | 267 | |
264 | 268 | logger.info(f'Loaded {g.number_of_nodes()} topics') |
... | ... | @@ -286,6 +290,7 @@ class LearnApp(object): |
286 | 290 | qref = q.get('ref', str(i)) # ref or number |
287 | 291 | q['ref'] = tref + ':' + qref |
288 | 292 | q['path'] = topicpath |
293 | + q.setdefault('append_wrong', t['append_wrong']) | |
289 | 294 | |
290 | 295 | # if questions are left undefined, include all. |
291 | 296 | if not t['questions']: | ... | ... |
serve.py
... | ... | @@ -149,6 +149,8 @@ class RootHandler(BaseHandler): |
149 | 149 | # Start a given topic: /topic/... |
150 | 150 | # ---------------------------------------------------------------------------- |
151 | 151 | class TopicHandler(BaseHandler): |
152 | + SUPPORTED_METHODS = ['GET'] | |
153 | + | |
152 | 154 | @tornado.web.authenticated |
153 | 155 | async def get(self, topic): |
154 | 156 | uid = self.current_user | ... | ... |
templates/question.html
tools.py
... | ... | @@ -102,18 +102,18 @@ class HighlightRenderer(mistune.Renderer): |
102 | 102 | def image(self, src, title, alt): |
103 | 103 | alt = mistune.escape(alt, quote=True) |
104 | 104 | title = mistune.escape(title or '', quote=True) |
105 | - if title: | |
106 | - caption = f'<figcaption class="figure-caption">{title}</figcaption>' | |
107 | - else: | |
108 | - caption = '' | |
109 | - | |
110 | - return f''' | |
111 | - <figure class="figure"> | |
112 | - <img src="/file/{src}" class="figure-img img-fluid rounded" alt="{alt}" title="{title}"> | |
113 | - {caption} | |
114 | - </figure> | |
115 | - ''' | |
116 | - # return f'<img src="/file/{src}" class="img-fluid mx-auto d-block" alt="{alt}" title="{title}">' | |
105 | + # if title: | |
106 | + # caption = f'<figcaption class="figure-caption">{title}</figcaption>' | |
107 | + # else: | |
108 | + # caption = '' | |
109 | + | |
110 | + # return f''' | |
111 | + # <figure class="figure"> | |
112 | + # <img src="/file/{src}" class="figure-img img-fluid rounded" alt="{alt}" title="{title}"> | |
113 | + # {caption} | |
114 | + # </figure> | |
115 | + # ''' | |
116 | + return f'<img src="/file/{src}" class="img-fluid mx-auto d-block" alt="{alt}" title="{title}">' | |
117 | 117 | |
118 | 118 | # Pass math through unaltered - mathjax does the rendering in the browser |
119 | 119 | def block_math(self, text): | ... | ... |