Commit ef03716c7924a1fd0189dff27cd5bac90d50dde5
1 parent
e07f3a34
Exists in
master
and in
1 other branch
- minor corrections in MANUAL.md
- fixed order of the students in /result, added elapsed time and cosmetic changes - new icon (pomba)
Showing
7 changed files
with
75 additions
and
31 deletions
Show diff stats
BUGS.md
1 | - | 1 | + |
2 | 2 | ||
3 | # BUGS | 3 | # BUGS |
4 | 4 | ||
5 | !!! - questions type script, necessário dar um caminho exacto relativamete ao directorio do server em vez da pergunta. deveria ser possivel mover as perguntas de directorio sem rebentar os caminhos. | 5 | !!! - questions type script, necessário dar um caminho exacto relativamete ao directorio do server em vez da pergunta. deveria ser possivel mover as perguntas de directorio sem rebentar os caminhos. |
6 | 6 | ||
7 | -- colisoes nas referencias das perguntas. a referencia deveria influir o nome do ficheiro? | 7 | +- parece que é preciso criar à mão a pasta para as respostas (ans/...) depois apercebo-me que os caminhos no teste dizem respeito à directoria donde o teste é corrido... as respostas deveriam guardadas no directório dado. |
8 | +- colisoes nas referencias das perguntas. a referencia deveria influir o nome do ficheiro? acho que nao | ||
8 | - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. | 9 | - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. |
9 | - mostrar erro quando nao consegue importar questions files | 10 | - mostrar erro quando nao consegue importar questions files |
10 | - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. | 11 | - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. |
11 | - | 12 | +- testar envio de parametros para stdin para perguntas tipo generator. |
13 | +- usar pomba da ue moderna. | ||
12 | 14 | ||
13 | # TODO | 15 | # TODO |
14 | 16 | ||
17 | +- pacotes exactos usados para instalar. | ||
18 | +- SQLAlchemy em vez da classe database. | ||
15 | - Criar botão para o docente fazer enable/disable do aluno explicitamente (exames presenciais). | 19 | - Criar botão para o docente fazer enable/disable do aluno explicitamente (exames presenciais). |
16 | -- testar envio de parametros para stdin para perguntas tipo generator. | ||
17 | - hash das passwords obtidas da concatenacao do numero de aluno com password (evita que passwords repetidas sejam detectadas). | 20 | - hash das passwords obtidas da concatenacao do numero de aluno com password (evita que passwords repetidas sejam detectadas). |
18 | - permitir enviar varios testes, aluno escolhe qual o teste que quer fazer. | 21 | - permitir enviar varios testes, aluno escolhe qual o teste que quer fazer. |
19 | - criar script json2md.py ou outra forma de gerar um teste ja realizado | 22 | - criar script json2md.py ou outra forma de gerar um teste ja realizado |
@@ -23,10 +26,11 @@ | @@ -23,10 +26,11 @@ | ||
23 | - criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput | 26 | - criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput |
24 | - perguntas para professor corrigir mais tarde. | 27 | - perguntas para professor corrigir mais tarde. |
25 | - testar com microsoft surface. | 28 | - testar com microsoft surface. |
26 | - | 29 | +- share do score em /results (email) |
27 | 30 | ||
28 | # FIXED | 31 | # FIXED |
29 | 32 | ||
33 | +- /results esta ordenado por numero e nao por data | ||
30 | - numeros das perguntas não fazem sentido quando há caixas de informação (numerar informacao tb?) | 34 | - numeros das perguntas não fazem sentido quando há caixas de informação (numerar informacao tb?) |
31 | - Quando apresenta o teste, preencher com os valores definidos em answer (permite que professor dê informação à partida, e no modo practice fiquem com o preenchido anteriormente) | 35 | - Quando apresenta o teste, preencher com os valores definidos em answer (permite que professor dê informação à partida, e no modo practice fiquem com o preenchido anteriormente) |
32 | - information points é definido onde? test.y ou questions.py? | 36 | - information points é definido onde? test.y ou questions.py? |
MANUAL.md
@@ -113,18 +113,20 @@ A test is a file in `yaml` format that can reside anywhere on the filesystem. It | @@ -113,18 +113,20 @@ A test is a file in `yaml` format that can reside anywhere on the filesystem. It | ||
113 | # Each question has a default value of 1.0 point, but it can be overridden. | 113 | # Each question has a default value of 1.0 point, but it can be overridden. |
114 | # The points defined here do not need to be normalized (it's automatic). | 114 | # The points defined here do not need to be normalized (it's automatic). |
115 | questions: | 115 | questions: |
116 | - - ref: | ||
117 | - - first-question-1 # randomly choose one from these 3 questions | ||
118 | - - first-question-2 | ||
119 | - - first-question-3 | ||
120 | - points: 0.5 | 116 | + - ref: |
117 | + - first-question-1 # randomly choose one from these 3 questions | ||
118 | + - first-question-2 | ||
119 | + - first-question-3 | ||
120 | + points: 0.5 | ||
121 | 121 | ||
122 | - - ref: second-question # just one question, 1.0 point (unnormalized) | 122 | + - ref: second-question # one question, 1.0 point (unnormalized) |
123 | 123 | ||
124 | - - third-question # "ref:" not needed in simple cases | 124 | + - third-question # "ref:" not needed in simple cases |
125 | 125 | ||
126 | - - wrong-question # ref: missing because we also have | ||
127 | - points: 2 # points: | 126 | +This following one is wrong: |
127 | + | ||
128 | + - wrong-question # missing "ref:" key | ||
129 | + points: 2 | ||
128 | 130 | ||
129 | Some of the options have default values if they are omitted. The defaults are the following: | 131 | Some of the options have default values if they are omitted. The defaults are the following: |
130 | 132 | ||
@@ -134,6 +136,7 @@ Some of the options have default values if they are omitted. The defaults are th | @@ -134,6 +136,7 @@ Some of the options have default values if they are omitted. The defaults are th | ||
134 | show_hints: False | 136 | show_hints: False |
135 | show_points: False | 137 | show_points: False |
136 | practice_mode: False | 138 | practice_mode: False |
139 | + show_ref: False | ||
137 | debug: False | 140 | debug: False |
138 | points: 1.0 | 141 | points: 1.0 |
139 | 142 |
database.py
@@ -20,12 +20,12 @@ class Database(object): | @@ -20,12 +20,12 @@ class Database(object): | ||
20 | 20 | ||
21 | # only the best result for each student | 21 | # only the best result for each student |
22 | cmd = ''' | 22 | cmd = ''' |
23 | - SELECT student_id, name, MAX(grade) | 23 | + SELECT student_id, name, MAX(grade), finish_time |
24 | FROM students INNER JOIN tests | 24 | FROM students INNER JOIN tests |
25 | ON students.number=tests.student_id | 25 | ON students.number=tests.student_id |
26 | WHERE test_id==? AND student_id!=0 | 26 | WHERE test_id==? AND student_id!=0 |
27 | GROUP BY student_id | 27 | GROUP BY student_id |
28 | - ORDER BY grade DESC;''' | 28 | + ORDER BY grade DESC, finish_time DESC;''' |
29 | return c.execute(cmd, [test_id]).fetchall() | 29 | return c.execute(cmd, [test_id]).fetchall() |
30 | 30 | ||
31 | # get list of students in the database | 31 | # get list of students in the database |
serve.py
@@ -23,7 +23,7 @@ class Root(object): | @@ -23,7 +23,7 @@ class Root(object): | ||
23 | self.database = database.Database(testconf['database']) | 23 | self.database = database.Database(testconf['database']) |
24 | self.auth = AuthController(database=testconf['database']) | 24 | self.auth = AuthController(database=testconf['database']) |
25 | self.templates = TemplateLookup(directories=['templates'], input_encoding='utf-8') | 25 | self.templates = TemplateLookup(directories=['templates'], input_encoding='utf-8') |
26 | - self.tags = {'online': set(), 'finished': set()} # should be in application, not server | 26 | + self.tags = {'online': set(), 'finished': set()} # FIXME should be in application, not server |
27 | 27 | ||
28 | # --- DEFAULT ------------------------------------------------------------ | 28 | # --- DEFAULT ------------------------------------------------------------ |
29 | # any path, e.g. /xpto/aargh is redirected to the test | 29 | # any path, e.g. /xpto/aargh is redirected to the test |
static/favicon.ico
No preview for this file type
templates/grade.html
templates/results.html
@@ -25,6 +25,10 @@ | @@ -25,6 +25,10 @@ | ||
25 | box-shadow: 0px 2px 10px 3px rgba(0, 0, 0, .2); | 25 | box-shadow: 0px 2px 10px 3px rgba(0, 0, 0, .2); |
26 | border-radius:5px; | 26 | border-radius:5px; |
27 | } | 27 | } |
28 | + .progress { | ||
29 | + margin-bottom: 0px; | ||
30 | + border-radius: 25px; | ||
31 | + } | ||
28 | </style> | 32 | </style> |
29 | </head> | 33 | </head> |
30 | <!-- ===================================================================== --> | 34 | <!-- ===================================================================== --> |
@@ -62,25 +66,41 @@ | @@ -62,25 +66,41 @@ | ||
62 | ${t['title']} | 66 | ${t['title']} |
63 | </div> | 67 | </div> |
64 | <!-- <div class="panel-body"> --> | 68 | <!-- <div class="panel-body"> --> |
65 | - <table class="table"> | 69 | + <table class="table table-hover"> |
66 | <thead> | 70 | <thead> |
67 | - <tr> | ||
68 | - <th>Posição</th> | ||
69 | - <th>Número</th> | ||
70 | - <th>Nome</th> | ||
71 | - <th>Nota (0-20)</th> | ||
72 | - </tr> | 71 | + <tr> |
72 | + <th class="col-md-1 text-center">#</th> | ||
73 | + <th class="col-md-7 text-left">Nome</th> | ||
74 | + <th class="col-md-4 text-center">Nota</th> | ||
75 | + <th class="col-md-0"></th> | ||
76 | + </tr> | ||
73 | </thead> | 77 | </thead> |
74 | <tbody> | 78 | <tbody> |
75 | - % for r in results: | 79 | + <%! |
80 | + from datetime import datetime | ||
81 | + %> | ||
82 | + % for r in results: | ||
76 | <tr> | 83 | <tr> |
77 | - <td>${loop.index+1}</td> | ||
78 | - <td>${r[0]}</td> <!-- numero --> | 84 | + <td class="text-center"> |
85 | + % if loop.index == 0: | ||
86 | + <h4> | ||
87 | + <!-- <span class="label label-primary"> --> | ||
88 | + 1º | ||
89 | + <!-- </span> --> | ||
90 | + </h4> | ||
91 | + % else: | ||
92 | + <!-- <span class="label label-primary"> --> | ||
93 | + ${loop.index+1} | ||
94 | + <!-- </span> --> | ||
95 | + % endif | ||
96 | + </td> | ||
97 | + <!-- <td>${r[0]}</td> --> <!-- numero --> | ||
79 | <td> | 98 | <td> |
80 | % if loop.index == 0: | 99 | % if loop.index == 0: |
81 | - <img src="\crown.jpg" /> | ||
82 | - %endif | ||
83 | - ${r[1]} | 100 | + <h4 class="text-uppercase"><img src="\crown.jpg" /> ${r[1]}</h4> |
101 | + % else: | ||
102 | + ${r[1]} | ||
103 | + % endif | ||
84 | </td> <!-- nome --> | 104 | </td> <!-- nome --> |
85 | <td> <!-- nota --> | 105 | <td> <!-- nota --> |
86 | <div class="progress"> | 106 | <div class="progress"> |
@@ -95,6 +115,23 @@ | @@ -95,6 +115,23 @@ | ||
95 | </div> | 115 | </div> |
96 | </div> | 116 | </div> |
97 | </td> | 117 | </td> |
118 | + <td class="text-right"> | ||
119 | + <% | ||
120 | + dt = datetime.now() - datetime.strptime(r[3], '%Y-%m-%d %H:%M:%S.%f') | ||
121 | + %> | ||
122 | + <small> | ||
123 | + % if dt.days > 0: | ||
124 | + ${dt.days}d | ||
125 | + % elif dt.seconds >= 3600: | ||
126 | + (${dt.seconds // 3600} horas | ||
127 | + % elif dt.seconds >= 60: | ||
128 | + (${dt.seconds // 60} minutos | ||
129 | + % else: | ||
130 | + (${dt.seconds} segundos | ||
131 | + % endif | ||
132 | + | ||
133 | + </small> | ||
134 | + </td> | ||
98 | </tr> | 135 | </tr> |
99 | % endfor | 136 | % endfor |
100 | </tbody> | 137 | </tbody> |