Commit cd56848f1c40fdd4c91399b1ed666fe11436c8da

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

- review is working.

- fixed markdown rendering in questions.
1 1
2 # BUGS 2 # BUGS
3 3
  4 +- markdown no teste nao funciona
4 - numeracao das perguntas do teste esta a contar com paineis informativos... 5 - numeracao das perguntas do teste esta a contar com paineis informativos...
5 - servir imagens das perguntas 6 - servir imagens das perguntas
6 -- review de um teste nao funciona (hardcoded...)  
7 -- testar opcao --allow-all  
8 - como alterar configuracao para mostrar logs de debug? 7 - como alterar configuracao para mostrar logs de debug?
9 - hints nao funciona 8 - hints nao funciona
10 - uniformizar question.py com a de aprendizations... 9 - uniformizar question.py com a de aprendizations...
@@ -14,6 +13,14 @@ @@ -14,6 +13,14 @@
14 13
15 # TODO 14 # TODO
16 15
  16 +- mathjax-node:
  17 + sudo pkg install node npm
  18 + npm install mathjax-node mathjax-node-cli # pacotes em ~/node_modules
  19 + node_modules/mathjax-node-cli/bin/tex2svg '\sqrt{x}'
  20 + usar isto para gerar svg que passa a fazer parte do texto da pergunta (markdown suporta tags svg?)
  21 +
  22 +
  23 +
17 - Gerar pdf's com todos os testes no final (pdfkit). 24 - Gerar pdf's com todos os testes no final (pdfkit).
18 - manter registo dos unfocus durante o teste e de qual a pergunta visivel nesse momento 25 - manter registo dos unfocus durante o teste e de qual a pergunta visivel nesse momento
19 26
@@ -31,6 +38,7 @@ @@ -31,6 +38,7 @@
31 38
32 # FIXED 39 # FIXED
33 40
  41 +- review de um teste nao funciona (hardcoded...)
34 - testar SSL 42 - testar SSL
35 - text-numeric não está a gerar a pergunta. faltam templates? 43 - text-numeric não está a gerar a pergunta. faltam templates?
36 - testar perguntas warning/warn 44 - testar perguntas warning/warn
demo/questions/questions-tutorial.yaml
@@ -2,19 +2,41 @@ @@ -2,19 +2,41 @@
2 ref: tut-information 2 ref: tut-information
3 type: information 3 type: information
4 title: information (ou info) 4 title: information (ou info)
5 - text: Texto informativo. Não conta para avaliação. 5 + text: |
  6 + Texto informativo. Não conta para avaliação.
  7 +
  8 + $$ p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$
6 # --------------------------------------------------------------------------- 9 # ---------------------------------------------------------------------------
7 - 10 -
8 ref: tut-success 11 ref: tut-success
9 type: success 12 type: success
10 title: success 13 title: success
11 - text: Texto de positivo (sucesso). Não conta para avaliação. 14 + text: |
  15 + Texto de positivo (sucesso). Não conta para avaliação.
  16 +
  17 + ```C
  18 + int main() {
  19 + printf("Hello world!");
  20 + return 0; // comentario
  21 + }
  22 + ```
  23 +
  24 + Inline `code`.
  25 +
12 # --------------------------------------------------------------------------- 26 # ---------------------------------------------------------------------------
13 - 27 -
14 ref: tut-warning 28 ref: tut-warning
15 type: warning 29 type: warning
16 title: warning (ou warn) 30 title: warning (ou warn)
17 - text: Texto de aviso. Não conta para avaliação. 31 + text: |
  32 + Texto de aviso. Não conta para avaliação.
  33 +
  34 + Left | Center | Right
  35 + -----------------|:-------------:|----------:
  36 + $\sin(x^2)$ | *hello* | $1600.00
  37 + $\frac{1}{2\pi}$ | **world** | $12.50
  38 + $\sqrt{\pi}$ | `code` | $1.99
  39 +
