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 | 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
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> | ... | ... |