Commit 03210039c66bdcdc9623a43d47c8ffc8fe8e861d

Authored by Miguel Barao
1 parent 13773677
Exists in master and in 1 other branch dev

- main page ok.

knowledge.py
... ... @@ -42,45 +42,63 @@ class StudentKnowledge(object):
42 42 # select a topic to do and initialize questions
43 43 # self.start_topic()
44 44  
  45 +
  46 + # ------------------------------------------------------------------------
  47 + # Unlock all topics whose dependencies are satisfied
  48 + # ------------------------------------------------------------------------
  49 + def unlock_topics(self):
  50 + min_level = 0.01 # minimum level to unlock
  51 + for topic in self.topic_sequence:
  52 + if topic not in self.state: # if locked
  53 + pred = self.deps.predecessors(topic)
  54 + if all(d in self.state and self.state[d]['level'] > min_level for d in pred): # dependencies done
  55 + self.state[topic] = {
  56 + 'level': 0.0,
  57 + 'date': datetime.now()
  58 + }
  59 + logger.debug(f'unlocked {topic}')
  60 +
  61 +
  62 + # ------------------------------------------------------------------------
  63 + # Recommends a topic to practice/learn from the state
  64 + # ------------------------------------------------------------------------
  65 + def recommend_topic(self):
  66 + pass # FIXME
  67 +
45 68 # ------------------------------------------------------------------------
46 69 # Start a new topic. If not provided, selects the first with level < 0.8
47 70 # If all levels > 0.8, will stay in the last one forever...
48 71 # ------------------------------------------------------------------------
49 72 def start_topic(self, topic=''):
50 73 # unlock topics whose dependencies are done
51   - unlocked_topics = []
52   - for t in self.topic_sequence:
53   - if t not in self.state: # is locked
54   - deps = self.depgraph.predecessors(t)
55   - if all(d in self.state and self.state[d]['level'] > 0.01 for d in deps): # dependencies done
56   - unlocked_topics.append(t)
  74 + logger.debug('start_topic ' + topic)
57 75  
58   - for t in unlocked_topics:
59   - self.state[t] = {'level': 0.0, 'date': datetime.now()}
60   - logger.info(f'Unlocked "{t}"')
  76 + self.unlock_topics()
61 77  
62 78 # choose topic
63 79 if not topic:
64 80 for topic in self.topic_sequence:
65 81 unlocked = topic in self.state
66 82 needs_work = unlocked and self.state[topic]['level'] < 0.8
67   - factory = self.depgraph.node[topic]['factory']
  83 + factory = self.deps.node[topic]['factory']
68 84 if factory and (not unlocked or needs_work):
69 85 break
70 86  
71 87 # use given topic if possible
72 88 else:
73 89 unlocked = topic in self.state
74   - factory = self.depgraph.node[topic]['factory']
  90 + factory = self.deps.node[topic]['factory']
75 91 if not factory or not unlocked:
76 92 logger.debug(f'Can\'t start topic "{topic}".')
77 93 return
78 94  
  95 +
  96 +
79 97 self.current_topic = topic
80 98 logger.info(f'Topic set to "{topic}"')
81 99  
82 100 # generate question instances for current topic
83   - questionlist = self.depgraph.node[topic]['questions']
  101 + questionlist = self.deps.node[topic]['questions']
84 102 self.questions = [factory[qref].generate() for qref in questionlist]
85 103 self.current_question = self.questions.pop(0) # FIXME crashes if questions==[]
86 104 self.current_question['start_time'] = datetime.now()
... ... @@ -110,7 +128,7 @@ class StudentKnowledge(object):
110 128 else:
111 129 self.current_question['start_time'] = datetime.now()
112 130 else:
113   - factory = self.depgraph.node[self.current_topic]['factory']
  131 + factory = self.deps.node[self.current_topic]['factory']
114 132 self.questions.append(factory[q['ref']].generate())
115 133  
116 134 return q
... ...
learnapp.py
... ... @@ -289,6 +289,6 @@ def build_dependency_graph(config_file):
289 289 q['path'] = fullpath
290 290 tnode['factory'][q['ref']] = QFactory(q)
291 291  
292   - logger.info(f' {len(tnode["questions"])} questions from "{tref}"')
  292 + logger.info(f'{len(tnode["questions"]):4} questions from {tref}')
