Commit bd2ad2b73a8a0f4de7b7e1dbb42af531712b2680

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

- fix references to python3.6/3.7 in README.

- fix and update demo.
- fix striping <p></p> tags in certain cases in the md_to_html function.
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 3
4 - click numa opcao checkbox fora da checkbox+label não está a funcionar. 4 - click numa opcao checkbox fora da checkbox+label não está a funcionar.
5 - shift-enter não está a funcionar 5 - shift-enter não está a funcionar
6 -- nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido.  
7 - mathjax, formulas $$f(x)$$ nas opções de escolha multipla, não ficam centradas em toda a coluna mas apenas na largura do parágrafo. 6 - mathjax, formulas $$f(x)$$ nas opções de escolha multipla, não ficam centradas em toda a coluna mas apenas na largura do parágrafo.
8 - default prefix should be obtained from each course (yaml conf)? 7 - default prefix should be obtained from each course (yaml conf)?
9 - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. 8 - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question.
@@ -29,6 +28,8 @@ @@ -29,6 +28,8 @@
29 28
30 # FIXED 29 # FIXED
31 30
  31 +- nos topicos learn.yaml, qd falha acrescenta no fim. nao faz sentido.
  32 +- não esta a fazer render correcto de tabelas nas opcoes checkbox. e.g. information-theory/source-coding-theory/block-codes
32 - max tries nas perguntas. 33 - max tries nas perguntas.
33 - mostrar feedback/solucoes quando acerta, ou excede max tries. 34 - mostrar feedback/solucoes quando acerta, ou excede max tries.
34 - quando se pressiona "responde" rapido (enquanto a animacao dura), a pergunta passa para a seguinte sem haver o correspondente redraw, ou seja a proxima resposta nao é a da pergunta mostrada. 35 - quando se pressiona "responde" rapido (enquanto a animacao dura), a pergunta passa para a seguinte sem haver o correspondente redraw, ou seja a proxima resposta nao é a da pergunta mostrada.
@@ -37,7 +37,7 @@ python3.7 -m ensurepip --user @@ -37,7 +37,7 @@ python3.7 -m ensurepip --user
37 ``` 37 ```
38 38
39 This will install pip in your user account under `~/.local/bin`. 39 This will install pip in your user account under `~/.local/bin`.
40 -In the end you should be able to run `pip3 --version` and `python3 -c "import sqlite3"` without errors (sometimes `pip3` is `pip`, `pip3.6` or `pip-3.6`). 40 +In the end you should be able to run `pip3 --version` and `python3 -c "import sqlite3"` without errors (sometimes `pip3` is `pip`, `pip3.7` or `pip-3.7`).
41 41
42 If you want to always install python modules on the user account (recommended), edit the pip configuration file `~/.config/pip/pip.conf` (FreeBSD, Linux) or `Library/Application Support/pip/pip.conf` (MacOS) and add the lines 42 If you want to always install python modules on the user account (recommended), edit the pip configuration file `~/.config/pip/pip.conf` (FreeBSD, Linux) or `Library/Application Support/pip/pip.conf` (MacOS) and add the lines
43 43
@@ -93,7 +93,7 @@ cd aprendizations @@ -93,7 +93,7 @@ cd aprendizations
93 93
94 We need certificates for https. Certificates can be self-signed or validated by a trusted authority. 94 We need certificates for https. Certificates can be self-signed or validated by a trusted authority.
95 95
96 -Self-signed can be used locally for development and testing, but browsers will complain. 96 +Self-signed can be used locally for development and testing, but browsers will complain.
97 LetsEncrypt issues trusted and free certificates, but the server must have a registered publicly accessible domain name. 97 LetsEncrypt issues trusted and free certificates, but the server must have a registered publicly accessible domain name.
98 98
99 #### Selfsigned 99 #### Selfsigned
demo/demo.yaml
  1 +---
  2 +
1 title: Example 3 title: Example
2 database: students.db 4 database: students.db
3 -# path: ./demo 5 +
4 6
5 # values applie to each topic, if undefined there 7 # values applie to each topic, if undefined there
6 # default values are: file=question.yaml, shuffle=True, choose: all 8 # default values are: file=question.yaml, shuffle=True, choose: all
7 file: questions.yaml 9 file: questions.yaml
8 -shuffle: True 10 +shuffle: false
9 choose: 6 11 choose: 6
  12 +max_tries: 2