18 # ---------------------------------------------------------------------------- 40 # ----------------------------------------------------------------------------
19 - 41 -
20 ref: tut-alert 42 ref: tut-alert
@@ -48,7 +70,7 @@ @@ -48,7 +70,7 @@
48 - Opção 3 (sim) 70 - Opção 3 (sim)
49 correct: [1,-1,-1,1] 71 correct: [1,-1,-1,1]
50 # opcionais e valores por defeito 72 # opcionais e valores por defeito
51 - shuffle: True 73 + shuffle: True
52 # ---------------------------------------------------------------------------- 74 # ----------------------------------------------------------------------------
53 - 75 -
54 ref: tut-text 76 ref: tut-text
@@ -82,8 +104,8 @@ @@ -82,8 +104,8 @@
82 type: textarea 104 type: textarea
83 title: textarea 105 title: textarea
84 text: | 106 text: |
85 - Resposta num bloco de texto que pode ser usado para introduzir código.  
86 - A resposta é avaliada por um programa externo. 107 + Resposta num bloco de texto que pode ser usado para introduzir código.
  108 + A resposta é avaliada por um programa externo.
87 O programa externo, recebe a resposta no stdin e devolve a classificação no stdout. 109 O programa externo, recebe a resposta no stdin e devolve a classificação no stdout.
88 Neste exemplo, o programa de avaliação verifica se a resposta contém as três palavras red, green e blue. 110 Neste exemplo, o programa de avaliação verifica se a resposta contém as três palavras red, green e blue.
89 correct: correct/correct-question.py 111 correct: correct/correct-question.py
demo/questions/questions.yaml
@@ -70,7 +70,7 @@ @@ -70,7 +70,7 @@
70 # --------------------------------------------------------------------------- 70 # ---------------------------------------------------------------------------
71 - 71 -
72 ref: fractions 72 ref: fractions
73 - type: text-numeric 73 + type: numeric-interval
74 text: Quanto é 1/4? 74 text: Quanto é 1/4?
75 correct: [0.249, 0.251] 75 correct: [0.249, 0.251]
76 # --------------------------------------------------------------------------- 76 # ---------------------------------------------------------------------------
@@ -163,7 +163,7 @@ class TestHandler(BaseHandler): @@ -163,7 +163,7 @@ class TestHandler(BaseHandler):
163 163
164 # --- REVIEW ------------------------------------------------------------- 164 # --- REVIEW -------------------------------------------------------------
165 class ReviewHandler(BaseHandler): 165 class ReviewHandler(BaseHandler):
166 - templates = { 166 + _templates = {
167 'radio': 'review-question-radio.html', 167 'radio': 'review-question-radio.html',
168 'checkbox': 'review-question-checkbox.html', 168 'checkbox': 'review-question-checkbox.html',
169 'text': 'review-question-text.html', 169 'text': 'review-question-text.html',
@@ -181,12 +181,13 @@ class ReviewHandler(BaseHandler): @@ -181,12 +181,13 @@ class ReviewHandler(BaseHandler):
181 181
182 @tornado.web.authenticated 182 @tornado.web.authenticated
183 def get(self): 183 def get(self):
184 - test_id=45 # FIXME  
185 -  
186 uid = self.current_user 184 uid = self.current_user
187 if uid != '0': 185 if uid != '0':
188 self.redirect('/') # FIXME 404 not found? 186 self.redirect('/') # FIXME 404 not found?
189 187
  188 + test_id = self.get_query_argument('test_id', None)
  189 + # FIXME if test_id does not exist...
  190 +
190 fname = self.testapp.get_json_filename_of_test(test_id) 191 fname = self.testapp.get_json_filename_of_test(test_id)
191 try: 192 try:
192 f = open(path.expanduser(fname)) 193 f = open(path.expanduser(fname))
@@ -197,7 +198,7 @@ class ReviewHandler(BaseHandler): @@ -197,7 +198,7 @@ class ReviewHandler(BaseHandler):
197 else: 198 else:
198 with f: 199 with f:
199 t = json.load(f) 200 t = json.load(f)
200 - self.render('review.html', t=t, md=md_to_html_review, templ=self.templates) 201 + self.render('review.html', t=t, md=md_to_html_review, templ=self._templates)
201 202
202 203
203 # @cherrypy.expose 204 # @cherrypy.expose
templates/grade.html
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <!-- ===================================================================== --> 16 <!-- ===================================================================== -->
17 <body> 17 <body>
18 18
19 -<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark"> 19 +<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark">
20 <a class="navbar-brand" href="#">{{t['title']}}</a> 20 <a class="navbar-brand" href="#">{{t['title']}}</a>
21 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> 21 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
22 <span class="navbar-toggler-icon"></span> 22 <span class="navbar-toggler-icon"></span>
templates/question-alert.html
@@ -3,10 +3,10 @@ @@ -3,10 +3,10 @@
3 3
4 <div class="alert alert-danger border-danger" role="alert"> 4 <div class="alert alert-danger border-danger" role="alert">
5 <h3> 5 <h3>
6 - {{ question['title'] }} 6 + {{ q['title'] }}
7 </h3> 7 </h3>
8 8
9 <div id="text"> 9 <div id="text">
10 - {{ md(question['text']) }} 10 + {{ md(q['text'], q) }}
11 </div> 11 </div>
12 </div> 12 </div>
templates/question-checkbox.html
@@ -4,13 +4,12 @@ @@ -4,13 +4,12 @@
4 {% block answer %} 4 {% block answer %}
5 <fieldset data-role="controlgroup"> 5 <fieldset data-role="controlgroup">
6 <div class="list-group"> 6 <div class="list-group">
7 - {% for n, opt in enumerate(question['options']) %} 7 + {% for n, opt in enumerate(q['options']) %}
8 <a class="list-group-item"> 8 <a class="list-group-item">
9 <input type="checkbox" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}"> 9 <input type="checkbox" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}">
10 - <label for="{{n}}">{{ md(opt, question['ref'], question['files']) }}</label> 10 + <label for="{{n}}">{{ md(opt, q['ref'], q['files']) }}</label>
11 </a> 11 </a>
12 {% end %} 12 {% end %}
13 </div> 13 </div>
14 </fieldset> 14 </fieldset>
15 -<input type="hidden" name="question_ref" value="{{ question['ref'] }}">  
16 {% end %} 15 {% end %}
17 \ No newline at end of file 16 \ No newline at end of file
templates/question-information.html
@@ -3,10 +3,10 @@ @@ -3,10 +3,10 @@
3 3
4 <div class="alert alert-info border-info" role="alert"> 4 <div class="alert alert-info border-info" role="alert">
5 <h3> 5 <h3>
6 - {{ question['title'] }} 6 + {{ q['title'] }}
7 </h3> 7 </h3>
8 8
9 <div id="text"> 9 <div id="text">
10 - {{ md(question['text']) }} 10 + {{ md(q['text'], q) }}
11 </div> 11 </div>
12 </div> 12 </div>
13 \ No newline at end of file 13 \ No newline at end of file
templates/question-radio.html
@@ -4,10 +4,10 @@ @@ -4,10 +4,10 @@
4 {% block answer %} 4 {% block answer %}
5 <fieldset data-role="controlgroup"> 5 <fieldset data-role="controlgroup">
6 <div class="list-group"> 6 <div class="list-group">
7 - {% for n, opt in enumerate(question['options']) %} 7 + {% for n, opt in enumerate(q['options']) %}
8 <a class="list-group-item"> 8 <a class="list-group-item">
9 <input type="radio" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}"> 9 <input type="radio" id="{{i}}:{{n}}" name="{{i}}" value="{{n}}">
10 - <label for="{{n}}">{{ md(opt, question['ref'], question['files']) }}</label> 10 + <label for="{{n}}">{{ md(opt, q['ref'], q['files']) }}</label>
11 </a> 11 </a>
12 {% end %} 12 {% end %}
13 </div> 13 </div>
templates/question-success.html
@@ -3,10 +3,10 @@ @@ -3,10 +3,10 @@
3 3
4 <div class="alert alert-success border-success" role="alert"> 4 <div class="alert alert-success border-success" role="alert">
5 <h3> 5 <h3>
6 - {{ question['title'] }} 6 + {{ q['title'] }}
7 </h3> 7 </h3>
8 8
9 <div id="text"> 9 <div id="text">
10 - {{ md(question['text']) }} 10 + {{ md(q['text'], q) }}
11 </div> 11 </div>
12 </div> 12 </div>
templates/question-textarea.html
1 {% extends "question.html" %} 1 {% extends "question.html" %}
2 2
3 {% block answer %} 3 {% block answer %}
4 -  
5 -<textarea class="form-control" rows="{{ question['lines'] }}" name="{{i}}">{{ question['answer'] or '' }}</textarea><br />  
6 -<input type="hidden" name="question_ref" value="{{ question['ref'] }}">  
7 - 4 +<textarea class="form-control" rows="{{q['lines']}}" name="{{i}}">{{q['answer'] or ''}}</textarea><br />
8 {% end %} 5 {% end %}
templates/question-warning.html
@@ -3,10 +3,10 @@ @@ -3,10 +3,10 @@
3 3
4 <div class="alert alert-warning border-warning" role="alert"> 4 <div class="alert alert-warning border-warning" role="alert">
5 <h3> 5 <h3>
6 - {{ question['title'] }} 6 + {{ q['title'] }}
7 </h3> 7 </h3>
8 8
9 <div id="text"> 9 <div id="text">
10 - {{ md(question['text']) }} 10 + {{ md(q['text'], q) }}
11 </div> 11 </div>
12 </div> 12 </div>
templates/question.html
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 {% block question %} 3 {% block question %}
4 <div class="card border-dark mb-3"> 4 <div class="card border-dark mb-3">
5 <h5 class="card-header text-white bg-dark"> 5 <h5 class="card-header text-white bg-dark">
6 - {{ i+1 }}. {{ question['title'] }} 6 + {{ i+1 }}. {{ q['title'] }}
7 <div class="pull-right"> 7 <div class="pull-right">
8 <small>Classificar&nbsp;</small> 8 <small>Classificar&nbsp;</small>
9 <input type="checkbox" class="question_disabler" data-size="mini" name="answered-{{i}}" id="answered-{{i}}" checked=""> 9 <input type="checkbox" class="question_disabler" data-size="mini" name="answered-{{i}}" id="answered-{{i}}" checked="">
@@ -11,14 +11,14 @@ @@ -11,14 +11,14 @@
11 </h5> 11 </h5>
12 <div class="card-body"> 12 <div class="card-body">
13 <div id="text"> 13 <div id="text">
14 - {{ question['text'] }} 14 + {{ md(q['text'], md) }}
15 </div> 15 </div>
16 16
17 {% block answer %}{% end %} 17 {% block answer %}{% end %}
18 18
19 <p class="text-right"> 19 <p class="text-right">
20 <small> 20 <small>
21 - (Cotação: {{ round(question['points'], 2) }} pontos) 21 + (Cotação: {{ round(q['points'], 2) }} pontos)
22 </small> 22 </small>
23 </p> 23 </p>
24 24
templates/review-question-checkbox.html
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 {% if q['correct'][n] > 0 %} 11 {% if q['correct'][n] > 0 %}
12 <div class="text-right text-success"> 12 <div class="text-right text-success">
13 <i class="fa fa-check" aria-hidden="true"></i> 13 <i class="fa fa-check" aria-hidden="true"></i>
14 - </div> 14 + </div>
15 {% else %} 15 {% else %}
16 <div class="text-right text-danger"> 16 <div class="text-right text-danger">
17 <i class="fa fa-close" aria-hidden="true"></i> 17 <i class="fa fa-close" aria-hidden="true"></i>
@@ -19,9 +19,8 @@ @@ -19,9 +19,8 @@
19 {% end %} 19 {% end %}
20 {% else %} 20 {% else %}
21 {{ md('<i class="fa fa-square-o" aria-hidden="true"></i> ' + opt, q) }} 21 {{ md('<i class="fa fa-square-o" aria-hidden="true"></i> ' + opt, q) }}
22 -  
23 {% if q['correct'][n] > 0 %} 22 {% if q['correct'][n] > 0 %}
24 - <div class="text-right text-info"> 23 + <div class="text-right text-danger">
25 <i class="fa fa-close" aria-hidden="true"></i> 24 <i class="fa fa-close" aria-hidden="true"></i>
26 </div> 25 </div>
27 {% elif q['correct'][n] < 0 %} 26 {% elif q['correct'][n] < 0 %}
templates/review-question-text.html
@@ -2,5 +2,12 @@ @@ -2,5 +2,12 @@
2 {% autoescape %} 2 {% autoescape %}
3 3
4 {% block answer %} 4 {% block answer %}
  5 +
  6 +<div class="card bg-light">
  7 + <div class="card-body">
