Commit 1e53d0f7b15c754a5b3e3c15996a8ecdb72bb9c2

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

- replaced loggedin by tags 'online' and 'finished'. Tags are shown in

/students.
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 - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. 6 - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao.
6 -- hash das passwords obtidas da concatenacao do numero de aluno com password (evita que passwords repetidas sejam detectadas).  
7 - mostrar erro quando nao consegue importar questions files 7 - mostrar erro quando nao consegue importar questions files
8 -- numeros das perguntas não fazem sentido quando há caixas de informação (numerar informacao tb?)  
9 - 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. 8 - 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.
10 9
11 10
12 # TODO 11 # TODO
13 12
14 -- 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)  
15 -- testar envio de parametros para stdin para perguntas tipo generator 13 +- Criar botão para o docente fazer enable/disable do aluno explicitamente (exames presenciais).
  14 +- testar envio de parametros para stdin para perguntas tipo generator.
  15 +- hash das passwords obtidas da concatenacao do numero de aluno com password (evita que passwords repetidas sejam detectadas).
16 - permitir enviar varios testes, aluno escolhe qual o teste que quer fazer. 16 - permitir enviar varios testes, aluno escolhe qual o teste que quer fazer.
17 - criar script json2md.py ou outra forma de gerar um teste ja realizado 17 - criar script json2md.py ou outra forma de gerar um teste ja realizado
18 - Menu para professor com link para /results e /students 18 - Menu para professor com link para /results e /students
19 - implementar singlepage/multipage. Fazer uma class para single page que trate de andar gerir o avanco e correcao das perguntas 19 - implementar singlepage/multipage. Fazer uma class para single page que trate de andar gerir o avanco e correcao das perguntas
20 - permitir adicionar imagens nas perguntas 20 - permitir adicionar imagens nas perguntas
21 - criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput 21 - criar perguntas de outros tipos, e.g. associação, ordenação, varios textinput
  22 +- perguntas para professor corrigir mais tarde.
  23 +- testar com microsoft surface.
22 24
23 25
24 # FIXED 26 # FIXED
25 27
  28 +- numeros das perguntas não fazem sentido quando há caixas de informação (numerar informacao tb?)
  29 +- 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)
26 - information points é definido onde? test.y ou questions.py? 30 - information points é definido onde? test.y ou questions.py?
27 - textarea monospace 31 - textarea monospace
28 - disable tab behavior in textarea. 32 - disable tab behavior in textarea.
@@ -95,7 +95,12 @@ def create_question(q): @@ -95,7 +95,12 @@ def create_question(q):
95 questiontype = Question 95 questiontype = Question
96 96
97 # create question instance and return 97 # create question instance and return
98 - return questiontype(q) 98 + try:
  99 + qinstance = questiontype(q)
  100 + except:
  101 + print(' * Error creating question "{0}" from file "{1}".'.format(q['ref'], q['filename']))
  102 +
  103 + return qinstance
99 104
100 105
101 # --------------------------------------------------------------------------- 106 # ---------------------------------------------------------------------------
@@ -23,7 +23,8 @@ class Root(object): @@ -23,7 +23,8 @@ 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.loggedin = set() # students currently logged in 26 + self.tags = {'online': set(), 'finished': set()}
  27 + # self.loggedin = set() # students currently logged in
27 28
28 # --- DEFAULT ------------------------------------------------------------ 29 # --- DEFAULT ------------------------------------------------------------
29 # any path, e.g. /xpto/aargh is redirected to the test 30 # any path, e.g. /xpto/aargh is redirected to the test
@@ -37,7 +38,7 @@ class Root(object): @@ -37,7 +38,7 @@ class Root(object):
37 @require() 38 @require()
38 def logout(self): 39 def logout(self):
39 uid = cherrypy.session.get('userid') 40 uid = cherrypy.session.get('userid')
40 - self.loggedin.discard(uid) 41 + self.tags['online'].discard(uid)
41 cherrypy.lib.sessions.expire() # session coockie expires client side 42 cherrypy.lib.sessions.expire() # session coockie expires client side
42 cherrypy.session['userid'] = cherrypy.request.login = None 43 cherrypy.session['userid'] = cherrypy.request.login = None
43 cherrypy.log.error('Student {0} logged out.'.format(uid), 'APPLICATION') 44 cherrypy.log.error('Student {0} logged out.'.format(uid), 'APPLICATION')
@@ -58,7 +59,7 @@ class Root(object): @@ -58,7 +59,7 @@ class Root(object):
58 59
59 students = self.database.get_students() 60 students = self.database.get_students()
60 template = self.templates.get_template('students.html') 61 template = self.templates.get_template('students.html')
61 - return template.render(students=students, loggedin=self.loggedin) 62 + return template.render(students=students, tags=self.tags)
62 63
63 # --- RESULTS ------------------------------------------------------------ 64 # --- RESULTS ------------------------------------------------------------
64 @cherrypy.expose 65 @cherrypy.expose
@@ -82,7 +83,7 @@ class Root(object): @@ -82,7 +83,7 @@ class Root(object):
82 cherrypy.session['test'] = t = test.Test(self.testconf) 83 cherrypy.session['test'] = t = test.Test(self.testconf)
83 t['number'] = uid 84 t['number'] = uid
84 t['name'] = name 85 t['name'] = name
85 - self.loggedin.add(uid) # track logged in students 86 + self.tags['online'].add(uid) # track logged in students
86 87
87 # Generate question 88 # Generate question
88 template = self.templates.get_template('test.html') 89 template = self.templates.get_template('test.html')
@@ -126,7 +127,8 @@ class Root(object): @@ -126,7 +127,8 @@ class Root(object):
126 127
127 else: 128 else:
128 # ---- Expire session ---- 129 # ---- Expire session ----
129 - self.loggedin.discard(t['number']) 130 + self.tags['online'].discard(t['number'])
  131 + self.tags['finished'].add(t['number'])
