Commit c3e0209787c7fbbfa278721544d82e6bb422aa68

Authored by Miguel Barão
1 parent 6eac0104
Exists in master and in 1 other branch dev

- fixed default correct for checkbox questions.

- fixed debug messages alignment.
- updated codemirror and fontawesome links to latest versions
1 1
2 # BUGS 2 # BUGS
3 3
  4 +- se aluno entrar com l12345 rebenta. numa funcao get_... ver imagem no ipad
4 - a revisao do teste não mostra as imagens. 5 - a revisao do teste não mostra as imagens.
5 - melhorar o botao de autorizar (desliga-se), usar antes um botao? 6 - melhorar o botao de autorizar (desliga-se), usar antes um botao?
6 e.g. retornar None quando nao ha alteracoes relativamente à última vez. 7 e.g. retornar None quando nao ha alteracoes relativamente à última vez.
@@ -19,7 +20,7 @@ ou usar push (websockets?) @@ -19,7 +20,7 @@ ou usar push (websockets?)
19 - adicionar opcao para eliminar um teste em curso. 20 - adicionar opcao para eliminar um teste em curso.
20 - gerar teste qd o prof autoriza? melhor nao, pode apagar o teste em curso. gerar previamente e manter uma pool de testes gerados? 21 - gerar teste qd o prof autoriza? melhor nao, pode apagar o teste em curso. gerar previamente e manter uma pool de testes gerados?
21 - enviar resposta de cada pergunta individualmente. 22 - enviar resposta de cada pergunta individualmente.
22 -- experimentar gerador de svg que inclua no markdown da pergunta e ver se funciona. 23 +- experimentar gerador de svg que inclua no markdown da pergunta e ver se funciona.
23 - suportar cotacao to teste diferente de 20 (e.g. para juntar perguntas em papel). opcao "points: 18" que normaliza total para 18 em vez de 20. 24 - suportar cotacao to teste diferente de 20 (e.g. para juntar perguntas em papel). opcao "points: 18" que normaliza total para 18 em vez de 20.
24 - quando ha varias perguntas para escolher, escolher sucessivamente em vez de aleatoriamente. 25 - quando ha varias perguntas para escolher, escolher sucessivamente em vez de aleatoriamente.
25 - como refrescar a tabela de admin sem fazer reload da pagina? 26 - como refrescar a tabela de admin sem fazer reload da pagina?
@@ -61,6 +62,7 @@ ou usar push (websockets?) @@ -61,6 +62,7 @@ ou usar push (websockets?)
61 62
62 # FIXED 63 # FIXED
63 64
  65 +- default correct in checkbox must be 1.0, so that the pairs (right,wrong) still work with `correct` left undefined.
64 - textarea com codemirror 66 - textarea com codemirror
65 - decorador para user 0, evita o "if uid==0" em muitas funcoes. 67 - decorador para user 0, evita o "if uid==0" em muitas funcoes.
66 - numeric interval deve converter respostas que usam virgulas para pontos decimais 68 - numeric interval deve converter respostas que usam virgulas para pontos decimais
@@ -74,7 +74,6 @@ class App(object): @@ -74,7 +74,6 @@ class App(object):
74 dbfile = path.expanduser(self.testfactory['database']) 74 dbfile = path.expanduser(self.testfactory['database'])
75 engine = create_engine(f'sqlite:///{dbfile}', echo=False) 75 engine = create_engine(f'sqlite:///{dbfile}', echo=False)
76 self.Session = sessionmaker(bind=engine) 76 self.Session = sessionmaker(bind=engine)
77 -  
78 try: 77 try:
79 with self.db_session() as s: 78 with self.db_session() as s:
80 n = s.query(Student).filter(Student.id != '0').count() 79 n = s.query(Student).filter(Student.id != '0').count()
@@ -117,7 +116,7 @@ class App(object): @@ -117,7 +116,7 @@ class App(object):
117 else: # check password 116 else: # check password
118 pw_ok = await check_password(try_pw, password) # async bcrypt 117 pw_ok = await check_password(try_pw, password) # async bcrypt
119 118
120 - if pw_ok: # success 119 + if pw_ok: # success
121 self.allowed.discard(uid) # remove from set of allowed students 120 self.allowed.discard(uid) # remove from set of allowed students
122 if uid in self.online: 121 if uid in self.online:
123 logger.warning(f'Student {uid}: already logged in.') 122 logger.warning(f'Student {uid}: already logged in.')
config/logger-debug.yaml
@@ -5,7 +5,7 @@ formatters: @@ -5,7 +5,7 @@ formatters:
5 void: 5 void:
6 format: '' 6 format: ''
7 standard: 7 standard:
8 - format: '%(asctime)s | %(levelname)-8s | %(name)-14s | %(message)s' 8 + format: '%(asctime)s | %(levelname)-8s | %(name)-15s | %(message)s'
9 9
10 handlers: 10 handlers:
11 default: 11 default:
@@ -154,7 +154,7 @@ class QuestionCheckbox(Question): @@ -154,7 +154,7 @@ class QuestionCheckbox(Question):
154 # set defaults if missing 154 # set defaults if missing
155 self.set_defaults({ 155 self.set_defaults({
156 'text': '', 156 'text': '',
157 - 'correct': [0.0] * n, # useful for questionaries 157 + 'correct': [1.0] * n, # Using 0.0 breaks the (right, wrong) options
158 'shuffle': True, 158 'shuffle': True,
159 'discount': True, 159 'discount': True,
160 'choose': n, # number of options 160 'choose': n, # number of options
@@ -167,7 +167,7 @@ class QuestionCheckbox(Question): @@ -167,7 +167,7 @@ class QuestionCheckbox(Question):
167 # FIXME it's possible that all options are chosen wrong 167 # FIXME it's possible that all options are chosen wrong
168 options = [] 168 options = []
169 correct = [] 169 correct = []
170 - for o,c in zip(self['options'], self['correct']): 170 + for o, c in zip(self['options'], self['correct']):
171 if isinstance(o, list): 171 if isinstance(o, list):
172 r = random.randint(0,1) 172 r = random.randint(0,1)
173 o = o[r] 173 o = o[r]
@@ -190,7 +190,7 @@ class QuestionCheckbox(Question): @@ -190,7 +190,7 @@ class QuestionCheckbox(Question):
190 if self['answer'] is not None: 190 if self['answer'] is not None:
191 sum_abs = sum(abs(p) for p in self['correct']) 191 sum_abs = sum(abs(p) for p in self['correct'])
192 if sum_abs < 1e-6: # case correct [0,...,0] avoid div-by-zero 192 if sum_abs < 1e-6: # case correct [0,...,0] avoid div-by-zero
193 - self['grade'] = 0.0 193 + self['grade'] = 1.0
194 194
195 else: 195 else:
196 x = 0.0 196 x = 0.0
@@ -332,7 +332,8 @@ class QuestionTextArea(Question): @@ -332,7 +332,8 @@ class QuestionTextArea(Question):
332 'correct': '' # trying to execute this will fail => grade 0.0 332 'correct': '' # trying to execute this will fail => grade 0.0
333 }) 333 })
334 334
335 - self['correct'] = path.abspath(path.normpath(path.join(self['path'], self['correct']))) # abspath will prepend cwd, which is plain wrong... 335 + # self['correct'] = path.join(self['path'], self['correct'])
  336 + self['correct'] = path.abspath(path.normpath(path.join(self['path'], self['correct'])))