5 <pre>{{ q['answer'] if q['answer'] is not None else '' }}</pre> 8 <pre>{{ q['answer'] if q['answer'] is not None else '' }}</pre>
  9 + </div>
  10 +</div>
  11 +
  12 +
6 {% end %} 13 {% end %}
7 \ No newline at end of file 14 \ No newline at end of file
templates/review-question.html
@@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
16 </h5> 16 </h5>
17 17
18 <div class="card-body"> 18 <div class="card-body">
19 - <div id="text"> 19 + <p id="text">
20 {{ q['text'] }} 20 {{ q['text'] }}
21 - </div> 21 + </p>
22 22
23 {% block answer %}{% end %} 23 {% block answer %}{% end %}
24 24
25 {% if t['show_points'] %} 25 {% if t['show_points'] %}
26 <p class="text-right"> 26 <p class="text-right">
27 <small> 27 <small>
28 - (Cotação: {{ q['points'] }}) 28 + (Cotação: {{ round(q['points'], 2) }})
29 </small> 29 </small>
30 </p> 30 </p>
31 {% end %} 31 {% end %}
@@ -43,14 +43,14 @@ @@ -43,14 +43,14 @@
43 {% elif q['grade'] > 0.49 %} 43 {% elif q['grade'] > 0.49 %}
44 <p class="text-warning"> 44 <p class="text-warning">
45 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> 45 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
46 - {{ round(q['grade'] * q['points'], 2) }} 46 + {{ round(q['grade'] * q['points'], 2) }}
47 pontos<br> 47 pontos<br>
48 {{ q['comments'] }} 48 {{ q['comments'] }}
49 </p> 49 </p>
50 {% else %} 50 {% else %}
51 <p class="text-danger"> 51 <p class="text-danger">
52 <i class="fa fa-thumbs-o-down" aria-hidden="true"></i> 52 <i class="fa fa-thumbs-o-down" aria-hidden="true"></i>
53 - {{ round(q['grade'] * q['points'], 2) }} 53 + {{ round(q['grade'] * q['points'], 2) }}
54 pontos<br> 54 pontos<br>
55 {{ q['comments'] }} 55 {{ q['comments'] }}
56 </p> 56 </p>
templates/review.html
@@ -27,32 +27,53 @@ @@ -27,32 +27,53 @@
27 </head> 27 </head>
28 <!-- ===================================================================== --> 28 <!-- ===================================================================== -->
29 <body> 29 <body>
30 -<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary"> 30 +<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark">
31 <a class="navbar-brand" href="#">Revisão de prova</a> 31 <a class="navbar-brand" href="#">Revisão de prova</a>
32 </nav> 32 </nav>
33 <!-- ===================================================================== --> 33 <!-- ===================================================================== -->
34 <div class="container"> 34 <div class="container">
35 - <div class="jumbotron">  
36 - <big>  
37 - <dl class="dl-horizontal">  
38 - <dt>Prova:</dt><dd>{{t['title']}}</dd>  
39 - <dt>Nome:</dt><dd>{{t['student']['name']}}</dd>  
40 - <dt>Número:</dt><dd>{{t['student']['number']}}</dd>  
41 - <dt>Início:</dt><dd>{{t['start_time'][:19]}}</dd>  
42 - <dt>Fim:</dt><dd>{{t['finish_time'][:19]}}</dd>  
43 - <dt>Nota:</dt>  
44 - <dd>  
45 - <span class="label label-primary">{{ t['grade'] }}</span> valores  
46 - {% if t['state'] == 'QUIT' %}  
47 - (DESISTÊNCIA)  
48 - {% end %}  
49 - </dd>  
50 - {% if t['comment'] != '' %}  
51 - <dt>Comentário:</dt><dd>{{ t['comment'] }}</dd>  
52 - {% end %}  
53 - </dl>  
54 - </big>  
55 - </div> 35 + <div class="jumbotron">
  36 + <h1 class="display-5">{{ t['title'] }}</h1>
  37 + {{ t.get('duration', '') }}
  38 + <hr>
  39 +
  40 + <h3>
  41 + <div class="row">
  42 + <!-- <label for="nome" class="col-sm-1">Nome:</label> -->
  43 + <div class="col-sm-8" id="nome">{{t['student']['name']}}</div>
  44 + <label for="nome" class="col-sm-1">Nº.</label>
  45 + <div class="col-sm-3" id="numero">{{t['student']['number']}}</div>
  46 + </div>
  47 + </h3>
  48 +
  49 + <h5>
  50 + <div class="row">
  51 + <label for="inicio" class="col-sm-2">Início:</label>
  52 + <div class="col-sm-10" id="inicio">{{t['start_time'][:19]}}</div>
  53 + </div>
  54 + <div class="row">
  55 + <label for="fim" class="col-sm-2">Fim:</label>
  56 + <div class="col-sm-10" id="fim">{{t['finish_time'][:19]}}</div>
  57 + </div>
  58 + </h5>
  59 + <h3>
  60 + <div class="row">
  61 + <label for="nota" class="col-sm-2">Nota:</label>
  62 + <div class="col-sm-10" id="nota">
  63 + <span class="badge badge-primary">{{ t['grade'] }}</span> valores
  64 + {% if t['state'] == 'QUIT' %}
  65 + (DESISTÊNCIA)
  66 + {% end %}
  67 + </div>
  68 + </div>
  69 + {% if t['comment'] != '' %}
  70 + <div class="row">
  71 + <label for="comentario" class="col-sm-2">Comentário:</label>
  72 + <div class="col-sm-10" id="comentario">{{ t['comment'] }}</div>
  73 + </div>
  74 + {% end %}
  75 + </h3>
  76 + </div>