10 forgetting_factor: 0.99 13 forgetting_factor: 0.99
11 14
12 -# Representation of the edges of the dependency graph.  
13 -# Example: A depends on B and C  
14 -# A:  
15 -# name: Topic A  
16 -# deps:  
17 -# - B  
18 -# - C 15 +# ----------------------------------------------------------------------------
19 topics: 16 topics:
20 # topic without dependencies 17 # topic without dependencies
21 math: 18 math:
22 name: Matemática 19 name: Matemática
23 file: questions.yaml 20 file: questions.yaml
24 choose: 6 21 choose: 6
25 - shuffle: True 22 + shuffle: true
26 23
27 # topic with one dependency 24 # topic with one dependency
28 solar_system: 25 solar_system:
demo/solar_system/questions.yaml
1 --- 1 ---
2 2
3 # --------------------------------------------------------------------------- 3 # ---------------------------------------------------------------------------
4 -- ref: solar-system  
5 - type: radio 4 +- type: checkbox
  5 + ref: teste-debug
  6 + title: tabelas em opcoes
  7 + text: ve la se as tabelas estao bem...
  8 + options:
  9 + - |
  10 + x | y
  11 + --|--
  12 + 1 | 2
  13 + - |
  14 + x | y
  15 + --|--
  16 + 1 | 2
  17 + correct: [1, 1]
  18 +
  19 +# ---------------------------------------------------------------------------
  20 +- type: radio
  21 + ref: teste-debug2
  22 + title: formuolas em opcoes
  23 + text: ve la se as tabelas estao bem...
  24 + options:
  25 + - A
  26 + - B
  27 +# ---------------------------------------------------------------------------
  28 +- type: text
  29 + ref: home-planet
  30 + title: Sistema solar
  31 + text: O nosso planeta chama-se planeta...
  32 + correct: ['Terra', 'terra']
  33 + # opcional
  34 + answer: Não é Marte...
  35 +
  36 +# ---------------------------------------------------------------------------
  37 +- type: radio
  38 + ref: solar-system
6 title: Sistema solar 39 title: Sistema solar
7 text: | 40 text: |
8 ![planetas](planets.png " Planetas do Sistema Solar") 41 ![planetas](planets.png " Planetas do Sistema Solar")
@@ -16,30 +49,20 @@ @@ -16,30 +49,20 @@
16 - Têm todos o mesmo tamanho 49 - Têm todos o mesmo tamanho
17 # opcional 50 # opcional
18 correct: 2 51 correct: 2
19 - shuffle: False  
20 - discount: True 52 + shuffle: false
  53 + discount: true
21 54
22 -# ---------------------------------------------------------------------------  
23 --  
24 - ref: home-planet  
25 - type: text  
26 - title: Sistema solar  
27 - text: O nosso planeta chama-se planeta...  
28 - correct: ['Terra', 'terra']  
29 - # opcional  
30 - answer: Não é Marte...  
31 55
32 # --------------------------------------------------------------------------- 56 # ---------------------------------------------------------------------------
33 --  
34 - ref: saturn  
35 - type: text-regex  
36 - title: Sistema solar  
37 - text: O planeta do sistema solar conhecido por ter aneis é o planeta...  
38 - correct: !regex '[Ss]aturno' 57 +- type: text-regex
  58 + ref: saturn
  59 + title: Sistema solar
  60 + text: O planeta do sistema solar conhecido por ter aneis é o planeta...
  61 + correct: !regex '[Ss]aturno'
39 62
40 # --------------------------------------------------------------------------- 63 # ---------------------------------------------------------------------------
41 -- ref: first_3_planets  
42 - type: textarea 64 +- type: textarea
  65 + ref: first_3_planets