293 293  
294 294 return g
... ...
serve.py
... ... @@ -33,7 +33,7 @@ class WebApplication(tornado.web.Application):
33 33 (r'/change_password', ChangePasswordHandler),
34 34 (r'/question', QuestionHandler),
35 35 (r'/', LearnHandler),
36   - (r'/topic', TopicHandler),
  36 + (r'/topic/(.+)', TopicHandler),
37 37 (r'/(.+)', FileHandler),
38 38 ]
39 39 settings = {
... ... @@ -109,7 +109,7 @@ class ChangePasswordHandler(BaseHandler):
109 109 self.write({'msg': notification})
110 110  
111 111 # ----------------------------------------------------------------------------
112   -# main page /
  112 +# Main page: /
113 113 # Shows a list of topics and proficiency (stars, locked).
114 114 # ----------------------------------------------------------------------------
115 115 class LearnHandler(BaseHandler):
... ... @@ -122,12 +122,14 @@ class LearnHandler(BaseHandler):
122 122 state=self.learn.get_student_state(uid)
123 123 )
124 124  
125   -
  125 +# ----------------------------------------------------------------------------
  126 +# Start a given topic: /topic
  127 +# ----------------------------------------------------------------------------
126 128 class TopicHandler(BaseHandler):
127 129 @tornado.web.authenticated
128   - def get(self):
  130 + def get(self, topic):
129 131 uid = self.current_user
130   - topic = self.get_query_argument('topic', default='')
  132 + # topic = self.get_query_argument('topic', default='')
131 133 self.learn.start_topic(uid, topic)
132 134 self.render('topic.html',
133 135 uid=uid,
... ...
templates/maintopics.html
... ... @@ -42,28 +42,39 @@
42 42 </nav>
43 43 <div class="container">
44 44  
45   - <h3>Tópicos</h3>
  45 + <h3>Tópicos</h3>
46 46  
47   - <div class="list-group">
48   - {% for t in state %}
49   - {% if t['level'] is None %}
50   - <a class="list-group-item list-group-item-action disabled" href="#">
51   - {{ t['name'] }}
52   - <i class="fa fa-lock" aria-hidden="true"></i>
53   - </a>
54   - {% else %}
55   - <a class="list-group-item list-group-item-action" href="/?topic={{ t['ref'] }}">
56   - {{ t['name'] }}
57   - {% if t['level'] < 0.01 %}
58   - <i class="fa fa-unlock" aria-hidden="true"></i>
59   -
60   - {% else %}
61   - {{ round(t['level']*5)*'<i class="fa fa-star text-success" aria-hidden="true"></i>' + round(5-t['level']*5)*'<i class="fa fa-star-o" aria-hidden="true"></i>' }}
62   - {% end %}
63   - </a>
64   - {% end %}
65   - {% end %}
66   - </div>
  47 + <div class="list-group">
  48 + {% for t in state %}
  49 + {% if t['level'] is None %}
  50 + <a class="list-group-item list-group-item-action disabled" href="#">
  51 + <div class="d-flex justify-content-start">
  52 + <div class="p-2">
  53 + {{ t['name'] }}
  54 + </div>
  55 + <div class="ml-auto p-2">
  56 + <i class="fa fa-lock" aria-hidden="true"></i>
  57 + </div>
  58 + </div>
  59 + </a>
  60 + {% else %}
  61 + <a class="list-group-item list-group-item-action" href="/topic/{{t['ref']}}">
  62 + <div class="d-flex justify-content-start">
  63 + <div class="p-2">
  64 + {{ t['name'] }}
  65 + </div>
  66 + <div class="ml-auto p-2">
  67 + {% if t['level'] < 0.01 %}
  68 + <i class="fa fa-unlock float-right" aria-hidden="true"></i>
  69 + {% else %}
  70 + {{ round(t['level']*5)*'<i class="fa fa-star text-success" aria-hidden="true"></i>' + round(5-t['level']*5)*'<i class="fa fa-star-o" aria-hidden="true"></i>' }}
  71 + {% end %}
  72 + </div>
  73 + </div>
  74 + </a>
  75 + {% end %}
  76 + {% end %}
  77 + </div> <!-- list-group -->
67 78 </div>
68 79  
69 80 <!-- Scripts -->
... ...