Commit 23013d8cb34e4c9b1564756d9b891525159ca6da

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

- simplified json to save the test (not compatible with previous version)

- code cleanup, moved sql code to database.py
Showing 4 changed files with 25 additions and 46 deletions   Show diff stats
@@ -8,8 +8,7 @@ @@ -8,8 +8,7 @@
8 8
9 # TODO 9 # TODO
10 10
11 -- mostrar numero ordem em /results  
12 -- simplificar a gravacao do teste em json. alterar o script json2md.py em conformidade 11 +- alterar o script json2md.py em conformidade
13 - Menu para professor com link para /results e /students 12 - Menu para professor com link para /results e /students
14 - implementar singlepage/multipage. Fazer uma class para single page que trate de andar gerir o avanco e correcao das perguntas 13 - implementar singlepage/multipage. Fazer uma class para single page que trate de andar gerir o avanco e correcao das perguntas
15 - criar pergunta gerada por script externo. Na instanciacao QuestionScript() é corrido um script que devolve uma instancia de pergunta de qualquer tipo. 14 - criar pergunta gerada por script externo. Na instanciacao QuestionScript() é corrido um script que devolve uma instancia de pergunta de qualquer tipo.
@@ -19,6 +18,8 @@ @@ -19,6 +18,8 @@
19 18
20 # FIXED 19 # FIXED
21 20
  21 +- simplificar a gravacao do teste em json.
  22 +- mostrar numero ordem em /results
22 - modal a pedir confirmação de submissão. 23 - modal a pedir confirmação de submissão.
23 - pontos devem estar normalizados escala 0-20 24 - pontos devem estar normalizados escala 0-20
24 - mostrar numero de alunos online em /students 25 - mostrar numero de alunos online em /students
@@ -12,7 +12,7 @@ class Database(object): @@ -12,7 +12,7 @@ class Database(object):
12 grades = c.execute('SELECT test_id,grade,finish_time FROM tests WHERE student_id==?', [uid]) 12 grades = c.execute('SELECT test_id,grade,finish_time FROM tests WHERE student_id==?', [uid])
13 return grades.fetchall() 13 return grades.fetchall()
14 14
15 - # return students results from a given test 15 + # return list of students and their results for a given test
16 def test_grades(self, test_id): 16 def test_grades(self, test_id):
17 with sqlite3.connect(self.db) as c: 17 with sqlite3.connect(self.db) as c:
18 cmd = 'SELECT student_id,name,grade FROM students INNER JOIN tests ON students.number=tests.student_id WHERE test_id==? ORDER BY grade DESC;' 18 cmd = 'SELECT student_id,name,grade FROM students INNER JOIN tests ON students.number=tests.student_id WHERE test_id==? ORDER BY grade DESC;'
@@ -20,11 +20,23 @@ class Database(object): @@ -20,11 +20,23 @@ class Database(object):
20 return results.fetchall() 20 return results.fetchall()
21 21
22 # get list of students in the database 22 # get list of students in the database
23 - def students(self): 23 + def get_students(self):
24 with sqlite3.connect(self.db) as c: 24 with sqlite3.connect(self.db) as c:
25 students = c.execute('SELECT number,name,password FROM students ORDER BY number ASC;') 25 students = c.execute('SELECT number,name,password FROM students ORDER BY number ASC;')
26 return students.fetchall() 26 return students.fetchall()
27 27
  28 + # the following methods update de database data
  29 +
  30 + def save_test(self, t):
  31 + with sqlite3.connect(self.db) as c:
  32 + # store result of the test
  33 + values = (t['ref'], t['number'], t['grade'], str(t['start_time']), str(t['finish_time']))
  34 + c.execute('INSERT INTO tests VALUES (?,?,?,?,?)', values)
  35 +
  36 + # store grade of every question in the test
  37 + ans = [(t['ref'], q['ref'], t['number'], q['grade'], str(t['finish_time'])) for q in t['questions']]
  38 + c.executemany('INSERT INTO questions VALUES (?,?,?,?,?)', ans)
  39 +
