Commit 0b947002049e45c0a5db93291b8ee5920930a650

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

- fix bug in password reset.

- new information question in the demo suggesting use of yamllint.
- version bump to 2020.05.dev3
1 1
2 # BUGS 2 # BUGS
3 3
4 -- review does not show question refs when commandline --show-ref is used but not the test.yaml option.  
5 -- em admin, quando scale_max não é 20, as cores das barras continuam a reflectir a escala 0,20. a tabela teste na DB não tem a escala desse teste.  
6 - CRITICAL se answer for `i<n` a revisão de provas mostra apenas i (interpreta `<` como tag?) 4 - CRITICAL se answer for `i<n` a revisão de provas mostra apenas i (interpreta `<` como tag?)
7 -- na pagina grade.html as barras estao normalizadas para os limites scale_min e max do teste actual e nao do realizado. 5 +
  6 +- em admin, quando scale_max não é 20, as cores das barras continuam a reflectir a escala 0,20. a tabela teste na DB não tem a escala desse teste.
  7 +- em grade.html as barras estao normalizadas para os limites scale_min e max do teste actual e nao dos testes realizados no passado (tabela test devia guardar a escala).
8 - codigo `hello world` nao esta a preservar o whitespace. O renderer de markdown gera a tag <code> que não preserva whitespace. Necessario adicionar <pre>. 8 - codigo `hello world` nao esta a preservar o whitespace. O renderer de markdown gera a tag <code> que não preserva whitespace. Necessario adicionar <pre>.
9 -- teste nao esta a mostrar imagens de vez em quando.  
10 - mensagems de erro do assembler aparecem na mesma linha na correcao e nao fazerm rendering do `$t`, ver se servidor faz parse do markdown dessas mensagens. 9 - mensagems de erro do assembler aparecem na mesma linha na correcao e nao fazerm rendering do `$t`, ver se servidor faz parse do markdown dessas mensagens.
11 - impedir os eventos copy/paste. alunos usam isso para trazer codigo ja feito nos computadores. Obrigar a fazer reset? fazer um copy automaticamente? 10 - impedir os eventos copy/paste. alunos usam isso para trazer codigo ja feito nos computadores. Obrigar a fazer reset? fazer um copy automaticamente?
12 - a revisao do teste não mostra as imagens. 11 - a revisao do teste não mostra as imagens.
13 - Test.reset_answers() unused. 12 - Test.reset_answers() unused.
14 -- incluir test_id na tabela questions (futuro semestre, pode quebrar compatibilidade).  
15 -- na pagina admin, mostrar com cor vermelha as horas de entrada dos alunos que ja tenham excedido o tempo 13 +- teste nao esta a mostrar imagens de vez em quando.???
16 14
17 # TODO 15 # TODO
18 16
  17 +- na pagina admin, mostrar com cor vermelha as horas de entrada dos alunos que ja tenham excedido o tempo
19 - retornar None quando nao ha alteracoes relativamente à última vez. 18 - retornar None quando nao ha alteracoes relativamente à última vez.
20 ou usar push (websockets?) 19 ou usar push (websockets?)
21 - mudar ref do test para test_id (ref já é usado nas perguntas) 20 - mudar ref do test para test_id (ref já é usado nas perguntas)
demo/demo.yaml
1 --- 1 ---
2 # ============================================================================ 2 # ============================================================================
3 # Unique identifier of the test. 3 # Unique identifier of the test.
  4 +# Valid names can only include letters, digits, dash and underscore,
  5 +# e.g. asc1-test3
