Commit f865b05a08c5e9acbe0ab92f4b0dad1d776f789f

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

allow admin to reload topic and regenerate QFactory

aprendizations/learnapp.py
... ... @@ -78,7 +78,6 @@ class LearnApp(object):
78 78 logger.info(f'{len(t):>6} topics in {courses}')
79 79 for f in config.get('topics_from', []):
80 80 c = load_yaml(f) # course configuration
81   -
82 81 # FIXME set defaults??
83 82 logger.info(f'{len(c["topics"]):>6} topics imported from {f}')
84 83 self.populate_graph(c)
... ... @@ -302,6 +301,10 @@ class LearnApp(object):
302 301 # ------------------------------------------------------------------------
303 302 async def start_topic(self, uid: str, topic: str) -> None:
304 303 student = self.online[uid]['state']
  304 + if uid == '0':
  305 + logger.warning(f'Reloading "{topic}"')
  306 + self.factory.update(self.factory_for(topic))
  307 +
305 308 try:
306 309 await student.start_topic(topic)
307 310 except Exception as e:
... ... @@ -393,66 +396,78 @@ class LearnApp(object):
393 396  
394 397 # ------------------------------------------------------------------------
395 398 # Buils dictionary of question factories
  399 + # - visits each topic in the graph,
  400 + # - adds factory for each topic.
396 401 # ------------------------------------------------------------------------
397 402 def make_factory(self) -> Dict[str, QFactory]:
398 403  
399 404 logger.info('Building questions factory:')
400   - factory = {}
  405 + factory = dict()
401 406 g = self.deps
402 407 for tref in g.nodes():
403   - t = g.nodes[tref]
  408 + factory.update(self.factory_for(tref))
404 409  
405   - # load questions as list of dicts
406   - topicpath: str = path.join(g.graph['prefix'], tref)
407   - try:
408   - fullpath: str = path.join(topicpath, t['file'])
409   - except Exception:
410   - msg1 = f'Invalid topic "{tref}"'
411   - msg2 = f'Check dependencies of {", ".join(g.successors(tref))}'
412   - raise LearnException(f'{msg1}. {msg2}')
  410 + logger.info(f'Factory has {len(factory)} questions')
  411 + return factory
413 412  
414   - logger.debug(f' Loading {fullpath}')
415   - try:
416   - questions: List[QDict] = load_yaml(fullpath)
417   - except Exception:
418   - msg = f'Failed to load "{fullpath}"'
419   - logger.error(msg)
420   - raise LearnException(msg)
  413 + # ------------------------------------------------------------------------
  414 + # makes factory for a single topic
  415 + # ------------------------------------------------------------------------
  416 + def factory_for(self, tref: str) -> Dict[str, QFactory]:
  417 + factory = {}
  418 + g = self.deps
  419 + t = g.nodes[tref] # get node
421 420  
422   - if not isinstance(questions, list):
423   - msg = f'File "{fullpath}" must be a list of questions'
424   - raise LearnException(msg)
  421 + # load questions as list of dicts
  422 + topicpath: str = path.join(g.graph['prefix'], tref)
  423 + try:
  424 + fullpath: str = path.join(topicpath, t['file'])
  425 + except Exception:
  426 + msg1 = f'Invalid topic "{tref}"'
  427 + msg2 = f'Check dependencies of {", ".join(g.successors(tref))}'
  428 + raise LearnException(f'{msg1}. {msg2}')
425 429  
426   - # update refs to include topic as prefix.
427   - # refs are required to be unique only within the file.
428   - # undefined are set to topic:n, where n is the question number
429   - # within the file
430   - localrefs: Set[str] = set() # refs in current file
431   - for i, q in enumerate(questions):
432   - qref = q.get('ref', str(i)) # ref or number
433   - if qref in localrefs:
434   - msg = f'Duplicate ref "{qref}" in "{topicpath}"'
435   - raise LearnException(msg)
436   - localrefs.add(qref)
  430 + logger.debug(f' Loading {fullpath}')
  431 + try:
  432 + questions: List[QDict] = load_yaml(fullpath)
  433 + except Exception:
  434 + msg = f'Failed to load "{fullpath}"'
  435 + logger.error(msg)
  436 + raise LearnException(msg)
  437 +
  438 + if not isinstance(questions, list):
  439 + msg = f'File "{fullpath}" must be a list of questions'
  440 + raise LearnException(msg)
  441 +
  442 + # update refs to include topic as prefix.
  443 + # refs are required to be unique only within the file.
  444 + # undefined are set to topic:n, where n is the question number
  445 + # within the file
  446 + localrefs: Set[str] = set() # refs in current file
  447 + for i, q in enumerate(questions):
  448 + qref = q.get('ref', str(i)) # ref or number
  449 + if qref in localrefs:
  450 + msg = f'Duplicate ref "{qref}" in "{topicpath}"'
  451 + raise LearnException(msg)
  452 + localrefs.add(qref)
437 453  
438   - q['ref'] = f'{tref}:{qref}'
439   - q['path'] = topicpath
440   - q.setdefault('append_wrong', t['append_wrong'])
  454 + q['ref'] = f'{tref}:{qref}'
  455 + q['path'] = topicpath
  456 + q.setdefault('append_wrong', t['append_wrong'])
441 457  
442   - # if questions are left undefined, include all.
443   - if not t['questions']:
444   - t['questions'] = [q['ref'] for q in questions]
  458 + # if questions are left undefined, include all.
  459 + if not t['questions']:
  460 + t['questions'] = [q['ref'] for q in questions]
445 461  
446   - t['choose'] = min(t['choose'], len(t['questions']))
  462 + t['choose'] = min(t['choose'], len(t['questions']))
447 463  
448   - for q in questions:
449   - if q['ref'] in t['questions']:
450   - factory[q['ref']] = QFactory(q)
451   - logger.debug(f' + {q["ref"]}')
  464 + for q in questions:
  465 + if q['ref'] in t['questions']:
  466 + factory[q['ref']] = QFactory(q)
  467 + logger.debug(f' + {q["ref"]}')
452 468  
453   - logger.info(f'{len(t["questions"]):6} questions in {tref}')
  469 + logger.info(f'{len(t["questions"]):6} questions in {tref}')
454 470  
455   - logger.info(f'Factory has {len(factory)} questions')
456 471 return factory
457 472  
458 473 # ------------------------------------------------------------------------
... ... @@ -501,7 +516,7 @@ class LearnApp(object):
501 516  
502 517 # ------------------------------------------------------------------------
503 518 def get_current_public_dir(self, uid: str) -> str:
504   - topic: str = self.online[uid]['state'].get_current_topic() # FIXME returns None if its the last question in the topic
  519 + topic: str = self.online[uid]['state'].get_current_topic()
505 520 prefix: str = self.deps.graph['prefix']
506 521 return path.join(prefix, topic, 'public')
507 522  
... ...
aprendizations/student.py
... ... @@ -75,12 +75,12 @@ class StudentState(object):
75 75 logger.debug(f'start topic "{topic}"')
76 76  
77 77 # avoid regenerating questions in the middle of the current topic
78   - if self.current_topic == topic:
  78 + if self.current_topic == topic and self.uid != '0':
79 79 logger.info('Restarting current topic is not allowed.')
80 80 return
81 81  
82 82 # do not allow locked topics
83   - if self.is_locked(topic):
  83 + if self.is_locked(topic) and self.uid != '0':
84 84 logger.debug(f'is locked "{topic}"')
85 85 return
86 86  
... ...