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
  1 +
1 BUGS: 2 BUGS:
2 3
3 - guardar state cada vez que topico termina 4 - guardar state cada vez que topico termina
4 -- logs mostram que está a gerar cada pergunta 2 vezes...??  
5 - reload da página rebenta o estado. 5 - reload da página rebenta o estado.
6 - indicar o topico actual no sidebar 6 - indicar o topico actual no sidebar
7 - session management. close after inactive time. 7 - session management. close after inactive time.
@@ -9,7 +9,6 @@ BUGS: @@ -9,7 +9,6 @@ BUGS:
9 9
10 TODO: 10 TODO:
11 11
12 -- letsencrypt.org  
13 - logs de debug devem indicar o user. 12 - logs de debug devem indicar o user.
14 - implementar http com redirect para https. 13 - implementar http com redirect para https.
15 - topicos no sidebar devem ser links para iniciar um topico acessivel. os inacessiveis devem estar inactivos. 14 - topicos no sidebar devem ser links para iniciar um topico acessivel. os inacessiveis devem estar inactivos.
@@ -17,8 +16,10 @@ TODO: @@ -17,8 +16,10 @@ TODO:
17 - mostrar comments quando falha a resposta 16 - mostrar comments quando falha a resposta
18 - generators not working: bcrypt (ver blog) 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 - alterar password. 23 - alterar password.
23 - barra de progresso a funcionar 24 - barra de progresso a funcionar
24 - mostra tópicos do lado esquerdo, indicando quais estão feitos 25 - mostra tópicos do lado esquerdo, indicando quais estão feitos
@@ -71,12 +71,28 @@ First we need to create a database: @@ -71,12 +71,28 @@ First we need to create a database:
71 71
72 ### SSL Certificates 72 ### SSL Certificates
73 73
  74 +#### Selfsigned
74 We also need certificates for https. Generate selfsigned certificates using openssl: 75 We also need certificates for https. Generate selfsigned certificates using openssl:
75 76
76 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes 77 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
77 78
78 and place them in `aprendizations/certs`. 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 ### Testing 96 ### Testing
81 97
82 Run a demonstration: 98 Run a demonstration:
@@ -126,16 +142,16 @@ To correct in FreeBSD, edit `~/.login_conf` to use UTF-8, for example: @@ -126,16 +142,16 @@ To correct in FreeBSD, edit `~/.login_conf` to use UTF-8, for example:
126 142
127 ## Useful sqlite3 queries 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 sqlite3 students.db "select distinct student_id from studenttopic" 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 sqlite3 students.db "select student_id, count(topic_id) from studenttopic group by student_id" 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 sqlite3 students.db "select count(ref), ref from answers where grade<1.0 group by ref order by count(ref) desc" 157 sqlite3 students.db "select count(ref), ref from answers where grade<1.0 group by ref order by count(ref) desc"
@@ -20,27 +20,30 @@ class Knowledge(object): @@ -20,27 +20,30 @@ class Knowledge(object):
20 self.depgraph = depgraph 20 self.depgraph = depgraph
21 self.state = state # {node: level, node: level, ...} 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 def generate_questions_for_topic(self, topic): 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 def get_current_question(self): 49 def get_current_question(self):
@@ -58,26 +61,24 @@ class Knowledge(object): @@ -58,26 +61,24 @@ class Knowledge(object):
58 def get_topic_progress(self): 61 def get_topic_progress(self):
59 return len(self.finished_questions) / (len(self.finished_questions) + len(self.questions)) 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 def new_question(self): 67 def new_question(self):
63 logger.debug('Knowledge.new_question()') 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 while not self.questions: 75 while not self.questions:
68 - # finished topic!  
69 self.state[self.current_topic] = 1.0 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 self.current_question = self.questions.pop(0) 79 self.current_question = self.questions.pop(0)
79 self.current_question['start_time'] = datetime.now() 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 return self.current_question 83 return self.current_question
83 84