4 # Database queries can be done in the terminal with 6 # Database queries can be done in the terminal with
5 -# sqlite3 students.db "select * from tests where ref='tutorial'" 7 +# sqlite3 students.db "select * from tests where ref='asc1-test3'"
6 ref: tutorial 8 ref: tutorial
7 9
8 # Database file that includes student credentials, tests and questions grades. 10 # Database file that includes student credentials, tests and questions grades.
@@ -20,9 +22,9 @@ title: Teste de demonstração (tutorial) @@ -20,9 +22,9 @@ title: Teste de demonstração (tutorial)
20 22
21 # Duration in minutes. 23 # Duration in minutes.
22 # (0 or undefined means infinite time) 24 # (0 or undefined means infinite time)
23 -duration: 2 25 +duration: 0
24 26
25 -# Automatic test submission after the timeout 'duration'? 27 +# Automatic test submission after the given 'duration' timeout
26 # (default: false) 28 # (default: false)
27 autosubmit: true 29 autosubmit: true
28 30
@@ -40,9 +42,6 @@ scale: [0, 5] @@ -40,9 +42,6 @@ scale: [0, 5]
40 # scale_min: 0 42 # scale_min: 0
41 # scale_points: true 43 # scale_points: true
42 44
43 -show_ref: true  
44 -debug: false  
45 -  
46 # ---------------------------------------------------------------------------- 45 # ----------------------------------------------------------------------------
47 # Base path applied to the questions files and all the scripts 46 # Base path applied to the questions files and all the scripts
48 # including question generators and correctors. 47 # including question generators and correctors.
@@ -75,7 +74,7 @@ questions: @@ -75,7 +74,7 @@ questions:
75 - tut-warning 74 - tut-warning
76 - [tut-alert1, tut-alert2] 75 - [tut-alert1, tut-alert2]
77 - tut-generator 76 - tut-generator
78 - 77 + - tut-yamllint
79 78
80 # test: 79 # test:
81 # - ref1 80 # - ref1
demo/questions/generators/generate-question.py
@@ -18,11 +18,10 @@ print(f&quot;&quot;&quot;--- @@ -18,11 +18,10 @@ print(f&quot;&quot;&quot;---
18 type: text 18 type: text
19 title: Geradores de perguntas 19 title: Geradores de perguntas
20 text: | 20 text: |
21 - Existe a possibilidade da pergunta ser gerada por um programa externo. Este  
22 - programa deve escrever no `stdout` uma pergunta em formato `yaml` como nos 21 + Existe a possibilidade da pergunta ser gerada por um programa externo. O
  22 + programa deve escrever no `stdout` uma pergunta em formato `yaml` tal como os
23 exemplos anteriores. Pode também receber argumentos para parametrizar a 23 exemplos anteriores. Pode também receber argumentos para parametrizar a
24 - geração da pergunta. Aqui está um exemplo de uma pergunta gerada por um  
25 - script python: 24 + pergunta. Aqui está um exemplo de uma pergunta gerada por um script python:
26 25
27 ```python 26 ```python
28 #!/usr/bin/env python3 27 #!/usr/bin/env python3
@@ -46,9 +45,7 @@ text: | @@ -46,9 +45,7 @@ text: |
46 A solução é {{r}}.''') 45 A solução é {{r}}.''')
47 ``` 46 ```
48 47
49 - Este script deve ter permissões para poder ser executado no terminal. Dá  
50 - jeito usar o comando `gen-somar.py 1 100 | yamllint -` para validar o `yaml`  
51 - gerado. 48 + Este script deve ter permissões para poder ser executado no terminal.
52 49
53 Para indicar que uma pergunta é gerada externamente, esta é declarada com 50 Para indicar que uma pergunta é gerada externamente, esta é declarada com
54 51
@@ -56,12 +53,12 @@ text: | @@ -56,12 +53,12 @@ text: |
56 - type: generator 53 - type: generator
57 ref: gen-somar 54 ref: gen-somar
58 script: gen-somar.py 55 script: gen-somar.py
59 - # opcional 56 + # argumentos opcionais
60 args: [1, 100] 57 args: [1, 100]
61 ``` 58 ```
62 59
63 - Os argumentos `args` são opcionais e são passados para o programa como  
64 - argumentos da linha de comando. 60 + Opcionalmente, o programa pode receber uma lista de argumentos declarados em
  61 + `args`.
65 62
66 --- 63 ---
67 64
demo/questions/questions-tutorial.yaml
@@ -581,3 +581,25 @@ @@ -581,3 +581,25 @@
581 ref: tut-generator 581 ref: tut-generator
582 script: generators/generate-question.py 582 script: generators/generate-question.py
583 args: [1, 100] 583 args: [1, 100]
  584 +
  585 +# ----------------------------------------------------------------------------
  586 +- type: information
  587 + ref: tut-yamllint
  588 + title: Sugestões para validar yaml
  589 + text: |
  590 + Como os testes e perguntas são ficheiros `yaml`, é conveniente validar se
  591 + estão correctamente definitos. Um *linter* recomendado é o `yamllint`. Pode
  592 + ser instalado com `pip install yamllint` e usado do seguinte modo:
  593 +
  594 + ```sh
  595 + yamllint test.yaml
  596 + yamllint questions.yaml
  597 + ```
  598 +
  599 + No caso de programas geradores de perguntas e programas de correcção de
  600 + respostas pode usar-se um *pipe*:
  601 +
  602 + ```sh
  603 + generate-question | yamllint -
  604 + correct-answer | yamllint -
  605 + ```
perguntations/__init__.py
@@ -32,7 +32,7 @@ proof of submission and for review. @@ -32,7 +32,7 @@ proof of submission and for review.
32 ''' 32 '''
33 33
34 APP_NAME = 'perguntations' 34 APP_NAME = 'perguntations'
35 -APP_VERSION = '2020.05.dev2' 35 +APP_VERSION = '2020.05.dev3'
36 APP_DESCRIPTION = __doc__ 36 APP_DESCRIPTION = __doc__
37 37
38 __author__ = 'Miguel Barão' 38 __author__ = 'Miguel Barão'
perguntations/app.py
@@ -276,8 +276,9 @@ class App(): @@ -276,8 +276,9 @@ class App():
276 uid, area, win_x, win_y, scr_x, scr_y) 276 uid, area, win_x, win_y, scr_x, scr_y)
277 277
278 # ------------------------------------------------------------------------ 278 # ------------------------------------------------------------------------
  279 + # --- GETTERS
  280 + # ------------------------------------------------------------------------
