Commit bbc1c50606a4da44b9782157d5ddea36e0afcf11
1 parent
f75a344f
Exists in
master
and in
1 other branch
- 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 | ... | ... |