43 title: Sistema solar 66 title: Sistema solar
44 text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) 67 text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`)
45 correct: correct-first_3_planets.py 68 correct: correct-first_3_planets.py
@@ -23,7 +23,7 @@ from learnapp import LearnApp @@ -23,7 +23,7 @@ from learnapp import LearnApp
23 from tools import load_yaml, md_to_html 23 from tools import load_yaml, md_to_html
24 24
25 # ---------------------------------------------------------------------------- 25 # ----------------------------------------------------------------------------
26 -# Decorator used to restrict access to the administrator 26 +# Decorator used to restrict access to the administrator only
27 # ---------------------------------------------------------------------------- 27 # ----------------------------------------------------------------------------
28 def admin_only(func): 28 def admin_only(func):
29 @functools.wraps(func) 29 @functools.wraps(func)
@@ -96,7 +96,7 @@ class LoginHandler(BaseHandler): @@ -96,7 +96,7 @@ class LoginHandler(BaseHandler):
96 login_ok = await self.learn.login(uid, pw) 96 login_ok = await self.learn.login(uid, pw)
97 97
98 if login_ok: 98 if login_ok:
99 - self.set_secure_cookie('user', uid) # expires_days=30 99 + self.set_secure_cookie('user', uid)
100 self.set_secure_cookie('counter', str(self.learn.get_login_counter(uid))) 100 self.set_secure_cookie('counter', str(self.learn.get_login_counter(uid)))
101 self.redirect('/') 101 self.redirect('/')
102 else: 102 else:
@@ -198,7 +198,6 @@ class FileHandler(BaseHandler): @@ -198,7 +198,6 @@ class FileHandler(BaseHandler):
198 self.set_header("Content-Type", content_type) 198 self.set_header("Content-Type", content_type)
199 self.write(data) 199 self.write(data)
200 await self.flush() 200 await self.flush()
201 - # self.flush()  
202 201
203 202
204 # ---------------------------------------------------------------------------- 203 # ----------------------------------------------------------------------------
@@ -216,8 +215,9 @@ class QuestionHandler(BaseHandler): @@ -216,8 +215,9 @@ class QuestionHandler(BaseHandler):
216 'textarea': 'question-textarea.html', 215 'textarea': 'question-textarea.html',
217 # -- information panels -- 216 # -- information panels --
218 'information': 'question-information.html', 217 'information': 'question-information.html',
219 - 'info': 'question-information.html',  
220 'success': 'question-success.html', 218 'success': 'question-success.html',
  219 + 'warning': 'question-information.html',
  220 + 'alert': 'question-information.html',
221 } 221 }
222 222
223 # --- get question to render 223 # --- get question to render
templates/question-checkbox.html
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 <div class="custom-control custom-checkbox"> 9 <div class="custom-control custom-checkbox">
10 <input type="checkbox" class="custom-control-input" 10 <input type="checkbox" class="custom-control-input"
11 id="{{ n }}" accesskey="{{ n+1 }}" name="answer" value="{{ n }}"> 11 id="{{ n }}" accesskey="{{ n+1 }}" name="answer" value="{{ n }}">
12 - <label for="{{ n }}" class="custom-control-label">{{ md(opt)[3:-5] }}</label> 12 + <label for="{{ n }}" class="custom-control-label">{{ md(opt, strip_p_tag=True) }}</label>
13 </div> 13 </div>
14 </a> 14 </a>
15 {% end %} 15 {% end %}
templates/question-radio.html
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 <div class="custom-control custom-radio"> 9 <div class="custom-control custom-radio">
10 <input type="radio" class="custom-control-input" 10 <input type="radio" class="custom-control-input"
11 id="{{ n }}" accesskey="{{ n+1 }}" name="answer" value="{{ n }}"> 11 id="{{ n }}" accesskey="{{ n+1 }}" name="answer" value="{{ n }}">
12 - <label for="{{ n }}" class="custom-control-label">{{ md(opt)[3:-5] }}</label> 12 + <label for="{{ n }}" class="custom-control-label">{{ md(opt, strip_p_tag=True) }}</label>
13 </div> 13 </div>
14 </a> 14 </a>
15 {% end %} 15 {% end %}
1 1
2 -# builtin 2 +# python standard library
3 from os import path 3 from os import path
4 import subprocess 4 import subprocess
5 import logging 5 import logging
6 import re 6 import re
7 7
8 -# packages 8 +# user installed libraries
9 import yaml 9 import yaml
10 import mistune 10 import mistune
11 from pygments import highlight 11 from pygments import highlight
@@ -117,8 +117,12 @@ class HighlightRenderer(mistune.Renderer): @@ -117,8 +117,12 @@ class HighlightRenderer(mistune.Renderer):
117 117
118 markdown = MarkdownWithMath(HighlightRenderer(escape=True)) # hard_wrap=True to insert <br> on newline 118 markdown = MarkdownWithMath(HighlightRenderer(escape=True)) # hard_wrap=True to insert <br> on newline
119 119
120 -def md_to_html(text, q=None):  
121 - return markdown(text) 120 +def md_to_html(text, strip_p_tag=False, q=None):
  121 + md = markdown(text)
  122 + if strip_p_tag and md.startswith('<p>') and md.endswith('</p>'):
  123 + return md[3:-5]
  124 + else:
  125 + return md
122 126
123 # --------------------------------------------------------------------------- 127 # ---------------------------------------------------------------------------
124 # load data from yaml file 128 # load data from yaml file