Commit cd56848f1c40fdd4c91399b1ed666fe11436c8da
1 parent
526721fd
Exists in
master
and in
1 other branch
- review is working.
- fixed markdown rendering in questions.
Showing
20 changed files
with
172 additions
and
98 deletions
Show diff stats
BUGS.md
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 | # --------------------------------------------------------------------------- |
serve.py
@@ -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 </small> | 8 | <small>Classificar </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> |
test.py
@@ -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) |
tools.py
@@ -58,6 +58,7 @@ def run_script(script, stdin='', timeout=5): | @@ -58,6 +58,7 @@ def run_script(script, stdin='', 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])) |