Commit bd2ad2b73a8a0f4de7b7e1dbb42af531712b2680
1 parent
eeb28a09
Exists in
master
and in
1 other branch
- 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.
Showing
8 changed files
with
69 additions
and
44 deletions
Show diff stats
BUGS.md
| @@ -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. |
README.md
| @@ -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 |  | 41 |  |
| @@ -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 |
serve.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 %} |
tools.py
| 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 |