56 77
57 {% for i, q in enumerate(t['questions']) %} 78 {% for i, q in enumerate(t['questions']) %}
58 {% module Template(templ[q['type']], i=i, q=q, md=md, t=t) %} 79 {% module Template(templ[q['type']], i=i, q=q, md=md, t=t) %}
templates/test.html
@@ -61,17 +61,28 @@ @@ -61,17 +61,28 @@
61 </span> 61 </span>
62 </div> 62 </div>
63 </nav> 63 </nav>
64 -<!-- ===================================================================== -->  
65 <div class="container"> 64 <div class="container">
66 65
67 <div class="jumbotron"> 66 <div class="jumbotron">
68 <h1 class="display-5">{{ t['title'] }}</h1> 67 <h1 class="display-5">{{ t['title'] }}</h1>
69 {{ t.get('duration', '') }} 68 {{ t.get('duration', '') }}
  69 + <hr>
  70 +
  71 + <h5>
  72 + <div class="row">
  73 + <label for="inicio" class="col-sm-2">Início:</label>
  74 + <div class="col-sm-10" id="inicio">{{ str(t['start_time'].time())[:8]}}</div>
  75 + </div>
  76 + <div class="row">
  77 + <label for="duracao" class="col-sm-2">Duração:</label>
  78 + <div class="col-sm-10" id="duracao">{{ t.get('duration', chr(8734)) }}</div>
  79 + </div>
  80 + </h5>
