Commit a08b82c950e6fccd4cf46d01f87c9001afde6b54

Authored by Miguel Barão
1 parent 0b1ced64
Exists in master and in 1 other branch dev

- changed how paths are handled so that the ~ is expanded to $HOME only when man…

…ipulating files, and not saving expanded paths (to avoid /User vs /home conflicts between OSX and Linux).
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 27
28 # FIXED 28 # FIXED
29 29
  30 +- Quando grava JSON do teste deve usar 'path' tal como definido na configuração e não expandido. Isto porque em OSX /home é /Users e quando se muda de um sistema para outro não encontra os testes. Assim, usando ~ na configuração deveria funcionar sempre.
30 - configuração do teste não joga bem com o do aprendizations. Em particular os scripts não ficam com o mesmo path!!! 31 - configuração do teste não joga bem com o do aprendizations. Em particular os scripts não ficam com o mesmo path!!!
31 - configurar pf em freebsd, port forward 80 -> 8080. documentacao 32 - configurar pf em freebsd, port forward 80 -> 8080. documentacao
32 - barras com notas em grade estão desalinhadas. 33 - barras com notas em grade estão desalinhadas.
@@ -34,7 +34,8 @@ class App(object): @@ -34,7 +34,8 @@ class App(object):
34 self.testfactory = test.TestFactory(filename, conf=conf) 34 self.testfactory = test.TestFactory(filename, conf=conf)
35 35
36 # connect to database and check registered students 36 # connect to database and check registered students
37 - engine = create_engine('sqlite:///{}'.format(self.testfactory['database']), echo=False) 37 + dbfile = path.expanduser(self.testfactory['database'])
  38 + engine = create_engine('sqlite:///{}'.format(dbfile), echo=False)
38 self.Session = scoped_session(sessionmaker(bind=engine)) 39 self.Session = scoped_session(sessionmaker(bind=engine))
39 40
40 try: 41 try:
@@ -133,7 +134,7 @@ class App(object): @@ -133,7 +134,7 @@ class App(object):
133 134
134 # save test in JSON format 135 # save test in JSON format
135 fname = ' -- '.join((t['student']['number'], t['ref'], str(t['finish_time']))) + '.json' 136 fname = ' -- '.join((t['student']['number'], t['ref'], str(t['finish_time']))) + '.json'
136 - fpath = path.abspath(path.join(t['answers_dir'], fname)) 137 + fpath = path.join(t['answers_dir'], fname)
137 t.save_json(fpath) 138 t.save_json(fpath)
138 139
139 # insert test and questions into database 140 # insert test and questions into database
@@ -447,7 +447,7 @@ class QuestionTextArea(Question): @@ -447,7 +447,7 @@ class QuestionTextArea(Question):
447 'correct': '' # trying to execute this will fail => grade 0.0 447 'correct': '' # trying to execute this will fail => grade 0.0
448 }) 448 })
449 449
450 - self['correct'] = path.abspath(path.normpath(path.join(self['path'], self['correct']))) 450 + self['correct'] = path.join(self['path'], self['correct'])
451 451
452 #------------------------------------------------------------------------ 452 #------------------------------------------------------------------------
453 # can return negative values for wrong answers 453 # can return negative values for wrong answers
@@ -281,12 +281,19 @@ class Root(object): @@ -281,12 +281,19 @@ class Root(object):
281 @require(name_is('0')) 281 @require(name_is('0'))
282 def review(self, test_id): 282 def review(self, test_id):
283 fname = self.app.get_json_filename_of_test(test_id) 283 fname = self.app.get_json_filename_of_test(test_id)
284 - with open(fname) as f:  
285 - t = json.load(f)  
286 - r = self.template['review'].render(t=t)  
287 - # import pdfkit  
288 - # pdfkit.from_string(r, 'out.pdf') # FIXME fails getting css, images, etc  
289 - return r 284 + try:
  285 + f = open(path.expanduser(fname))
  286 + except FileNotFoundError:
  287 + logging.error('Cannot find "{}" for review.'.format(fname))
  288 + except Exception as e:
  289 + raise e
  290 + else:
  291 + with f:
  292 + t = json.load(f)
  293 + return self.template['review'].render(t=t)
  294 + # FIXME
  295 + # import pdfkit
  296 + # pdfkit.from_string(r, 'out.pdf') # FIXME fails getting css, images, etc
