From 0b1675b0ba146a3513d7df2633f189ccd7282e4e Mon Sep 17 00:00:00 2001 From: Miguel Barão Date: Sat, 4 Mar 2017 20:05:55 +0000 Subject: [PATCH] - fix browser redirection to /question when enter key is pressed. - fix direction of graph edges. - use config file given in a commandline option. - improved debug messages - removed panel from question html --- BUGS.md | 7 +++++-- app.py | 8 ++++---- knowledge.py | 9 +++++++-- questions.py | 27 +++++++++------------------ serve.py | 18 +++++++++++++++--- templates/learn.html | 10 ++++++---- templates/question.html | 20 +++++++++++--------- 7 files changed, 57 insertions(+), 42 deletions(-) diff --git a/BUGS.md b/BUGS.md index a94cade..31df91a 100644 --- a/BUGS.md +++ b/BUGS.md @@ -1,7 +1,8 @@ BUGS: -- de vez em quando o browser é redireccionado para /question em vez de fazer um post?? não percebo... -- load/save the knowledge state of the student +- não entra à primeira +- logs mostram que está a gerar cada pergunta 2 vezes...?? +- mostra tópicos do lado esquerdo, indicando quais estão feitos e quantas perguntas contêm. - se students.db não existe, rebenta. - database hardcoded in LearnApp. - implementar xsrf. Ver [http://www.tornadoweb.org/en/stable/guide/security.html#cross-site-request-forgery-protection]() @@ -15,6 +16,8 @@ TODO: SOLVED: +- o browser é redireccionado para /question em vez de fazer um post?? quando se pressiona enter numa caixa text edit. +- load/save the knowledge state of the student - servir ficheiros de public temporariamente - path dos generators scripts mal construido - questions hardcoded in LearnApp. diff --git a/app.py b/app.py index 8c2eb06..79630e6 100644 --- a/app.py +++ b/app.py @@ -28,7 +28,7 @@ logger = logging.getLogger(__name__) # LearnApp - application logic # ============================================================================ class LearnApp(object): - def __init__(self): + def __init__(self, conffile='demo/demo.yaml'): # online students self.online = {} @@ -36,7 +36,7 @@ class LearnApp(object): self.db_setup('students.db') # FIXME # build dependency graph - self.build_dependency_graph('demo/config.yaml') # FIXME + self.build_dependency_graph(conffile) # FIXME # add topics from depgraph to the database self.db_add_topics() @@ -103,7 +103,7 @@ class LearnApp(object): # ------------------------------------------------------------------------ def get_current_public_dir(self, uid): - topic = self.online[uid]['state'].topic + topic = self.online[uid]['state'].get_current_topic() p = self.depgraph.graph['path'] return path.join(p, topic, 'public') @@ -164,7 +164,7 @@ class LearnApp(object): # Build dependency graph deps = config.get('dependencies', {}) for n,dd in deps.items(): - g.add_edges_from((n,d) for d in dd) + g.add_edges_from((d,n) for d in dd) # Builds factories for each node for n in g.nodes_iter(): diff --git a/knowledge.py b/knowledge.py index 1c6c18e..3493397 100644 --- a/knowledge.py +++ b/knowledge.py @@ -30,7 +30,10 @@ class Knowledge(object): def topic_generator(self): topics = nx.topological_sort(self.depgraph) # FIXME for now... for t in topics: + if self.state.get(t, 0.0) > 0.999: + continue self.questions = self.generate_questions_for_topic(t) + logger.info(f'Generated {len(self.questions)} questions for topic "{t}"') yield t # ------------------------------------------------------------------------ @@ -43,6 +46,10 @@ class Knowledge(object): return self.current_question # ------------------------------------------------------------------------ + def get_current_topic(self): + return self.current_topic + + # ------------------------------------------------------------------------ def get_knowledge_state(self): return self.state @@ -61,8 +68,6 @@ class Knowledge(object): self.current_topic = next(self.topic) self.questions = self.generate_questions_for_topic(self.current_topic) - print(self.current_topic) - print(self.current_question) self.current_question = self.questions.pop(0) self.current_question['start_time'] = datetime.now() diff --git a/questions.py b/questions.py index 09ef653..bbbbe24 100644 --- a/questions.py +++ b/questions.py @@ -406,7 +406,7 @@ class QFactory(object): # i.e. a question object (radio, checkbox, ...). # ----------------------------------------------------------------------- def generate(self): - logger.debug('generate()') + logger.debug(f'generate "{self.question["ref"]}"') # Shallow copy so that script generated questions will not replace # the original generators q = self.question.copy() @@ -415,10 +415,8 @@ class QFactory(object): # which will print a valid question in yaml format to stdout. This # output is then converted to a dictionary and `q` becomes that dict. if q['type'] == 'generator': - logger.debug('Running script to generate question "{0}".'.format(q['ref'])) + logger.debug(f'Running script "{q["script"]}"...') q.setdefault('arg', '') # optional arguments will be sent to stdin - # print(q['path']) - # print(q['script']) script = path.join(q['path'], q['script']) out = run_script(script=script, stdin=q['arg']) q.update(out) @@ -433,18 +431,11 @@ class QFactory(object): # }) # Finally we create an instance of Question() - logger.debug('create instance...') - # try: - # qinstance = self._types[q['type']](q) # instance with correct class - # except KeyError as e: - # logger.error('Unknown question type "{0}" in "{1}:{2}".'.format(q['type'], q['filename'], q['ref'])) - # raise e - # except: - # logger.error('Failed to create question "{0}" from file "{1}".'.format(q['ref'], q['filename'])) - # else: - # logger.debug('Generated question "{}".'.format(ref)) - # return qinstance - qinstance = self._types[q['type']](q) # instance with correct class - logger.debug('returning') - return qinstance + try: + qinstance = self._types[q['type']](q) # instance with correct class + except KeyError as e: + logger.error(f'Unknown question type "{q["type"]}"') + raise e + else: + return qinstance diff --git a/serve.py b/serve.py index e9f8a5a..42a9da5 100755 --- a/serve.py +++ b/serve.py @@ -8,6 +8,7 @@ import base64 import uuid import concurrent.futures import logging.config +import argparse # user installed libraries try: @@ -32,7 +33,7 @@ from tools import load_yaml, md # WebApplication - Tornado Web Server # ============================================================================ class WebApplication(tornado.web.Application): - def __init__(self): + def __init__(self, learnapp): handlers = [ (r'/login', LoginHandler), (r'/logout', LogoutHandler), @@ -50,7 +51,7 @@ class WebApplication(tornado.web.Application): 'debug': True, } super().__init__(handlers, **settings) - self.learn = LearnApp() + self.learn = learnapp # ============================================================================ # Handlers @@ -169,6 +170,16 @@ def main(): SERVER_PATH = os.path.dirname(os.path.realpath(__file__)) LOGGER_CONF = os.path.join(SERVER_PATH, 'config/logger.yaml') + # --- Commandline argument parsing + argparser = argparse.ArgumentParser(description='Server for online learning. Enrolled students and topics have to be previously configured. Please read the documentation included with this software before running the server.') + # FIXME: + # serverconf_file = path.normpath(path.join(SERVER_PATH, 'config', 'server.conf')) + # argparser.add_argument('--conf', default=serverconf_file, type=str, help='server configuration file') + # argparser.add_argument('--debug', action='store_true', help='Enable debug logging.') + # argparser.add_argument('--allow-all', action='store_true', + # help='Students are initially allowed to login (can be denied later)') + argparser.add_argument('conffile', type=str, nargs='+', help='Topics configuration file in YAML format.') # FIXME only one supported at the moment + arg = argparser.parse_args() # --- Setup logging try: @@ -179,8 +190,9 @@ def main(): sys.exit(1) # --- start application + learnapp = LearnApp(arg.conffile[0]) try: - webapp = WebApplication() + webapp = WebApplication(learnapp) except Exception as e: logging.critical('Can\'t start application.') # sys.exit(1) diff --git a/templates/learn.html b/templates/learn.html index 5f056ac..e1ef4e5 100644 --- a/templates/learn.html +++ b/templates/learn.html @@ -66,12 +66,12 @@
-