Commit ef03716c7924a1fd0189dff27cd5bac90d50dde5

Authored by Miguel Barao
1 parent e07f3a34
Exists in master and in 1 other branch dev

- minor corrections in MANUAL.md

- fixed order of the students in /result, added elapsed time and cosmetic changes
- new icon (pomba)
BUGS.md
1   -
  1 +
2 2  
3 3 # BUGS
4 4  
5 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 9 - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao.
9 10 - mostrar erro quando nao consegue importar questions files
10 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 15 # TODO
14 16  
  17 +- pacotes exactos usados para instalar.
  18 +- SQLAlchemy em vez da classe database.
15 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 20 - hash das passwords obtidas da concatenacao do numero de aluno com password (evita que passwords repetidas sejam detectadas).
18 21 - permitir enviar varios testes, aluno escolhe qual o teste que quer fazer.
19 22 - criar script json2md.py ou outra forma de gerar um teste ja realizado
... ... @@ -23,10 +26,11 @@
23 26 - criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput
24 27 - perguntas para professor corrigir mais tarde.
25 28 - testar com microsoft surface.
26   -
  29 +- share do score em /results (email)
27 30  
28 31 # FIXED
29 32  
  33 +- /results esta ordenado por numero e nao por data
30 34 - numeros das perguntas não fazem sentido quando há caixas de informação (numerar informacao tb?)
31 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 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 113 # Each question has a default value of 1.0 point, but it can be overridden.
114 114 # The points defined here do not need to be normalized (it's automatic).
115 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 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 136 show_hints: False
135 137 show_points: False
136 138 practice_mode: False
  139 + show_ref: False
137 140 debug: False
138 141 points: 1.0
139 142  
... ...
database.py
... ... @@ -20,12 +20,12 @@ class Database(object):
20 20  
21 21 # only the best result for each student
22 22 cmd = '''
23   - SELECT student_id, name, MAX(grade)
  23 + SELECT student_id, name, MAX(grade), finish_time
24 24 FROM students INNER JOIN tests
25 25 ON students.number=tests.student_id
26 26 WHERE test_id==? AND student_id!=0
27 27 GROUP BY student_id
28   - ORDER BY grade DESC;'''
  28 + ORDER BY grade DESC, finish_time DESC;'''
29 29 return c.execute(cmd, [test_id]).fetchall()
30 30  
31 31 # get list of students in the database
... ...
serve.py
... ... @@ -23,7 +23,7 @@ class Root(object):
23 23 self.database = database.Database(testconf['database'])
24 24 self.auth = AuthController(database=testconf['database'])
25 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 28 # --- DEFAULT ------------------------------------------------------------
29 29 # any path, e.g. /xpto/aargh is redirected to the test
... ...
static/favicon.ico
No preview for this file type
templates/grade.html
... ... @@ -109,7 +109,7 @@
109 109 </tbody>
110 110 <tfoot>
111 111 <tr>
112   - <th>Média</th>
  112 + <th>Média (não ponderada)</th>
113 113 <th colspan="2">
114 114 <div class="progress">
115 115 <%
... ...
templates/results.html
... ... @@ -25,6 +25,10 @@
25 25 box-shadow: 0px 2px 10px 3px rgba(0, 0, 0, .2);
26 26 border-radius:5px;
27 27 }
  28 + .progress {
  29 + margin-bottom: 0px;
  30 + border-radius: 25px;
  31 + }
28 32 </style>
29 33 </head>
30 34 <!-- ===================================================================== -->
... ... @@ -62,25 +66,41 @@
62 66 ${t['title']}
63 67 </div>
64 68 <!-- <div class="panel-body"> -->
65   - <table class="table">
  69 + <table class="table table-hover">
66 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 77 </thead>
74 78 <tbody>
75   - % for r in results:
  79 + <%!
  80 + from datetime import datetime
  81 + %>
  82 + % for r in results:
76 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 98 <td>
80 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 104 </td> <!-- nome -->
85 105 <td> <!-- nota -->
86 106 <div class="progress">
... ... @@ -95,6 +115,23 @@
95 115 </div>
96 116 </div>
97 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 135 </tr>
99 136 % endfor
100 137 </tbody>
... ...