130 cherrypy.lib.sessions.expire() # session coockie expires client side 132 cherrypy.lib.sessions.expire() # session coockie expires client side
131 cherrypy.session['userid'] = cherrypy.request.login = None 133 cherrypy.session['userid'] = cherrypy.request.login = None
132 cherrypy.log.error('Student %s terminated with grade = %.2f points.' % 134 cherrypy.log.error('Student %s terminated with grade = %.2f points.' %
templates/students.html
@@ -33,12 +33,13 @@ @@ -33,12 +33,13 @@
33 <div class="container"> 33 <div class="container">
34 <div class="panel panel-default drop-shadow"> 34 <div class="panel panel-default drop-shadow">
35 <div class="panel-heading"> 35 <div class="panel-heading">
36 - List of students (${len(loggedin)} online) 36 + <span class="badge">${len(tags['online'])} online</span> <span class="badge">${len(tags['finished'])} finished</span>
37 </div> 37 </div>
38 <!-- <div class="panel-body"> --> 38 <!-- <div class="panel-body"> -->
39 <table class="table"> 39 <table class="table">
40 <thead> 40 <thead>
41 <tr> 41 <tr>
  42 + <th>Tags</th>
42 <th>Número</th> 43 <th>Número</th>
43 <th>Nome</th> 44 <th>Nome</th>
44 <th>Password</th> 45 <th>Password</th>
@@ -46,27 +47,31 @@ @@ -46,27 +47,31 @@
46 </thead> 47 </thead>
47 <tbody> 48 <tbody>
48 % for r in students: 49 % for r in students:
49 - % if r[0] in loggedin:  
50 - <tr class="danger">  
51 - % else:  
52 - <tr>  
53 - % endif  
54 - <td>${r[0]}</td> <!-- numero -->  
55 - <td>${r[1]}</td> <!-- nome -->  
56 - <td class="col-sm-6">  
57 - <form action="/students/" method="post" id="${r[0]}">  
58 - <div class="input-group">  
59 - <span class="input-group-btn">  
60 - <!-- <button class="btn btn-danger" type="submit">reset</button> -->  
61 - <button form="${r[0]}" type="submit" value="submit" class="btn btn-danger">reset</button> 50 + <tr>
  51 + <td>
  52 + % if r[0] in tags['online']:
  53 + <span class="label label-primary">online</span>
  54 + % endif
  55 + % if r[0] in tags['finished']:
  56 + <span class="label label-success">finished</span>
  57 + % endif
  58 + </td>
  59 + <td>${r[0]}</td> <!-- numero -->
  60 + <td>${r[1]}</td> <!-- nome -->
  61 + <td class="col-sm-3">
  62 + <form action="/students/" method="post" id="${r[0]}">
  63 + <div class="input-group">
  64 + <input type="password" class="form-control" placeholder="${r[2][:8]}" name="${r[0]}">
  65 + <span class="input-group-btn">
  66 + <!-- <button class="btn btn-danger" type="submit">reset</button> -->
  67 + <button form="${r[0]}" type="submit" value="submit" class="btn btn-danger">reset</button>
62 68
63 - </span>  
64 - <input type="password" class="form-control" placeholder="${r[2]}" name="${r[0]}">  
65 - </div><!-- /input-group -->  
66 - </form>  
67 - </td> <!-- password -->  
68 - </tr>  
69 - % endfor 69 + </span>
  70 + </div><!-- /input-group -->
  71 + </form>
  72 + </td> <!-- password -->
  73 + </tr>
  74 + % endfor
70 </tbody> 75 </tbody>
71 </table> 76 </table>
72 </div> <!-- panel --> 77 </div> <!-- panel -->
templates/test.html
@@ -88,7 +88,7 @@ @@ -88,7 +88,7 @@
88 ${t['name']} (${t['number']}) <span class="caret"></span> 88 ${t['name']} (${t['number']}) <span class="caret"></span>
89 </a> 89 </a>
90 <ul class="dropdown-menu"> 90 <ul class="dropdown-menu">
91 - <li><a href="/logout"><span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> Logout</a></li> 91 + <li><a href="/logout"><span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> Sair</a></li>
92 <!-- <li><a href="#">Change password</a></li> --> 92 <!-- <li><a href="#">Change password</a></li> -->
93 </ul> 93 </ul>
94 </li> 94 </li>
@@ -101,7 +101,6 @@ @@ -101,7 +101,6 @@
101 <div class="container"> 101 <div class="container">
102 <div class="row"> 102 <div class="row">
103 <form action="/correct/" method="post" id="test"> 103 <form action="/correct/" method="post" id="test">
104 -  
105 <%! 104 <%!
106 import markdown as md 105 import markdown as md
107 import yaml 106 import yaml