70 </div> 81 </div>
71 82
72 <form action="/test" method="post" id="test" autocomplete="off"> 83 <form action="/test" method="post" id="test" autocomplete="off">
73 {% for i, q in enumerate(t['questions']) %} 84 {% for i, q in enumerate(t['questions']) %}
74 - {% module Template(templ[q['type']], i=i, question=q, md=md) %} 85 + {% module Template(templ[q['type']], i=i, q=q, md=md) %}
75 {% end %} 86 {% end %}
76 87
77 <div class="form-row"> 88 <div class="form-row">
@@ -84,47 +95,51 @@ @@ -84,47 +95,51 @@
84 </div> 95 </div>
85 </form> 96 </form>
86 <hr> 97 <hr>
  98 +</div> <!-- container -->
87 99
88 - <!-- Modal de confirmacao submissao -->  
89 - <div class="modal fade" id="confirmar" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">  
90 - <div class="modal-dialog" role="document">  
91 - <div class="modal-content">  
92 - <div class="modal-header">  
93 - <h4 class="modal-title">Deseja submeter o teste?</h4>  
94 - </div>  
95 - <div class="modal-body">  
96 - O teste será enviado para classificação e já não poderá voltar atrás.  
97 - Antes de submeter, veja se respondeu a todas as questões e desactive as que não pretende classificar.  
98 - </div>  
99 - <div class="modal-footer">  
100 - <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Oops, NÃO!!!</button>  
101 - <button form="test" type="submit" class="btn btn-success btn-lg">Sim, submeter...</button>  
102 - </div>  
103 - </div> 100 +<!-- ===================================================================== -->
  101 +
  102 +<!-- Modal de confirmacao submissao -->
  103 +<div class="modal fade" id="confirmar" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  104 + <div class="modal-dialog" role="document">
  105 + <div class="modal-content">
  106 + <div class="modal-header">
  107 + <h4 class="modal-title">Deseja submeter o teste?</h4>
  108 + </div>
  109 + <div class="modal-body">
  110 + O teste será enviado para classificação e já não poderá voltar atrás.
  111 + Antes de submeter, veja se respondeu a todas as questões e desactive as que não pretende classificar.
  112 + </div>
  113 + <div class="modal-footer">
  114 + <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Oops, NÃO!!!</button>
  115 + <button form="test" type="submit" class="btn btn-success btn-lg">Sim, submeter...</button>
