Commit db04e658cdb955cc98823f2c1520a76c4076d104

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

- added option to select which questions go for a given topic instead of all of them.

Showing 3 changed files with 37 additions and 22 deletions   Show diff stats
BUGS.md
1 1  
2 2 BUGS:
3 3  
4   -- level depender do numero de respostas correctas
  4 +- nao permite perguntas repetidas. iterar questions da configuracao em vez das do ficheiro. ver app.py linha 223.
5 5 - pymips: activar/desactivar instruções
6 6 - tabs em textarea nao funcionam correctamente (insere 1 espaco em vez de 4)
7 7 - reportar comentarios após submeter.
... ... @@ -27,6 +27,7 @@ TODO:
27 27  
28 28 FIXED:
29 29  
  30 +- level depender do numero de respostas correctas
30 31 - pymips a funcionar
31 32 - logs mostram que está a gerar cada pergunta 2 vezes...??
32 33 - letsencrypt.org
... ...
README.md
... ... @@ -72,7 +72,7 @@ First we need to create a database:
72 72 ### SSL Certificates
73 73  
74 74 We need certificates for https. Certificates can be self-signed or certificates validated by a trusted authority.
75   -Self-signed can be used for development, but browsers will complain.
  75 +Self-signed can be used for development, but browsers will complain.
76 76 LetsEncrypt issues trusted and free certificates, but the served must have a fixed IP and a domain name (not dynamic).
77 77  
78 78 #### Selfsigned
... ... @@ -140,24 +140,26 @@ Reboot.
140 140  
141 141 The server should not generate this error, but when using external scripts to generate questions or to correct, these scripts can print unicode strings to stdout. If the terminal does not support unicode, python will generate this exception.
142 142  
143   -To correct in FreeBSD, edit `~/.login_conf` to use UTF-8, for example:
  143 +- FreeBSD fix: edit `~/.login_conf` to use UTF-8, for example:
144 144  
145 145 me:\
146 146 :charset=UTF-8:\
147 147 :lang=en_US.UTF-8:
148 148  
  149 +- Debian fix: check `locale`...
  150 +
149 151 ## Useful sqlite3 queries
150 152  
151   -Which students have already done at least one topic?
  153 +Which students did at least one topic?
152 154  
153 155 sqlite3 students.db "select distinct student_id from studenttopic"
154 156  
155 157  
156   -How many topics have done each student?
  158 +How many topics had each student done?
157 159  
158 160 sqlite3 students.db "select student_id, count(topic_id) from studenttopic group by student_id order by count(topic_id) desc"
159 161  
160 162  
161   -What questions have more wrong answers?
  163 +Which questions have more wrong answers?
162 164  
163 165 sqlite3 students.db "select count(ref), ref from answers where grade<1.0 group by ref order by count(ref) desc"
... ...
app.py
... ... @@ -146,7 +146,7 @@ class LearnApp(object):
146 146 # return self.online[uid]['state'].current_question
147 147  
148 148 # ------------------------------------------------------------------------
149   - # check answer and if correct returns new question, otherise returns None
  149 + # check answer and if correct returns new question, otherwise returns None
150 150 def check_answer(self, uid, answer):
151 151 knowledge = self.online[uid]['state']
152 152 current_question = knowledge.check_answer(answer)
... ... @@ -168,7 +168,6 @@ class LearnApp(object):
168 168 # Receives a set of topics (strings like "math/algebra"),
169 169 # and recursively adds dependencies to the dependency graph
170 170 def build_dependency_graph(self, config_file):
171   - logger.debug(f'LearnApp.build_dependency_graph("{config_file}")')
172 171  
173 172 # Load configuration file
174 173 try:
... ... @@ -189,36 +188,49 @@ class LearnApp(object):
189 188 topics = config.get('topics', {})
190 189 for ref,attr in topics.items():
191 190 g.add_node(ref)
192   - if isinstance(attr, list):
193   - # if prop is a list, we assume it's just a list of dependencies
194   - g.add_edges_from((d,ref) for d in attr)
195   -
196   - elif isinstance(attr, dict):
  191 + if isinstance(attr, dict):
197 192 g.node[ref]['name'] = attr.get('name', ref)
  193 + g.node[ref]['questions'] = attr.get('questions', [])
198 194 g.add_edges_from((d,ref) for d in attr.get('deps', []))
199 195  
200   - elif isinstance(attr, str):
  196 + elif isinstance(attr, list):
  197 + # if prop is a list, we assume it's just a list of dependencies
  198 + g.add_edges_from((d,ref) for d in attr)
  199 +
  200 + elif isinstance(attr, str): # FIXME is this really useful??
201 201 g.node[ref]['name'] = attr
202 202  
203 203 # iterate over topics and create question factories
204 204 logger.info('Loading:')
205 205 for ref in g.nodes_iter():
206 206 g.node[ref].setdefault('name', ref)
207   - fullpath = path.expanduser(path.join(prefix, ref))
  207 + prefix_ref = path.join(prefix, ref)
  208 + fullpath = path.expanduser(prefix_ref)
208 209 if path.isdir(fullpath):
209 210 filename = path.join(fullpath, "questions.yaml")
210 211 else:
211   - logger.error(f'build_dependency_graph: "{fullpath}" is not a directory')
  212 + logger.error(f'Cant find directory "{prefix_ref}", ignored...')
  213 + continue
212 214  
213 215 if path.isfile(filename):
214   - questions = load_yaml(filename, default=[])
215   - logger.info(f' {len(questions)} questions from "{ref}"')
216   - for q in questions:
217   - q['path'] = fullpath
218   - g.node[ref]['factory'] = [QFactory(q) for q in questions]
  216 + loaded_questions = load_yaml(filename, default=[])
  217 +
  218 + # if 'questions' is not provided in configuration, load all
  219 + if not g.node[ref]['questions']:
  220 + g.node[ref]['questions'] = [q['ref'] for q in loaded_questions]
  221 +
  222 +
  223 + # FIXME nao permite perguntas repetidas. iterar questions da configuracao em vez das do ficheiro.
  224 + g.node[ref]['factory'] = []
  225 + for q in loaded_questions:
  226 + if q['ref'] in g.node[ref]['questions']:
  227 + q['path'] = fullpath
  228 + g.node[ref]['factory'].append(QFactory(q))
  229 + logger.info(f' {len(g.node[ref]["factory"])} questions from "{ref}"')
  230 +
219 231 else:
220 232 g.node[ref]['factory'] = []
221   - logger.error(f'build_dependency_graph: "{filename}" does not exist')
  233 + logger.error(f'Cant load "{filename}"')
222 234  
223 235 self.depgraph = g
224 236 return g
... ...