290 297
291 @cherrypy.expose 298 @cherrypy.expose
292 @require(name_is('0')) 299 @require(name_is('0'))
templates/review.html
@@ -226,7 +226,7 @@ @@ -226,7 +226,7 @@
226 226
227 % if t['show_points']: 227 % if t['show_points']:
228 <p class="text-right"> 228 <p class="text-right">
229 - <small>(Cotação: ${round(q['points'] / total_points * 20.0, 1)} pontos)</small> 229 + <small>(Cotação: ${round(q['points'] / total_points * 20.0, 2)} pontos)</small>
230 <p> 230 <p>
231 % endif 231 % endif
232 232
@@ -74,7 +74,7 @@ class TestFactory(dict): @@ -74,7 +74,7 @@ class TestFactory(dict):
74 if 'ref' not in self: 74 if 'ref' not in self:
75 logger.warning('Missing "ref". Will use current date/time.') 75 logger.warning('Missing "ref". Will use current date/time.')
76 if 'answers_dir' not in self: 76 if 'answers_dir' not in self:
77 - logger.warning('Missing "answers_dir". Will use current directory!') 77 + logger.warning('Missing "answers_dir". Will save to current directory {}'.format(path.abspath(path.curdir)))
78 if 'questions_dir' not in self: 78 if 'questions_dir' not in self:
79 logger.warning('Missing "questions_dir". Using {}'.format(path.abspath(path.curdir))) 79 logger.warning('Missing "questions_dir". Using {}'.format(path.abspath(path.curdir)))
80 if 'files' not in self: 80 if 'files' not in self:
@@ -89,15 +89,15 @@ class TestFactory(dict): @@ -89,15 +89,15 @@ class TestFactory(dict):
89 self.setdefault('show_ref', False) 89 self.setdefault('show_ref', False)
90 self.setdefault('questions_dir', path.curdir) 90 self.setdefault('questions_dir', path.curdir)
91 self.setdefault('answers_dir', path.curdir) 91 self.setdefault('answers_dir', path.curdir)
92 - self['database'] = path.abspath(path.expanduser(self['database']))  
93 - self['questions_dir'] = path.abspath(path.expanduser(self['questions_dir']))  
94 - self['answers_dir'] = path.abspath(path.expanduser(self['answers_dir'])) 92 + # self['database'] = path.abspath(path.expanduser(self['database']))
  93 + # self['questions_dir'] = path.abspath(path.expanduser(self['questions_dir']))
  94 + # self['answers_dir'] = path.abspath(path.expanduser(self['answers_dir']))
95 95
96 - if not path.isfile(self['database']): 96 + if not path.isfile(path.expanduser(self['database'])):
97 logger.critical('Can\'t find database "{}"'.format(self['database'])) 97 logger.critical('Can\'t find database "{}"'.format(self['database']))
98 raise TestFactoryException() 98 raise TestFactoryException()
99 99
100 - if not path.isdir(self['questions_dir']): 100 + if not path.isdir(path.expanduser(self['questions_dir'])):
101 logger.critical('Can\'t find questions directory "{}"'.format(self['questions_dir'])) 101 logger.critical('Can\'t find questions directory "{}"'.format(self['questions_dir']))
102 raise TestFactoryException() 102 raise TestFactoryException()
103 103
@@ -117,7 +117,7 @@ class TestFactory(dict): @@ -117,7 +117,7 @@ class TestFactory(dict):
117 117
118 118
119 try: 119 try:
120 - f = open(path.join(self['answers_dir'],'REMOVE-ME'), 'w') 120 + f = open(path.join(path.expanduser(self['answers_dir']),'REMOVE-ME'), 'w')
121 except EnvironmentError: 121 except EnvironmentError:
122 logger.critical('Cannot write answers to "{0}".'.format(self['answers_dir'])) 122 logger.critical('Cannot write answers to "{0}".'.format(self['answers_dir']))
123 raise TestFactoryException() 123 raise TestFactoryException()
@@ -175,7 +175,7 @@ class TestFactory(dict): @@ -175,7 +175,7 @@ class TestFactory(dict):
175 'show_hints': self['show_hints'], 175 'show_hints': self['show_hints'],
176 'show_points': self['show_points'], 176 'show_points': self['show_points'],
177 'show_ref': self['show_ref'], 177 'show_ref': self['show_ref'],
178 - 'debug': self['debug'], 178 + 'debug': self['debug'], # required by template test.html
179 'database': self['database'], 179 'database': self['database'],
180 'questions_dir': self['questions_dir'], 180 'questions_dir': self['questions_dir'],
181 'files': self['files'], 181 'files': self['files'],
@@ -249,7 +249,7 @@ class Test(dict): @@ -249,7 +249,7 @@ class Test(dict):
249 249
250 # ----------------------------------------------------------------------- 250 # -----------------------------------------------------------------------
251 def save_json(self, filepath): 251 def save_json(self, filepath):
252 - with open(filepath, 'w') as f: 252 + with open(path.expanduser(filepath), 'w') as f:
253 json.dump(self, f, indent=2, default=str) 253 json.dump(self, f, indent=2, default=str)
254 # HACK default=str is required for datetime objects 254 # HACK default=str is required for datetime objects
255 logger.info('Student {}: saved JSON file.'.format(self['student']['number'])) 255 logger.info('Student {}: saved JSON file.'.format(self['student']['number']))
1 1
  2 +from os import path
2 import subprocess 3 import subprocess
3 import logging 4 import logging
  5 +
4 import yaml 6 import yaml
5 import markdown 7 import markdown
6 8
@@ -12,7 +14,7 @@ logger = logging.getLogger(__name__) @@ -12,7 +14,7 @@ logger = logging.getLogger(__name__)
12 # --------------------------------------------------------------------------- 14 # ---------------------------------------------------------------------------
13 def load_yaml(filename, default=None): 15 def load_yaml(filename, default=None):
14 try: 16 try:
15 - f = open(filename, 'r', encoding='utf-8') 17 + f = open(path.expanduser(filename), 'r', encoding='utf-8')
16 except IOError: 18 except IOError:
17 logger.error('Can\'t open file "{}"'.format(filename)) 19 logger.error('Can\'t open file "{}"'.format(filename))
18 return default 20 return default
@@ -30,6 +32,7 @@ def load_yaml(filename, default=None): @@ -30,6 +32,7 @@ def load_yaml(filename, default=None):
30 # Note: requires python 3.5+ 32 # Note: requires python 3.5+
31 # --------------------------------------------------------------------------- 33 # ---------------------------------------------------------------------------
32 def run_script(script, stdin='', timeout=5): 34 def run_script(script, stdin='', timeout=5):
  35 + script = path.expanduser(script)
33 try: 36 try:
34 p = subprocess.run([script], 37 p = subprocess.run([script],
35 input=stdin, 38 input=stdin,