Commit cc63d37e7b4dad1a1a6ca42d8eaba062f2ed744c
1 parent
a9131008
Exists in
master
and in
1 other branch
fix error where topics declared in chapters but not in goals were not shown.
fix error where finishing a course would try to start empty course. goals that are chapters will recursively import dependencies.
Showing
4 changed files
with
21 additions
and
10 deletions
Show diff stats
BUGS.md
| 1 | 1 | ||
| 2 | # BUGS | 2 | # BUGS |
| 3 | 3 | ||
| 4 | -- goals se forem do tipo chapter deve importar todas as dependencias do chapter (e não mostrar chapters?). | ||
| 5 | - nao esta a seguir o max_tries definido no ficheiro de dependencias. | 4 | - nao esta a seguir o max_tries definido no ficheiro de dependencias. |
| 6 | - devia mostrar timeout para o aluno saber a razao. | 5 | - devia mostrar timeout para o aluno saber a razao. |
| 7 | - permitir configuracao para escolher entre static files locais ou remotos | 6 | - permitir configuracao para escolher entre static files locais ou remotos |
| 8 | -- templates question-*.html tem input hidden question_ref que não é usado. remover? | ||
| 9 | - shift-enter não está a funcionar | 7 | - shift-enter não está a funcionar |
| 10 | - default prefix should be obtained from each course (yaml conf)? | 8 | - default prefix should be obtained from each course (yaml conf)? |
| 11 | 9 | ||
| @@ -32,6 +30,8 @@ | @@ -32,6 +30,8 @@ | ||
| 32 | 30 | ||
| 33 | # FIXED | 31 | # FIXED |
| 34 | 32 | ||
| 33 | +- templates question-*.html tem input hidden question_ref que não é usado. remover? | ||
| 34 | +- goals se forem do tipo chapter deve importar todas as dependencias do chapter. | ||
| 35 | - initdb da integrity error se no mesmo comando existirem alunos repetidos (p.ex em ficheiros csv diferentes ou entre csv e opcao -a) | 35 | - initdb da integrity error se no mesmo comando existirem alunos repetidos (p.ex em ficheiros csv diferentes ou entre csv e opcao -a) |
| 36 | - dependencias que não são goals de um curso, só devem aparecer se ainda não tiverem sido feitas. | 36 | - dependencias que não são goals de um curso, só devem aparecer se ainda não tiverem sido feitas. |
| 37 | - ir para inicio da pagina quando le nova pergunta. | 37 | - ir para inicio da pagina quando le nova pergunta. |
aprendizations/learnapp.py
| @@ -108,6 +108,9 @@ class LearnApp(object): | @@ -108,6 +108,9 @@ class LearnApp(object): | ||
| 108 | msg = f'Goal "{goal}" from course "{c}" does not exist' | 108 | msg = f'Goal "{goal}" from course "{c}" does not exist' |
| 109 | logger.error(msg) | 109 | logger.error(msg) |
| 110 | raise LearnException(msg) | 110 | raise LearnException(msg) |
| 111 | + elif self.deps.nodes[goal]['type'] == 'chapter': | ||
| 112 | + d['goals'] += [g for g in self.deps.predecessors(goal) | ||
| 113 | + if g not in d['goals']] | ||
| 111 | 114 | ||
| 112 | # --- factory is a dict with question generators for all topics | 115 | # --- factory is a dict with question generators for all topics |
| 113 | self.factory: Dict[str, QFactory] = self.make_factory() | 116 | self.factory: Dict[str, QFactory] = self.make_factory() |
| @@ -318,7 +321,7 @@ class LearnApp(object): | @@ -318,7 +321,7 @@ class LearnApp(object): | ||
| 318 | async def start_topic(self, uid: str, topic: str) -> None: | 321 | async def start_topic(self, uid: str, topic: str) -> None: |
| 319 | student = self.online[uid]['state'] | 322 | student = self.online[uid]['state'] |
| 320 | if uid == '0': | 323 | if uid == '0': |
| 321 | - logger.warning(f'Reloading "{topic}"') | 324 | + logger.warning(f'Reloading "{topic}"') # FIXME should be an option |
| 322 | self.factory.update(self.factory_for(topic)) | 325 | self.factory.update(self.factory_for(topic)) |
| 323 | 326 | ||
| 324 | try: | 327 | try: |
| @@ -406,6 +409,7 @@ class LearnApp(object): | @@ -406,6 +409,7 @@ class LearnApp(object): | ||
| 406 | 409 | ||
| 407 | t['path'] = path.join(g.graph['prefix'], tref) # prefix/topic | 410 | t['path'] = path.join(g.graph['prefix'], tref) # prefix/topic |
| 408 | 411 | ||
| 412 | + | ||
| 409 | # ======================================================================== | 413 | # ======================================================================== |
| 410 | # methods that do not change state (pure functions) | 414 | # methods that do not change state (pure functions) |
| 411 | # ======================================================================== | 415 | # ======================================================================== |
aprendizations/serve.py
| @@ -201,12 +201,14 @@ class CoursesHandler(BaseHandler): | @@ -201,12 +201,14 @@ class CoursesHandler(BaseHandler): | ||
| 201 | 201 | ||
| 202 | # ---------------------------------------------------------------------------- | 202 | # ---------------------------------------------------------------------------- |
| 203 | # /course/... | 203 | # /course/... |
| 204 | -# Start a given course | 204 | +# Start a given course and show list of topics |
| 205 | # ---------------------------------------------------------------------------- | 205 | # ---------------------------------------------------------------------------- |
| 206 | class CourseHandler(BaseHandler): | 206 | class CourseHandler(BaseHandler): |
| 207 | @tornado.web.authenticated | 207 | @tornado.web.authenticated |
| 208 | def get(self, course_id): | 208 | def get(self, course_id): |
| 209 | uid = self.current_user | 209 | uid = self.current_user |
| 210 | + if course_id == '': | ||
| 211 | + course_id = self.learn.get_current_course_id(uid) | ||
| 210 | 212 | ||
| 211 | try: | 213 | try: |
| 212 | self.learn.start_course(uid, course_id) | 214 | self.learn.start_course(uid, course_id) |
aprendizations/student.py
| @@ -59,12 +59,15 @@ class StudentState(object): | @@ -59,12 +59,15 @@ class StudentState(object): | ||
| 59 | self.current_course: Optional[str] = None | 59 | self.current_course: Optional[str] = None |
| 60 | self.topic_sequence: List[str] = [] | 60 | self.topic_sequence: List[str] = [] |
| 61 | self.current_topic: Optional[str] = None | 61 | self.current_topic: Optional[str] = None |
| 62 | - # self.previous_topic: Optional[str] = None | ||
| 63 | else: | 62 | else: |
| 64 | - logger.debug(f'starting course {course}') | 63 | + try: |
| 64 | + topics = self.courses[course]['goals'] | ||
| 65 | + except KeyError: | ||
| 66 | + logger.debug(f'course "{course}" does not exist') | ||
| 67 | + raise | ||
| 68 | + logger.debug(f'starting course "{course}"') | ||
| 65 | self.current_course = course | 69 | self.current_course = course |
| 66 | - topics = self.courses[course]['goals'] | ||
| 67 | - self.topic_sequence = self.recommend_topic_sequence(topics) | 70 | + self.topic_sequence = self.recommend_sequence(topics) |
| 68 | 71 | ||
| 69 | # ------------------------------------------------------------------------ | 72 | # ------------------------------------------------------------------------ |
| 70 | # Start a new topic. | 73 | # Start a new topic. |
| @@ -178,7 +181,7 @@ class StudentState(object): | @@ -178,7 +181,7 @@ class StudentState(object): | ||
| 178 | # The current topic is unchanged. | 181 | # The current topic is unchanged. |
| 179 | # ------------------------------------------------------------------------ | 182 | # ------------------------------------------------------------------------ |
| 180 | def finish_topic(self) -> None: | 183 | def finish_topic(self) -> None: |
| 181 | - logger.debug(f'finished "{self.current_topic}"') | 184 | + logger.debug(f'finished {self.current_topic} in {self.current_course}') |
| 182 | 185 | ||
| 183 | self.state[self.current_topic] = { | 186 | self.state[self.current_topic] = { |
| 184 | 'date': datetime.now(), | 187 | 'date': datetime.now(), |
| @@ -232,7 +235,7 @@ class StudentState(object): | @@ -232,7 +235,7 @@ class StudentState(object): | ||
| 232 | # ------------------------------------------------------------------------ | 235 | # ------------------------------------------------------------------------ |
| 233 | # compute recommended sequence of topics ['a', 'b', ...] | 236 | # compute recommended sequence of topics ['a', 'b', ...] |
| 234 | # ------------------------------------------------------------------------ | 237 | # ------------------------------------------------------------------------ |
| 235 | - def recommend_topic_sequence(self, goals: List[str] = []) -> List[str]: | 238 | + def recommend_sequence(self, goals: List[str] = []) -> List[str]: |
| 236 | G = self.deps | 239 | G = self.deps |
| 237 | ts = set(goals) | 240 | ts = set(goals) |
| 238 | for t in goals: | 241 | for t in goals: |
| @@ -245,6 +248,8 @@ class StudentState(object): | @@ -245,6 +248,8 @@ class StudentState(object): | ||
| 245 | if t in goals or level < min_level: | 248 | if t in goals or level < min_level: |
| 246 | todo.append(t) | 249 | todo.append(t) |
| 247 | 250 | ||
| 251 | + logger.debug(f' {len(ts)} total topics, {len(todo)} listed ') | ||
| 252 | + | ||
| 248 | # FIXME topological sort is a poor way to sort topics | 253 | # FIXME topological sort is a poor way to sort topics |
| 249 | tl = list(nx.topological_sort(G.subgraph(todo))) | 254 | tl = list(nx.topological_sort(G.subgraph(todo))) |
| 250 | 255 |