Commit 50a03cac86d6cf3d861a293fd909be2d3714acb4
1 parent
71adb971
Exists in
master
and in
1 other branch
- /admin review includes student identification.
- Fixed bug where textarea was being initialized with answer from previous submission from another student. - Fixed get CSV with grades. - Fixed many regressions from the upgrade to bootstrap 5.1. - Changed menu in /admin. - Removed dependency from fontawesome (but added bootstrap-icons). - Removed jquery where not needed.
Showing
12 changed files
with
143 additions
and
180 deletions
Show diff stats
BUGS.md
| ... | ... | @@ -2,21 +2,22 @@ |
| 2 | 2 | |
| 3 | 3 | ## BUGS |
| 4 | 4 | |
| 5 | -- review por nome e numero no cabecalho jumbotron | |
| 6 | -- talvez a base de dados devesse ter como chave do teste um id que fosse único | |
| 7 | - desse teste particular (não um auto counter, nem ref do teste) | |
| 8 | 5 | - em caso de timeout na submissão (e.g. JOBE ou script nao responde) a correcção |
| 9 | 6 | não termina e o teste não é guardado. |
| 10 | -- reload do teste recomeça a contagem no inicio do tempo. | |
| 7 | +- modo --review nao implementado em testfactory.py | |
| 8 | +- talvez a base de dados devesse ter como chave do teste um id que fosse único | |
| 9 | + desse teste particular (não um auto counter, nem ref do teste) | |
| 11 | 10 | - em admin, quando scale_max não é 20, as cores das barras continuam a reflectir |
| 12 | 11 | a escala 0,20. a tabela teste na DB não tem a escala desse teste. |
| 12 | +- a revisao do teste não mostra as imagens que nao estejam ja em cache. | |
| 13 | +- reload do teste recomeça a contagem no inicio do tempo. | |
| 13 | 14 | - mensagems de erro do assembler aparecem na mesma linha na correcao e nao |
| 14 | - fazerm rendering do `$t`, ver se servidor faz parse do markdown dessas | |
| 15 | + fazem rendering do `$t`, ver se servidor faz parse do markdown dessas | |
| 15 | 16 | mensagens. |
| 16 | -- a revisao do teste não mostra as imagens que nao estejam ja em cache. | |
| 17 | 17 | |
| 18 | 18 | ## TODO |
| 19 | 19 | |
| 20 | +- pagina de login semelhante ao aprendizations | |
| 20 | 21 | - QuestionTextArea falta reportar nos comments os vários erros que podem ocorrer |
| 21 | 22 | (timeout, etc) |
| 22 | 23 | - pergunta com varias partes. |
| ... | ... | @@ -62,6 +63,12 @@ |
| 62 | 63 | - se ocorrer um erro na correcçao avisar aluno para contactar o professor. |
| 63 | 64 | - abrir o teste numa janela maximizada e que nao permite que o aluno a |
| 64 | 65 | redimensione/mova? modo kiosk? |
| 65 | -- detectar scroll e enviar posição para servidor (analise de scroll para detectar copianço?) | |
| 66 | +- detectar scroll e enviar posição para servidor (analise de scroll para | |
| 67 | + detectar copianço?) | |
| 66 | 68 | - criar perguntas de outros tipos, e.g. associação, ordenação. |
| 67 | -- stress tests. use https://locust.io | |
| 69 | +- stress tests. use [locust](https://locust.io) | |
| 70 | + | |
| 71 | +## FIXED | |
| 72 | + | |
| 73 | +- textarea vem inicializado com a resposta de outros alunos!!! | |
| 74 | +- App has no attribute get_grades_csv | ... | ... |
package.json
perguntations/app.py
| ... | ... | @@ -372,7 +372,7 @@ class App(): |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | 374 | # ------------------------------------------------------------------------ |
| 375 | - def get_test_csv(self): | |
| 375 | + def get_grades_csv(self): | |
| 376 | 376 | '''generates a CSV with the grades of the test currently running''' |
| 377 | 377 | test_ref = self._testfactory['ref'] |
| 378 | 378 | with Session(self._engine, future=True) as session: | ... | ... |
perguntations/questions.py
| ... | ... | @@ -604,16 +604,14 @@ def question_from(qdict: QDict) -> Question: |
| 604 | 604 | try: |
| 605 | 605 | qclass = types[qdict['type']] |
| 606 | 606 | except KeyError: |
| 607 | - logger.error('Invalid type "%s" in "%s"', | |
| 608 | - qdict['type'], qdict['ref']) | |
| 607 | + logger.error('Invalid type "%s" in "%s"', qdict['type'], qdict['ref']) | |
| 609 | 608 | raise |
| 610 | 609 | |
| 611 | 610 | # Create an instance of Question() of appropriate type |
| 612 | 611 | try: |
| 613 | - qinstance = qclass(QDict(qdict)) | |
| 612 | + qinstance = qclass(qdict.copy()) | |
| 614 | 613 | except QuestionException: |
| 615 | - logger.error('Error generating "%s" in %s/%s', | |
| 616 | - qdict['ref'], qdict['path'], qdict['filename']) | |
| 614 | + logger.error('Generating "%s" in %s', qdict['ref'], qdict['filename']) | |
| 617 | 615 | raise |
| 618 | 616 | |
| 619 | 617 | return qinstance |
| ... | ... | @@ -625,11 +623,10 @@ class QFactory(): |
| 625 | 623 | QFactory is a class that can generate question instances, e.g. by shuffling |
| 626 | 624 | options, running a script to generate the question, etc. |
| 627 | 625 | |
| 628 | - To generate an instance of a question we use the method generate(). | |
| 626 | + To generate an instance of a question we use the method gen_async(). | |
| 629 | 627 | It returns a question instance of the correct class. |
| 630 | - There is also an asynchronous version called gen_async(). This version is | |
| 631 | - synchronous for all question types (radio, checkbox, etc) except for | |
| 632 | - generator types which run asynchronously. | |
| 628 | + The method is async but it only awaits on generator questions. The others | |
| 629 | + are run until completion. | |
| 633 | 630 | |
| 634 | 631 | Example: |
| 635 | 632 | |
| ... | ... | @@ -640,16 +637,13 @@ class QFactory(): |
| 640 | 637 | 'options': ['a', 'b'] |
| 641 | 638 | }) |
| 642 | 639 | |
| 643 | - # generate synchronously | |
| 644 | - question = qfactory.generate() | |
| 645 | - | |
| 646 | 640 | # generate asynchronously |
| 647 | 641 | question = await qfactory.gen_async() |
| 648 | 642 | |
| 649 | 643 | # answer one question and correct it |
| 650 | - question['answer'] = 42 # set answer | |
| 651 | - question.correct() # correct answer | |
| 652 | - grade = question['grade'] # get grade | |
| 644 | + question.set_answer(42) # set answer | |
| 645 | + question.correct() # correct answer | |
| 646 | + grade = question['grade'] # get grade | |
| 653 | 647 | ''' |
| 654 | 648 | |
| 655 | 649 | def __init__(self, qdict: QDict = QDict({})) -> None: | ... | ... |
perguntations/templates/admin.html
| ... | ... | @@ -21,8 +21,6 @@ |
| 21 | 21 | |
| 22 | 22 | <!-- Scripts --> |
| 23 | 23 | <script src="/static/jquery/jquery.min.js"></script> |
| 24 | - <!-- <script defer src="/static/popper.js/popper.min.js"></script> --> | |
| 25 | - <!-- <script defer src="/static/fontawesome-free/js/all.min.js"></script> --> | |
| 26 | 24 | <script defer src="/static/bootstrap/js/bootstrap.bundle.min.js"></script> |
| 27 | 25 | <script defer src="/static/datatables/js/jquery.dataTables.min.js"></script> |
| 28 | 26 | <script defer src="/static/underscore/underscore-min.js"></script> |
| ... | ... | @@ -40,27 +38,34 @@ |
| 40 | 38 | <span class="navbar-toggler-icon"></span> |
| 41 | 39 | </button> |
| 42 | 40 | <div class="collapse navbar-collapse" id="navbarNavDropdown"> |
| 43 | - <!-- left --> | |
| 44 | - <span class="navbar-text mr-auto"></span> | |
| 45 | - | |
| 46 | 41 | <!-- center --> |
| 47 | - <span class="navbar-text mr-auto"><span id="clock"> --:-- </span></span> | |
| 42 | + <span class="navbar-text mx-auto" id="clock"> --:-- </span> | |
| 48 | 43 | |
| 49 | 44 | <!-- right --> |
| 50 | 45 | <ul class="navbar-nav"> |
| 51 | 46 | <li class="nav-item dropdown"> |
| 47 | + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownNotas" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
| 48 | + Notas | |
| 49 | + </a> | |
| 50 | + <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownNotas"> | |
| 51 | + <li><a class="dropdown-item" href="/adminwebservice?cmd=testcsv">Obter CSV notas finais...</a></li> | |
| 52 | + <li><a class="dropdown-item" href="/adminwebservice?cmd=questionscsv">Obter CSV detalhado...</a></li> | |
| 53 | + </ul> | |
| 54 | + </li> | |
| 55 | + <li class="nav-item dropdown"> | |
| 52 | 56 | <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownAluno" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| 53 | - Acções | |
| 57 | + Alunos | |
| 54 | 58 | </a> |
| 55 | - <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownAluno"> | |
| 59 | + <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownAluno"> | |
| 56 | 60 | <li><a class="dropdown-item" href="#" id="novo_aluno" data-bs-toggle="modal" data-bs-target="#novo_aluno_modal">Novo aluno...</a></li> |
| 57 | 61 | <li><a class="dropdown-item" href="#" id="reset_password_menu" data-bs-toggle="modal" data-bs-target="#reset_password_modal">Limpar password...</a></li> |
| 58 | 62 | <li><a class="dropdown-item" href="#" id="allow_all">Autorizar todos</a></li> |
| 59 | 63 | <li><a class="dropdown-item" href="#" id="deny_all">Desautorizar todos</a></li> |
| 60 | - <li><hr class="dropdown-divider"></hr></li> | |
| 61 | - <li><a class="dropdown-item" href="/logout">Sair</a></li> | |
| 62 | 64 | </ul> |
| 63 | 65 | </li> |
| 66 | + <li class="nav-item"> | |
| 67 | + <a class="nav-link" href="/logout">Sair</a> | |
| 68 | + </li> | |
| 64 | 69 | </ul> |
| 65 | 70 | </div> |
| 66 | 71 | </div> |
| ... | ... | @@ -71,28 +76,25 @@ |
| 71 | 76 | <div class="bg-light p-3"> |
| 72 | 77 | <h3 id="title"></h3> |
| 73 | 78 | <ul> |
| 74 | - <li>Referência: <code id="ref">--</code><br></li> | |
| 75 | - <li>Ficheiro de configuração: <code id="filename">--</code><br></li> | |
| 76 | - <li>Directório com os testes entregues: <code id="answers_dir">--</code><br></li> | |
| 77 | - <li>Base de dados: <code id="database">--</code><br></li> | |
| 79 | + <li>Referência: <code id="ref">--</code></li> | |
| 80 | + <li>Ficheiro de configuração: <code id="filename">--</code></li> | |
| 81 | + <li>Directório com os testes entregues: <code id="answers_dir">--</code></li> | |
| 82 | + <li>Base de dados: <code id="database">--</code></li> | |
| 78 | 83 | </ul> |
| 79 | - <p> | |
| 80 | - <a href="/adminwebservice?cmd=testcsv" class="btn btn-primary">Obter CSV das notas</a> | |
| 81 | - <a href="/adminwebservice?cmd=questionscsv" class="btn btn-primary">Obter CSV detalhado</a> | |
| 82 | - </p> | |
| 83 | 84 | </div> |
| 84 | 85 | <br> |
| 85 | - <table class="table table-sm table-striped" style="width:100%" id="students_table"> | |
| 86 | - <thead class="thead thead-light"> | |
| 86 | + <table class="table table-borderless table-striped" id="students_table"> | |
| 87 | + <thead> | |
| 87 | 88 | <tr> |
| 88 | - <th>#</th> | |
| 89 | - <th>Autoriz.</th> | |
| 90 | - <th>Número</th> | |
| 91 | - <th>Nome</th> | |
| 92 | - <th>Estado</th> | |
| 93 | - <th>Nota</th> | |
| 89 | + <th scope="col">#</th> | |
| 90 | + <th scope="col">Autoriz.</th> | |
| 91 | + <th scope="col">Número</th> | |
| 92 | + <th scope="col">Nome</th> | |
| 93 | + <th scope="col">Estado</th> | |
| 94 | + <th scope="col">Nota</th> | |
| 94 | 95 | </tr> |
| 95 | 96 | </thead> |
| 97 | + <tbody> </tbody> | |
| 96 | 98 | </table> |
| 97 | 99 | |
| 98 | 100 | </div> <!-- container --> | ... | ... |
perguntations/templates/grade.html
| 1 | -<!DOCTYPE html> | |
| 1 | +<!doctype html> | |
| 2 | 2 | <html lang="pt-PT"> |
| 3 | 3 | <head> |
| 4 | - <title>Teste</title> | |
| 4 | + <title>Prova de avaliação</title> | |
| 5 | 5 | <meta charset="utf-8"> |
| 6 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
| 7 | 7 | <link rel="icon" href="/static/favicon.ico"> |
| ... | ... | @@ -35,9 +35,7 @@ |
| 35 | 35 | <div class="container"> |
| 36 | 36 | <div class="bg-light p-3"> |
| 37 | 37 | {% if t['state'] == 'CORRECTED' %} |
| 38 | - <h1> | |
| 39 | - Resultado: <strong>{{ f'{round(t["grade"], 3)}' }}</strong> valores | |
| 40 | - </h1> | |
| 38 | + <h1>Resultado: <strong>{{ f'{round(t["grade"], 3)}' }}</strong> valores</h1> | |
| 41 | 39 | {% elif t['state'] == 'SUBMITTED' %} |
| 42 | 40 | <h3>A prova foi submetida com sucesso. Vai ser corrigida mais tarde.</h3> |
| 43 | 41 | {% elif t['state'] == 'QUIT' %} | ... | ... |
perguntations/templates/review-question-checkbox.html
| ... | ... | @@ -10,45 +10,35 @@ |
| 10 | 10 | {% if q['answer'] is not None and str(n) in q['answer'] %} |
| 11 | 11 | <div class="p-2"> |
| 12 | 12 | <i class="bi bi-check-square"></i> |
| 13 | - <!-- <i class="far fa-check-square" aria-hidden="true"></i> --> | |
| 14 | 13 | </div> |
| 15 | 14 | <div class="p-2"> |
| 16 | 15 | {{ md(opt) }} |
| 17 | 16 | </div> |
| 18 | - <div class="ml-auto p-2"> | |
| 19 | - {% if q['correct'][n] > 0 %} | |
| 20 | - <div class="text-right text-success"> | |
| 21 | - <i class="bi bi-check-lg"></i> | |
| 22 | - <!-- <i class="fas fa-check" aria-hidden="true"></i> --> | |
| 23 | - </div> | |
| 24 | - {% else %} | |
| 25 | - <div class="text-right text-danger"> | |
| 26 | - <i class="bi bi-x-lg"></i> | |
| 27 | - <!-- <i class="fas fa-times" aria-hidden="true"></i> --> | |
| 28 | - </div> | |
| 29 | - {% end %} | |
| 17 | + <div class="ms-auto p-2"> | |
| 18 | + <div class="text-end"> | |
| 19 | + {% if q['correct'][n] > 0 %} | |
| 20 | + <i class="bi bi-check-lg text-success"></i> | |
| 21 | + {% else %} | |
| 22 | + <i class="bi bi-x-lg text-danger"></i> | |
| 23 | + {% end %} | |
| 24 | + </div> | |
| 30 | 25 | </div> |
| 31 | 26 | |
| 32 | 27 | {% else %} |
| 33 | 28 | <div class="p-2"> |
| 34 | 29 | <i class="bi bi-square"></i> |
| 35 | - <!-- <i class="far fa-square" aria-hidden="true"></i> --> | |
| 36 | 30 | </div> |
| 37 | 31 | <div class="p-2"> |
| 38 | 32 | {{ md(opt) }} |
| 39 | 33 | </div> |
| 40 | - <div class="ml-auto p-2"> | |
| 41 | - {% if q['correct'][n] > 0 %} | |
| 42 | - <div class="text-right text-danger"> | |
| 43 | - <i class="bi bi-x-lg"></i> | |
| 44 | - <!-- <i class="fas fa-times" aria-hidden="true"></i> --> | |
| 45 | - </div> | |
| 46 | - {% else %} | |
| 47 | - <div class="text-right text-success"> | |
| 48 | - <i class="bi bi-check-lg"></i> | |
| 49 | - <!-- <i class="fas fa-check" aria-hidden="true"></i> --> | |
| 50 | - </div> | |
| 51 | - {% end %} | |
| 34 | + <div class="ms-auto p-2"> | |
| 35 | + <div class="text-end"> | |
| 36 | + {% if q['correct'][n] > 0 %} | |
| 37 | + <i class="bi bi-x-lg text-danger"></i> | |
| 38 | + {% else %} | |
| 39 | + <i class="bi bi-check-lg text-success"></i> | |
| 40 | + {% end %} | |
| 41 | + </div> | |
| 52 | 42 | </div> |
| 53 | 43 | {% end %} |
| 54 | 44 | </div> | ... | ... |
perguntations/templates/review-question-radio.html
| ... | ... | @@ -10,39 +10,28 @@ |
| 10 | 10 | {% if q['answer'] is not None and str(n)==q['answer'] %} |
| 11 | 11 | <div class="p-2"> |
| 12 | 12 | <i class="bi bi-record-circle"></i> |
| 13 | - <!-- <i class="fas fa-dot-circle" aria-hidden="true"></i> --> | |
| 14 | 13 | </div> |
| 15 | 14 | <div class="p-2"> |
| 16 | 15 | {{ md(opt) }} |
| 17 | 16 | </div> |
| 18 | - <div class="ml-auto p-2"> | |
| 17 | + <div class="ms-auto p-2"> | |
| 19 | 18 | {% if q['correct'][n] > 0 %} |
| 20 | - <div class="text-right text-success"> | |
| 21 | - <i class="bi bi-check-lg"></i> | |
| 22 | - <!-- <i class="fas fa-check" aria-hidden="true"></i> --> | |
| 23 | - </div> | |
| 19 | + <i class="bi bi-check-lg text-success"></i> | |
| 24 | 20 | {% else %} |
| 25 | - <div class="text-right text-danger"> | |
| 26 | - <i class="bi bi-x-lg"></i> | |
| 27 | - <!-- <i class="fas fa-times" aria-hidden="true"></i> --> | |
| 28 | - </div> | |
| 21 | + <i class="bi bi-x-lg text-danger"></i> | |
| 29 | 22 | {% end %} |
| 30 | 23 | </div> |
| 31 | 24 | |
| 32 | 25 | {% else %} |
| 33 | 26 | <div class="p-2"> |
| 34 | 27 | <i class="bi bi-circle"></i> |
| 35 | - <!-- <i class="far fa-circle" aria-hidden="true"></i> --> | |
| 36 | 28 | </div> |
| 37 | 29 | <div class="p-2"> |
| 38 | 30 | {{ md(opt) }} |
| 39 | 31 | </div> |
| 40 | - <div class="ml-auto p-2"> | |
| 32 | + <div class="ms-auto p-2"> | |
| 41 | 33 | {% if q['correct'][n] > 0 %} |
| 42 | - <div class="text-right text-info"> | |
| 43 | - <i class="bi bi-arrow-left"></i> | |
| 44 | - <!-- <i class="fas fa-dot-circle" aria-hidden="true"></i> --> | |
| 45 | - </div> | |
| 34 | + <i class="bi bi-arrow-left text-info"></i> | |
| 46 | 35 | {% end %} |
| 47 | 36 | </div> |
| 48 | 37 | {% end %} | ... | ... |
perguntations/templates/review-question.html
| ... | ... | @@ -6,10 +6,9 @@ |
| 6 | 6 | <div class="card border-dark mb-3"> |
| 7 | 7 | <h5 class="card-header text-white bg-dark"> |
| 8 | 8 | {{ q['number'] }}. {{ q['title'] }} |
| 9 | - <div class="float-right"> | |
| 10 | - <small>Classificar </small> | |
| 11 | - <i class="bi bi-check-square"></i> | |
| 12 | - <!-- <i class="far fa-check-square" aria-hidden="true"></i> --> | |
| 9 | + <div class="float-end"> | |
| 10 | + <small>Classificada </small> | |
| 11 | + <i class="bi bi-toggle2-on"></i> | |
| 13 | 12 | </div> |
| 14 | 13 | </h5> <!-- card-header --> |
| 15 | 14 | |
| ... | ... | @@ -38,14 +37,12 @@ |
| 38 | 37 | {% if q['grade'] > 0.999 %} |
| 39 | 38 | <h1 class="text-success"><i class="bi bi-hand-thumbs-up"></i></h1> |
| 40 | 39 | <p class="text-success"> |
| 41 | - <!-- <i class="far fa-thumbs-up fa-3x" aria-hidden="true"></i> --> | |
| 42 | 40 | {{ round(q['grade'] * q['points'], 2) }} pontos |
| 43 | 41 | </p> |
| 44 | 42 | <p class="text-success">{{ md(q['comments']) }}</p> |
| 45 | 43 | {% elif q['grade'] >= 0.5 %} |
| 46 | 44 | <h1 class="text-warning"><i class="bi bi-exclamation-triangle"></i></h1> |
| 47 | 45 | <p class="text-warning"> |
| 48 | - <!-- <i class="fas fa-exclamation-triangle fa-3x" aria-hidden="true"></i> --> | |
| 49 | 46 | {{ round(q['grade'] * q['points'], 2) }} pontos |
| 50 | 47 | </p> |
| 51 | 48 | <p class="text-warning">{{ md(q['comments']) }}</p> |
| ... | ... | @@ -56,7 +53,6 @@ |
| 56 | 53 | {% else %} |
| 57 | 54 | <h1 class="text-danger"><i class="bi bi-hand-thumbs-down"></i></h1> |
| 58 | 55 | <p class="text-danger"> |
| 59 | - <!-- <i class="far fa-thumbs-down fa-3x" aria-hidden="true"></i> --> | |
| 60 | 56 | {{ round(q['grade'] * q['points'], 2) }} pontos |
| 61 | 57 | </p> |
| 62 | 58 | <p class="text-danger">{{ md(q['comments']) }}</p> |
| ... | ... | @@ -80,10 +76,9 @@ |
| 80 | 76 | <div class="card border-secondary mb-3"> |
| 81 | 77 | <h5 class="card-header text-white bg-secondary"> |
| 82 | 78 | {{ q['number'] }}. {{ q['title'] }} |
| 83 | - <div class="float-right"> | |
| 84 | - <small>Classificar </small> | |
| 85 | - <i class="bi bi-square"></i> | |
| 86 | - <!-- <i class="far fa-square" aria-hidden="true"></i> --> | |
| 79 | + <div class="float-end"> | |
| 80 | + <small>Não classificada</small> | |
| 81 | + <i class="bi bi-toggle2-off"></i> | |
| 87 | 82 | </div> |
| 88 | 83 | </h5> <!-- card-header --> |
| 89 | 84 | |
| ... | ... | @@ -102,16 +97,10 @@ |
| 102 | 97 | </div> <!-- card-body --> |
| 103 | 98 | |
| 104 | 99 | <div class="card-footer"> |
| 105 | - <h1 class="text-secondary"><i class="bi bi-dash-circle"></i></h1> | |
| 106 | - <p class="text-secondary"> | |
| 107 | - Não respondeu | |
| 108 | - <!-- <i class="fas fa-ban fa-3x" aria-hidden="true"></i> --> | |
| 109 | - {{ md(q['comments']) }} | |
| 110 | - {% if q['solution'] %} | |
| 111 | - <hr> | |
| 112 | - {{ md('**Solução:** \n\n' + q['solution']) }} | |
| 113 | - {% end %} | |
| 114 | - </p> | |
| 100 | + {{ md(q['comments']) }} | |
| 101 | + {% if q['solution'] %} | |
| 102 | + {{ md('**Solução:** \n\n' + q['solution']) }} | |
| 103 | + {% end %} | |
| 115 | 104 | |
| 116 | 105 | {% if debug %} |
| 117 | 106 | <hr> | ... | ... |
perguntations/templates/review.html
| ... | ... | @@ -22,14 +22,12 @@ |
| 22 | 22 | |
| 23 | 23 | <!-- Styles --> |
| 24 | 24 | <link rel="stylesheet" type="text/css" href="/static/bootstrap/css/bootstrap.min.css"> |
| 25 | + <link rel="stylesheet" type="text/css" href="/static/bootstrap-icons/font/bootstrap-icons.css"> | |
| 25 | 26 | <link rel="stylesheet" type="text/css" href="/static/css/github.css"> <!-- syntax highlight --> |
| 26 | 27 | <link rel="stylesheet" type="text/css" href="/static/css/test.css"> |
| 27 | - <link rel="stylesheet" type="text/css" href="/static/bootstrap-icons/font/bootstrap-icons.css"> | |
| 28 | 28 | |
| 29 | 29 | <!-- Scripts --> |
| 30 | 30 | <script src="/static/jquery/jquery.min.js"></script> |
| 31 | - <!-- <script defer src="/static/popper.js/popper.min.js"></script> --> | |
| 32 | - <!-- <script defer src="/static/fontawesome-free/js/all.min.js"></script> --> | |
| 33 | 31 | <script defer src="/static/bootstrap/js/bootstrap.bundle.min.js"></script> |
| 34 | 32 | </head> |
| 35 | 33 | <!-- ===================================================================== --> |
| ... | ... | @@ -58,10 +56,8 @@ |
| 58 | 56 | <ul class="nav navbar-nav"> |
| 59 | 57 | <li class="nav-item"> |
| 60 | 58 | <span class="navbar-text"> |
| 61 | - <!-- <i class="fas fa-user" aria-hidden="true"></i> --> | |
| 62 | 59 | <span id="name">{{ escape(name) }}</span> |
| 63 | 60 | (<span id="number">{{ escape(uid) }}</span>) |
| 64 | - <!-- <span class="caret"></span> --> | |
| 65 | 61 | </span> |
| 66 | 62 | </li> |
| 67 | 63 | </ul> |
| ... | ... | @@ -73,46 +69,47 @@ |
| 73 | 69 | <div class="container"> |
| 74 | 70 | <div class="bg-light p-3"> |
| 75 | 71 | <h1 class="display-5">{{ t['title'] }}</h1> |
| 76 | - <h5> | |
| 77 | - <div class="row"> | |
| 78 | - <label for="duracao" class="col-sm-2">Duração:</label> | |
| 79 | - <div class="col-sm-10" id="duracao"> | |
| 80 | - {{ str(t.get('duration', 0)) + ' minutos' if t.get('duration', 0) > 0 else '+'+chr(8734) }} | |
| 81 | - </div> | |
| 82 | - </div> | |
| 83 | - </h5> | |
| 84 | 72 | <hr> |
| 85 | - | |
| 86 | - <h5> | |
| 87 | - <div class="row"> | |
| 88 | - <label for="inicio" class="col-sm-2">Início:</label> | |
| 89 | - <div class="col-sm-10" id="inicio">{{t['start_time'][:19]}}</div> | |
| 73 | + <div class="row"> | |
| 74 | + <label for="nome" class="col-sm-2">Nome:</label> | |
| 75 | + <div class="col-sm-9" id="nome">{{ escape(name) }}</div> | |
| 76 | + </div> | |
| 77 | + <div class="row"> | |
| 78 | + <label for="numero" class="col-sm-2">Número:</label> | |
| 79 | + <div class="col-sm-9" id="numero">{{ escape(uid) }}</div> | |
| 80 | + </div> | |
| 81 | + <div class="row"> | |
| 82 | + <label for="duracao" class="col-sm-2">Duração:</label> | |
| 83 | + <div class="col-sm-10" id="duracao"> | |
| 84 | + {{ str(t.get('duration', 0)) + ' minutos' if t.get('duration', 0) > 0 else '+'+chr(8734) }} | |
| 90 | 85 | </div> |
| 91 | - <div class="row"> | |
| 92 | - <label for="fim" class="col-sm-2">Fim:</label> | |
| 93 | - <div class="col-sm-10" id="fim">{{t['finish_time'][:19]}}</div> | |
| 86 | + </div> | |
| 87 | + <div class="row"> | |
| 88 | + <label for="inicio" class="col-sm-2">Início:</label> | |
| 89 | + <div class="col-sm-10" id="inicio">{{t['start_time'][:19]}}</div> | |
| 90 | + </div> | |
| 91 | + <div class="row"> | |
| 92 | + <label for="fim" class="col-sm-2">Fim:</label> | |
| 93 | + <div class="col-sm-10" id="fim">{{t['finish_time'][:19]}}</div> | |
| 94 | + </div> | |
| 95 | + <div class="row"> | |
| 96 | + <label for="nota" class="col-sm-2">Nota:</label> | |
| 97 | + <div class="col-sm-10" id="nota"> | |
| 98 | + {% if t['state'] == 'CORRECTED' %} | |
| 99 | + <strong>{{ round(t['grade'], 2) }}</strong> valores | |
| 100 | + {% elif t['state'] == 'SUBMITTED' %} | |
| 101 | + (não corrigido) | |
| 102 | + {% elif t['state'] == 'QUIT' %} | |
| 103 | + (DESISTIU) | |
| 104 | + {% end %} | |
| 94 | 105 | </div> |
| 95 | - </h5> | |
| 96 | - <h3> | |
| 106 | + </div> | |
| 107 | + {% if t['comment'] != '' %} | |
| 97 | 108 | <div class="row"> |
| 98 | - <label for="nota" class="col-sm-2">Nota:</label> | |
| 99 | - <div class="col-sm-10" id="nota"> | |
| 100 | - {% if t['state'] == 'CORRECTED' %} | |
| 101 | - <span class="badge badge-primary">{{ round(t['grade'], 2) }}</span> valores | |
| 102 | - {% elif t['state'] == 'SUBMITTED' %} | |
| 103 | - (não corrigido) | |
| 104 | - {% elif t['state'] == 'QUIT' %} | |
| 105 | - (DESISTIU) | |
| 106 | - {% end %} | |
| 107 | - </div> | |
| 109 | + <label for="comentario" class="col-sm-2">Comentário:</label> | |
| 110 | + <div class="col-sm-10" id="comentario">{{ t['comment'] }}</div> | |
| 108 | 111 | </div> |
| 109 | - {% if t['comment'] != '' %} | |
| 110 | - <div class="row"> | |
| 111 | - <label for="comentario" class="col-sm-2">Comentário:</label> | |
| 112 | - <div class="col-sm-10" id="comentario">{{ t['comment'] }}</div> | |
| 113 | - </div> | |
| 114 | - {% end %} | |
| 115 | - </h3> | |
| 112 | + {% end %} | |
| 116 | 113 | </div> |
| 117 | 114 | |
| 118 | 115 | {% for i, q in enumerate(t['questions']) %} | ... | ... |
perguntations/templates/test.html
| 1 | -<!DOCTYPE html> | |
| 1 | +<!doctype html> | |
| 2 | 2 | <html lang="pt-PT"> |
| 3 | 3 | <head> |
| 4 | - <title>Teste</title> | |
| 5 | - <meta charset="UTF-8"> | |
| 6 | - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
| 4 | + <title>Prova de avalliação</title> | |
| 5 | + <meta charset="utf-8"> | |
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 7 | 7 | <link rel="icon" href="/static/favicon.ico"> |
| 8 | 8 | |
| 9 | +<!-- Styles --> | |
| 10 | + <link rel="stylesheet" type="text/css" href="/static/bootstrap/css/bootstrap.min.css"> | |
| 11 | + <link rel="stylesheet" type="text/css" href="/static/codemirror/lib/codemirror.css"> | |
| 12 | + <link rel="stylesheet" type="text/css" href="/static/codemirror/theme/darcula.css"> | |
| 13 | + <link rel="stylesheet" type="text/css" href="/static/css/github.css"> <!-- syntax highlight --> | |
| 14 | + <link rel="stylesheet" type="text/css" href="/static/css/test.css"> | |
| 15 | + | |
| 9 | 16 | <!-- MathJax3 --> |
| 10 | 17 | <script> |
| 11 | 18 | MathJax = { |
| ... | ... | @@ -21,21 +28,12 @@ |
| 21 | 28 | |
| 22 | 29 | <!-- Scripts --> |
| 23 | 30 | <script src="/static/jquery/jquery.min.js"></script> |
| 24 | - <!-- <script defer src="/static/popper.js/popper.min.js"></script> --> | |
| 25 | - <!-- <script defer src="/static/fontawesome-free/js/all.min.js"></script> --> | |
| 26 | 31 | <script defer src="/static/bootstrap/js/bootstrap.bundle.min.js"></script> |
| 27 | 32 | <script defer src="/static/underscore/underscore-min.js"></script> |
| 28 | 33 | <script src="/static/codemirror/lib/codemirror.js"></script> |
| 29 | 34 | <script src="/static/codemirror/addon/selection/active-line.js"></script> |
| 30 | 35 | <script src="/static/codemirror/addon/edit/matchbrackets.js"></script> |
| 31 | 36 | |
| 32 | -<!-- Styles --> | |
| 33 | - <link rel="stylesheet" type="text/css" href="/static/bootstrap/css/bootstrap.min.css"> | |
| 34 | - <link rel="stylesheet" type="text/css" href="/static/codemirror/lib/codemirror.css"> | |
| 35 | - <link rel="stylesheet" type="text/css" href="/static/codemirror/theme/darcula.css"> | |
| 36 | - <link rel="stylesheet" type="text/css" href="/static/css/github.css"> <!-- syntax highlight --> | |
| 37 | - <link rel="stylesheet" type="text/css" href="/static/css/test.css"> | |
| 38 | - | |
| 39 | 37 | <!-- My scripts --> |
| 40 | 38 | <script defer src="/static/js/question_disabler.js"></script> |
| 41 | 39 | <script defer src="/static/js/prevent_enter_submit.js"></script> |
| ... | ... | @@ -73,10 +71,8 @@ |
| 73 | 71 | <ul class="nav navbar-nav"> |
| 74 | 72 | <li class="nav-item"> |
| 75 | 73 | <span class="navbar-text"> |
| 76 | - <!-- <i class="fas fa-user" aria-hidden="true"></i> --> | |
| 77 | 74 | <span id="name">{{ escape(name) }}</span> |
| 78 | 75 | (<span id="number">{{ escape(uid) }}</span>) |
| 79 | - <!-- <span class="caret"></span> --> | |
| 80 | 76 | </span> |
| 81 | 77 | </li> |
| 82 | 78 | </ul> |
| ... | ... | @@ -136,17 +132,19 @@ |
| 136 | 132 | <h4 class="modal-title">Deseja submeter o teste?</h4> |
| 137 | 133 | </div> |
| 138 | 134 | <div class="modal-body"> |
| 139 | - O teste será enviado para classificação e já não poderá voltar atrás. | |
| 140 | - Antes de submeter, verifique se respondeu a todas as questões. | |
| 141 | - Desactive as perguntas que não pretende classificar para evitar | |
| 142 | - penalizações. | |
| 135 | + <ul> | |
| 136 | + <li> O teste será enviado para classificação e já não poderá voltar atrás.</li> | |
| 137 | + <li> Antes de submeter, verifique se respondeu a todas as questões.</li> | |
| 138 | + <li> Para evitar penalizações, esconda as perguntas que não | |
| 139 | + respondeu desactivando a checkbox "classificar".</li> | |
| 140 | + </ul> | |
| 143 | 141 | </div> |
| 144 | 142 | <div class="modal-footer"> |
| 145 | 143 | <button form="test" type="submit" class="btn btn-success btn-lg"> |
| 146 | 144 | Sim, submeter... |
| 147 | 145 | </button> |
| 148 | 146 | <button type="button" class="btn btn-danger btn-lg" data-bs-dismiss="modal"> |
| 149 | - Oops, NÃO!!! | |
| 147 | + Ainda NÃO!!! | |
| 150 | 148 | </button> |
| 151 | 149 | </div> |
| 152 | 150 | </div> |
| ... | ... | @@ -157,7 +155,6 @@ |
| 157 | 155 | $("textarea").each(function(i, ta) { |
| 158 | 156 | CodeMirror.fromTextArea(ta, { |
| 159 | 157 | lineNumbers: true, |
| 160 | - // theme: "darcula", | |
| 161 | 158 | viewportMargin: Infinity, |
| 162 | 159 | matchBrackets: true, |
| 163 | 160 | styleActiveLine: true, | ... | ... |
perguntations/testfactory.py