279 281
280 - # --- helpers (getters)  
281 # def get_student_name(self, uid): 282 # def get_student_name(self, uid):
282 # return self.online[uid]['student']['name'] 283 # return self.online[uid]['student']['name']
283 284
@@ -388,7 +389,10 @@ class App(): @@ -388,7 +389,10 @@ class App():
388 # if q['ref'] == ref and key in q['files']: 389 # if q['ref'] == ref and key in q['files']:
389 # return path.abspath(path.join(q['path'], q['files'][key])) 390 # return path.abspath(path.join(q['path'], q['files'][key]))
390 391
391 - # --- helpers (change state) 392 + # ------------------------------------------------------------------------
  393 + # --- SETTERS
  394 + # ------------------------------------------------------------------------
  395 +
392 def allow_student(self, uid): 396 def allow_student(self, uid):
393 '''allow a single student to login''' 397 '''allow a single student to login'''
394 self.allowed.add(uid) 398 self.allowed.add(uid)
perguntations/models.py
@@ -90,5 +90,5 @@ class Question(Base): @@ -90,5 +90,5 @@ class Question(Base):
90 f' grade: "{self.grade}"\n' 90 f' grade: "{self.grade}"\n'
91 f' starttime: "{self.starttime}"\n' 91 f' starttime: "{self.starttime}"\n'
92 f' finishtime: "{self.finishtime}"\n' 92 f' finishtime: "{self.finishtime}"\n'
93 - f' student_id: "{self.student_id}"\n' 93 + f' student_id: "{self.student_id}"\n' # FIXME normal form
94 f' test_id: "{self.test_id}"\n') 94 f' test_id: "{self.test_id}"\n')
perguntations/serve.py
@@ -246,7 +246,7 @@ class AdminHandler(BaseHandler): @@ -246,7 +246,7 @@ class AdminHandler(BaseHandler):
246 self.testapp.deny_student(value) 246 self.testapp.deny_student(value)
247 247
248 elif cmd == 'reset_password': 248 elif cmd == 'reset_password':
249 - await self.testapp.update_student_password(uid=value, pw='') 249 + await self.testapp.update_student_password(uid=value, password='')
250 250
251 elif cmd == 'insert_student': 251 elif cmd == 'insert_student':
252 student = json.loads(value) 252 student = json.loads(value)
perguntations/templates/review-question-information.html
@@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
18 </div> 18 </div>
19 {% if t['show_ref'] %} 19 {% if t['show_ref'] %}
20 <hr> 20 <hr>
21 - File: <code>{{ q['path'] }}/{{ q['filename'] }}</code>,  
22 - Ref: <code>{{ q['ref'] }}</code> 21 + file: <code>{{ q['path'] }}/{{ q['filename'] }}</code><br>
  22 + ref: <code>{{ q['ref'] }}</code>
23 {% end %} 23 {% end %}
24 </div> 24 </div>
25 \ No newline at end of file 25 \ No newline at end of file
perguntations/templates/review-question.html
@@ -66,8 +66,8 @@ @@ -66,8 +66,8 @@
66 66
67 {% if t['show_ref'] %} 67 {% if t['show_ref'] %}
68 <hr> 68 <hr>
69 - File: <code>{{ q['path'] }}/{{ q['filename'] }}</code>,  
70 - Ref: <code>{{ q['ref'] }}</code> 69 + file: <code>{{ q['path'] }}/{{ q['filename'] }}</code><br>
  70 + ref: <code>{{ q['ref'] }}</code>
71 {% end %} 71 {% end %}
72 72
73 </div> <!-- card-footer --> 73 </div> <!-- card-footer -->
@@ -110,8 +110,8 @@ @@ -110,8 +110,8 @@
110 110
111 {% if t['show_ref'] %} 111 {% if t['show_ref'] %}
112 <hr> 112 <hr>
113 - File: <code>{{ q['path'] }}/{{ q['filename'] }}</code>,  
114 - Ref: <code>{{ q['ref'] }}</code> 113 + file: <code>{{ q['path'] }}/{{ q['filename'] }}</code><br>
  114 + ref: <code>{{ q['ref'] }}</code>
115 {% end %} 115 {% end %}
116 116
117 </div> <!-- card-footer --> 117 </div> <!-- card-footer -->