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)
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?
@@ -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
@@ -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
@@ -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
@@ -109,7 +109,7 @@ @@ -109,7 +109,7 @@
109 </tbody> 109 </tbody>
110 <tfoot> 110 <tfoot>
111 <tr> 111 <tr>
112 - <th>Média</th> 112 + <th>Média (não ponderada)</th>
113 <th colspan="2"> 113 <th colspan="2">
114 <div class="progress"> 114 <div class="progress">
115 <% 115 <%
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>