28 def student_reset_pw(self, d): 40 def student_reset_pw(self, d):
29 # d = {'12345': 'mypassword', ...} 41 # d = {'12345': 'mypassword', ...}
30 with sqlite3.connect(self.db) as c: 42 with sqlite3.connect(self.db) as c:
@@ -6,10 +6,7 @@ @@ -6,10 +6,7 @@
6 6
7 import cherrypy 7 import cherrypy
8 from mako.lookup import TemplateLookup 8 from mako.lookup import TemplateLookup
9 -import yaml  
10 import argparse 9 import argparse
11 -from datetime import datetime  
12 -import os.path  
13 10
14 # my code 11 # my code
15 from myauth import AuthController, require 12 from myauth import AuthController, require
@@ -26,7 +23,7 @@ class Root(object): @@ -26,7 +23,7 @@ class Root(object):
26 self.database = database.Database(testconf['database']) 23 self.database = database.Database(testconf['database'])
27 self.auth = AuthController(database=testconf['database']) 24 self.auth = AuthController(database=testconf['database'])
28 self.templates = TemplateLookup(directories=['templates'], input_encoding='utf-8') 25 self.templates = TemplateLookup(directories=['templates'], input_encoding='utf-8')
29 - self.loggedin = set() # students currently logged in #FIXME should be in database instead?? 26 + self.loggedin = set() # students currently logged in
30 27
31 # --- DEFAULT ------------------------------------------------------------ 28 # --- DEFAULT ------------------------------------------------------------
32 # any path, e.g. /xpto/aargh is redirected to the test 29 # any path, e.g. /xpto/aargh is redirected to the test
@@ -41,7 +38,6 @@ class Root(object): @@ -41,7 +38,6 @@ class Root(object):
41 # def students(self, reset_pw=None): 38 # def students(self, reset_pw=None):
42 def students(self, **reset_pw): 39 def students(self, **reset_pw):
43 uid = cherrypy.session.get('userid') 40 uid = cherrypy.session.get('userid')
44 -  
45 if uid != '0': 41 if uid != '0':
46 raise cherrypy.HTTPRedirect('/') #FIXME use authorization @require(admin) 42 raise cherrypy.HTTPRedirect('/') #FIXME use authorization @require(admin)
47 43
@@ -51,16 +47,15 @@ class Root(object): @@ -51,16 +47,15 @@ class Root(object):
51 cherrypy.log.error('Password updated for student %s.' % str(num), 'APPLICATION') 47 cherrypy.log.error('Password updated for student %s.' % str(num), 'APPLICATION')
52 48
53 students = self.database.students() 49 students = self.database.students()
54 - # print(students)  
55 template = self.templates.get_template('students.html') 50 template = self.templates.get_template('students.html')
56 return template.render(students=students, loggedin=self.loggedin) 51 return template.render(students=students, loggedin=self.loggedin)
57 52
58 # --- RESULTS ------------------------------------------------------------ 53 # --- RESULTS ------------------------------------------------------------
59 @cherrypy.expose 54 @cherrypy.expose
60 def results(self): 55 def results(self):
61 - results = self.database.test_grades(self.testconf['ref']) 56 + r = self.database.test_grades(self.testconf['ref'])
62 template = self.templates.get_template('results.html') 57 template = self.templates.get_template('results.html')
63 - return template.render(t=self.testconf, results=results) 58 + return template.render(t=self.testconf, results=r)
64 59
65 # --- TEST --------------------------------------------------------------- 60 # --- TEST ---------------------------------------------------------------
66 @cherrypy.expose 61 @cherrypy.expose
@@ -77,7 +72,7 @@ class Root(object): @@ -77,7 +72,7 @@ class Root(object):
77 cherrypy.session['test'] = t = test.Test(self.testconf) 72 cherrypy.session['test'] = t = test.Test(self.testconf)
78 t['number'] = uid 73 t['number'] = uid
79 t['name'] = name 74 t['name'] = name
80 - self.loggedin.add(uid) # track logged in students # FIXME should be in the auth module... 75 + self.loggedin.add(uid) # track logged in students
81 76
82 # Generate question 77 # Generate question
83 template = self.templates.get_template('test.html') 78 template = self.templates.get_template('test.html')
@@ -109,7 +104,7 @@ class Root(object): @@ -109,7 +104,7 @@ class Root(object):
109 t.correct() 104 t.correct()
110 if t['save_answers']: 105 if t['save_answers']:
111 t.save_json(self.testconf['answers_dir']) 106 t.save_json(self.testconf['answers_dir'])
112 - t.save_database(self.testconf['database']) # FIXME save_database should be in database.py 107 + self.database.save_test(t)
113 108
114 # ---- Expire session ---- 109 # ---- Expire session ----
115 self.loggedin.discard(t['number']) 110 self.loggedin.discard(t['number'])
@@ -6,6 +6,7 @@ import json @@ -6,6 +6,7 @@ import json
6 import sqlite3 6 import sqlite3
7 from datetime import datetime 7 from datetime import datetime
8 import questions 8 import questions
  9 +import database
