Commit cc63d37e7b4dad1a1a6ca42d8eaba062f2ed744c

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

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.
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