104 </div> 116 </div>
105 </div> 117 </div>
  118 + </div>
  119 +</div>
106 120
107 - <!-- Modal de confirmacao sair -->  
108 - <div class="modal fade" id="sair" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">  
109 - <div class="modal-dialog" role="document">  
110 - <div class="modal-content">  
111 - <div class="modal-header">  
112 - <h4 class="modal-title">Deseja desistir?</h4>  
113 - </div>  
114 - <div class="modal-body">  
115 - Se desistir, será registada a desistência da prova e terá uma classificação de 0 valores.  
116 - </div>  
117 - <div class="modal-footer">  
118 - <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Não!</button>  
119 - <a href="/giveup" class="btn btn-success btn-lg" role="button">Sim, desisto</a>  
120 - </div>  
121 - </div> 121 +<!-- Modal de confirmacao sair -->
  122 +<div class="modal fade" id="sair" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  123 + <div class="modal-dialog" role="document">
  124 + <div class="modal-content">
  125 + <div class="modal-header">
  126 + <h4 class="modal-title">Deseja desistir?</h4>
  127 + </div>
  128 + <div class="modal-body">
  129 + Se desistir, será registada a desistência da prova e terá uma classificação de 0 valores.
  130 + </div>
  131 + <div class="modal-footer">
  132 + <button type="button" class="btn btn-danger btn-lg" data-dismiss="modal">Não!</button>
  133 + <a href="/giveup" class="btn btn-success btn-lg" role="button">Sim, desisto</a>