9 10
10 # ============================================================================ 11 # ============================================================================
11 def read_configuration(filename): 12 def read_configuration(filename):
@@ -68,7 +69,6 @@ def read_configuration(filename): @@ -68,7 +69,6 @@ def read_configuration(filename):
68 69
69 # ============================================================================ 70 # ============================================================================
70 class Test(dict): 71 class Test(dict):
71 - '''Creates an instance of a test'''  
72 # ----------------------------------------------------------------------- 72 # -----------------------------------------------------------------------
73 def __init__(self, d): 73 def __init__(self, d):
74 super().__init__(d) 74 super().__init__(d)
@@ -113,38 +113,9 @@ class Test(dict): @@ -113,38 +113,9 @@ class Test(dict):
113 113
114 # ----------------------------------------------------------------------- 114 # -----------------------------------------------------------------------
115 def save_json(self, path): 115 def save_json(self, path):
116 - # ---- Saves test (JSON) ---- FIXME simplify and update json2md  
117 - header = {  
118 - 'title': self['title'],  
119 - 'number': self['number'],  
120 - 'name': self['name'],  
121 - 'testid': self['ref'],  
122 - 'start_time': str(self['start_time']),  
123 - 'finish_time': str(self['finish_time']),  
124 - 'final_grade': str(self['grade'])  
125 - }  
126 filename = ' -- '.join((str(self['number']), self['ref'], 116 filename = ' -- '.join((str(self['number']), self['ref'],
127 str(self['finish_time']))) + '.json' 117 str(self['finish_time']))) + '.json'
128 filepath = os.path.abspath(os.path.join(path, filename)) 118 filepath = os.path.abspath(os.path.join(path, filename))
129 with open(filepath, 'w') as f: 119 with open(filepath, 'w') as f:
130 - test = {'header': header, 'answers': self['questions']}  
131 - json.dump(test, f, indent=4)  
132 -  
133 - # -----------------------------------------------------------------------  
134 - def save_database(self, db):  
135 - # ---- Saves grade to database ---- FIXME SQLAlchemy??  
136 - t = self  
137 - ans = []  
138 - for q in t['questions']:  
139 - ans.append((t['ref'], q['ref'], t['number'], q['grade'], str(t['finish_time'])))  
140 - values = (t['ref'], t['number'], t['grade'], str(t['start_time']), str(t['finish_time']))  
141 -  
142 - conn = sqlite3.connect(db)  
143 - conn.execute('INSERT INTO tests VALUES (?,?,?,?,?)', values)  
144 - conn.executemany('INSERT INTO questions VALUES (?,?,?,?,?)', ans)  
145 - conn.commit()  
146 - conn.close()  
147 -  
148 - # -----------------------------------------------------------------------  
149 - def __str__(self):  
150 - return str(self) 120 + json.dump(self, f, indent=2, default=str)
  121 + # HACK default=str is required for datetime objects