Commit bbc1c50606a4da44b9782157d5ddea36e0afcf11

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

- documentation update: setting up letsencrypt certificates.

- fixed duplicate generation of questions.
- fixed crash when all topics are solved.
Showing 3 changed files with 50 additions and 32 deletions   Show diff stats
BUGS.md
  1 +
1 2 BUGS:
2 3  
3 4 - guardar state cada vez que topico termina
4   -- logs mostram que está a gerar cada pergunta 2 vezes...??
5 5 - reload da página rebenta o estado.
6 6 - indicar o topico actual no sidebar
7 7 - session management. close after inactive time.
... ... @@ -9,7 +9,6 @@ BUGS:
9 9  
10 10 TODO:
11 11  
12   -- letsencrypt.org
13 12 - logs de debug devem indicar o user.
14 13 - implementar http com redirect para https.
15 14 - topicos no sidebar devem ser links para iniciar um topico acessivel. os inacessiveis devem estar inactivos.
... ... @@ -17,8 +16,10 @@ TODO:
17 16 - mostrar comments quando falha a resposta
18 17 - generators not working: bcrypt (ver blog)
19 18  
20   -SOLVED:
  19 +FIXED:
21 20  
  21 +- logs mostram que está a gerar cada pergunta 2 vezes...??
  22 +- letsencrypt.org
22 23 - alterar password.
23 24 - barra de progresso a funcionar
24 25 - mostra tópicos do lado esquerdo, indicando quais estão feitos
... ...
README.md
... ... @@ -71,12 +71,28 @@ First we need to create a database:
71 71  
72 72 ### SSL Certificates
73 73  
  74 +#### Selfsigned
74 75 We also need certificates for https. Generate selfsigned certificates using openssl:
75 76  
76 77 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
77 78  
78 79 and place them in `aprendizations/certs`.
79 80  
  81 +#### LetsEcrypt
  82 +
  83 + sudo pkg install py27-certbot # FreeBSD
  84 +
  85 +Shutdown any server running and the firewall, and then run the script to generate the certificate:
  86 +
  87 + sudo pfctl -d # disable pf firewall
  88 + sudo certbot certonly --standalone -d bit.xdi.uevora.pt
  89 + sudo pfctl -e; sudo pfctl -f /etc/pf.conf # enable pf firewall
  90 +
  91 +Certificates are saved under `/usr/local/etc/letsencrypt/live/bit.xdi.uevora.pt/` which is readable only by root.
  92 +
  93 +Copy them to `aprendizations/certs` with names `cert.pem` and `key.pem`. And change permissions to be readble (FIXME how to do it with security?)
  94 +
  95 +
80 96 ### Testing
81 97  
82 98 Run a demonstration:
... ... @@ -126,16 +142,16 @@ To correct in FreeBSD, edit `~/.login_conf` to use UTF-8, for example:
126 142  
127 143 ## Useful sqlite3 queries
128 144  
129   -- Which students have already done at least one topic?
  145 +Which students have already done at least one topic?
130 146  
131 147 sqlite3 students.db "select distinct student_id from studenttopic"
132 148  
133 149  
134   -- How many topics have done each student?
  150 +How many topics have done each student?
135 151  
136 152 sqlite3 students.db "select student_id, count(topic_id) from studenttopic group by student_id"
137 153  
138 154  
139   -- What questions have more wrong answers?
  155 +What questions have more wrong answers?
140 156  
141 157 sqlite3 students.db "select count(ref), ref from answers where grade<1.0 group by ref order by count(ref) desc"
... ...
knowledge.py
... ... @@ -20,27 +20,30 @@ class Knowledge(object):
20 20 self.depgraph = depgraph
21 21 self.state = state # {node: level, node: level, ...}
22 22  
23   - self.topic = self.topic_generator()
24   - self.current_topic = next(self.topic)
  23 + self.topic_sequence = nx.topological_sort(self.depgraph) # FIXME
25 24  
26   - self.questions = self.generate_questions_for_topic(self.current_topic)
27   - self.current_question = None
28   - self.finished_questions = []
  25 + # select a topic to do
  26 + self.new_topic()
29 27  
30 28 # ------------------------------------------------------------------------
31   - def topic_generator(self):
32   - self.topic_sequence = nx.topological_sort(self.depgraph) # FIXME for now...
33   - for t in self.topic_sequence:
34   - if self.state.get(t, 0.0) > 0.999:
35   - continue
36   - self.questions = self.generate_questions_for_topic(t)
37   - logger.info(f'Generated {len(self.questions)} questions for topic "{t}"')
38   - yield t
  29 + def new_topic(self, topic=None):
  30 + if topic is None:
  31 + # select the first topic that has level < 0.9
  32 + for topic in self.topic_sequence:
  33 + if self.state.get(topic, 0.0) < 0.9:
  34 + break
  35 +
  36 + # FIXME if all are > 0.9, will stay in the last one forever...
  37 + self.current_topic = topic
  38 + self.current_topic_idx = self.topic_sequence.index(topic)
  39 + self.questions = self.generate_questions_for_topic(topic)
  40 + self.current_question = None
  41 + self.finished_questions = []
39 42  
40 43 # ------------------------------------------------------------------------
41 44 def generate_questions_for_topic(self, topic):
42   - factory = self.depgraph.node[topic]['factory']
43   - return [q.generate() for q in factory]
  45 + factory_list = self.depgraph.node[topic]['factory']
  46 + return [q.generate() for q in factory_list]
44 47  
45 48 # ------------------------------------------------------------------------
46 49 def get_current_question(self):
... ... @@ -58,26 +61,24 @@ class Knowledge(object):
58 61 def get_topic_progress(self):
59 62 return len(self.finished_questions) / (len(self.finished_questions) + len(self.questions))
60 63  
61   - # --- generates a new question given the current state -------------------
  64 + # ------------------------------------------------------------------------
  65 + # if answer to current question is correct generates a new question
  66 + # otherwise returns none
62 67 def new_question(self):
63 68 logger.debug('Knowledge.new_question()')
64 69  
65   - if self.current_question is None or self.current_question.get('grade', 0.0) > 0.9999:
  70 + if self.current_question is None or \
  71 + self.current_question.get('grade', 0.0) > 0.9:
66 72  
  73 + # if no more questions in this topic, go to the next one
  74 + # keep going if there are no questions in the next topics
67 75 while not self.questions:
68   - # finished topic!
69 76 self.state[self.current_topic] = 1.0
70   - self.finished_questions = []
71   - try:
72   - self.current_topic = next(self.topic)
73   - except StopIteration:
74   - self.topic = self.topic_generator()
75   - self.current_topic = next(self.topic)
76   - self.questions = self.generate_questions_for_topic(self.current_topic)
  77 + self.new_topic()
77 78  
78 79 self.current_question = self.questions.pop(0)
79 80 self.current_question['start_time'] = datetime.now()
80   - self.finished_questions.append(self.current_question) # FIXME not yet finished...
  81 + self.finished_questions.append(self.current_question)
81 82  
82 83 return self.current_question
83 84  
... ...