336 337
337 #------------------------------------------------------------------------ 338 #------------------------------------------------------------------------
338 # can return negative values for wrong answers 339 # can return negative values for wrong answers
@@ -10,14 +10,15 @@ import argparse @@ -10,14 +10,15 @@ import argparse
10 import mimetypes 10 import mimetypes
11 import signal 11 import signal
12 import asyncio 12 import asyncio
13 -import json  
14 import functools 13 import functools
  14 +import json
15 15
16 # user installed libraries 16 # user installed libraries
17 import tornado.ioloop 17 import tornado.ioloop
18 import tornado.web 18 import tornado.web
19 import tornado.httpserver 19 import tornado.httpserver
20 from tornado import template, gen 20 from tornado import template, gen
  21 +import yaml
21 22
22 # this project 23 # this project
23 from app import App, AppException 24 from app import App, AppException
@@ -293,7 +294,7 @@ class TestHandler(BaseHandler): @@ -293,7 +294,7 @@ class TestHandler(BaseHandler):
293 # --- REVIEW ------------------------------------------------------------- 294 # --- REVIEW -------------------------------------------------------------
294 class ReviewHandler(BaseHandler): 295 class ReviewHandler(BaseHandler):
295 SUPPORTED_METHODS = ['GET'] 296 SUPPORTED_METHODS = ['GET']
296 - 297 +
297 _templates = { 298 _templates = {
298 'radio': 'review-question-radio.html', 299 'radio': 'review-question-radio.html',
299 'checkbox': 'review-question-checkbox.html', 300 'checkbox': 'review-question-checkbox.html',
@@ -327,6 +328,7 @@ class ReviewHandler(BaseHandler): @@ -327,6 +328,7 @@ class ReviewHandler(BaseHandler):
327 else: 328 else:
328 with f: 329 with f:
329 t = json.load(f) 330 t = json.load(f)
  331 + # print(yaml.dump(t, default_flow_style=False))
330 self.render('review.html', t=t, md=md_to_html, templ=self._templates) 332 self.render('review.html', t=t, md=md_to_html, templ=self._templates)
331 333
332 334
static/codemirror
1 -libs/codemirror-5.40.2/  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +libs/codemirror-5.42.0/
3 \ No newline at end of file 3 \ No newline at end of file
static/fontawesome.min.js
1 -libs/fontawesome-free-5.3.1-web/js/all.js  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +libs/fontawesome-free-5.5.0-web/js/all.js
3 \ No newline at end of file 3 \ No newline at end of file
@@ -191,7 +191,7 @@ class TestFactory(dict): @@ -191,7 +191,7 @@ class TestFactory(dict):
191 'debug': self['debug'], # required by template test.html 191 'debug': self['debug'], # required by template test.html
192 'database': self['database'], 192 'database': self['database'],
193 'questions_dir': self['questions_dir'], 193 'questions_dir': self['questions_dir'],
194 - 'files': self['files'], 194 + # 'files': self['files'],
195 }) 195 })
196 196
197 # ----------------------------------------------------------------------- 197 # -----------------------------------------------------------------------