122 </div> 134 </div>
123 </div> 135 </div>
124 - 136 + </div>
125 </div> 137 </div>
126 138
127 139
  140 +
  141 +<!-- ===================================================================== -->
  142 +
128 <!-- Scripts --> 143 <!-- Scripts -->
129 <script src="/static/js/jquery.min.js"></script> 144 <script src="/static/js/jquery.min.js"></script>
130 <script src="/static/popper/umd/popper.min.js"></script> 145 <script src="/static/popper/umd/popper.min.js"></script>
@@ -145,6 +145,7 @@ class TestFactory(dict): @@ -145,6 +145,7 @@ class TestFactory(dict):
145 test = [] 145 test = []
146 total_points = 0.0 146 total_points = 0.0
147 147
  148 + n = 1
148 for qq in self['questions']: 149 for qq in self['questions']:
149 # generate Question() selected randomly from list of references 150 # generate Question() selected randomly from list of references
150 qref = random.choice(qq['ref']) 151 qref = random.choice(qq['ref'])
@@ -160,6 +161,8 @@ class TestFactory(dict): @@ -160,6 +161,8 @@ class TestFactory(dict):
160 q['points'] = qq.get('points', 0.0) 161 q['points'] = qq.get('points', 0.0)
161 else: 162 else:
162 q['points'] = qq.get('points', 1.0) 163 q['points'] = qq.get('points', 1.0)
  164 + q['number'] = n
  165 + n += 1
163 166
164 total_points += q['points'] 167 total_points += q['points']
165 test.append(q) 168 test.append(q)
@@ -58,6 +58,7 @@ def run_script(script, stdin=&#39;&#39;, timeout=5): @@ -58,6 +58,7 @@ def run_script(script, stdin=&#39;&#39;, timeout=5):
58 else: 58 else:
59 return output 59 return output
60 60
  61 +# ---------------------------------------------------------------------------
61 def md_to_html(text, ref=None, files={}): 62 def md_to_html(text, ref=None, files={}):
62 if ref is not None: 63 if ref is not None:
63 # given q['ref'] and q['files'] replaces references to files by a 64 # given q['ref'] and q['files'] replaces references to files by a
@@ -72,6 +73,7 @@ def md_to_html(text, ref=None, files={}): @@ -72,6 +73,7 @@ def md_to_html(text, ref=None, files={}):
72 'markdown.extensions.sane_lists' 73 'markdown.extensions.sane_lists'
73 ]) 74 ])
74 75
  76 +# ---------------------------------------------------------------------------
75 def md_to_html_review(text, q): 77 def md_to_html_review(text, q):
76 for k,f in q['files'].items(): 78 for k,f in q['files'].items():
77 text = text.replace(k, '/absfile?name={}'.format(q['files'][k])) 79 text = text.replace(k, '/absfile?name={}'.format(q['files'][k]))