Commit 23013d8cb34e4c9b1564756d9b891525159ca6da
1 parent
f6f24c2f
Exists in
master
and in
1 other branch
- 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
BUGS.md
... | ... | @@ -8,8 +8,7 @@ |
8 | 8 | |
9 | 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 | 12 | - Menu para professor com link para /results e /students |
14 | 13 | - implementar singlepage/multipage. Fazer uma class para single page que trate de andar gerir o avanco e correcao das perguntas |
15 | 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 | 18 | |
20 | 19 | # FIXED |
21 | 20 | |
21 | +- simplificar a gravacao do teste em json. | |
22 | +- mostrar numero ordem em /results | |
22 | 23 | - modal a pedir confirmação de submissão. |
23 | 24 | - pontos devem estar normalizados escala 0-20 |
24 | 25 | - mostrar numero de alunos online em /students | ... | ... |
database.py
... | ... | @@ -12,7 +12,7 @@ class Database(object): |
12 | 12 | grades = c.execute('SELECT test_id,grade,finish_time FROM tests WHERE student_id==?', [uid]) |
13 | 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 | 16 | def test_grades(self, test_id): |
17 | 17 | with sqlite3.connect(self.db) as c: |
18 | 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 | 20 | return results.fetchall() |
21 | 21 | |
22 | 22 | # get list of students in the database |
23 | - def students(self): | |
23 | + def get_students(self): | |
24 | 24 | with sqlite3.connect(self.db) as c: |
25 | 25 | students = c.execute('SELECT number,name,password FROM students ORDER BY number ASC;') |
26 | 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 | 40 | def student_reset_pw(self, d): |
29 | 41 | # d = {'12345': 'mypassword', ...} |
30 | 42 | with sqlite3.connect(self.db) as c: | ... | ... |
serve.py
... | ... | @@ -6,10 +6,7 @@ |
6 | 6 | |
7 | 7 | import cherrypy |
8 | 8 | from mako.lookup import TemplateLookup |
9 | -import yaml | |
10 | 9 | import argparse |
11 | -from datetime import datetime | |
12 | -import os.path | |
13 | 10 | |
14 | 11 | # my code |
15 | 12 | from myauth import AuthController, require |
... | ... | @@ -26,7 +23,7 @@ class Root(object): |
26 | 23 | self.database = database.Database(testconf['database']) |
27 | 24 | self.auth = AuthController(database=testconf['database']) |
28 | 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 | 28 | # --- DEFAULT ------------------------------------------------------------ |
32 | 29 | # any path, e.g. /xpto/aargh is redirected to the test |
... | ... | @@ -41,7 +38,6 @@ class Root(object): |
41 | 38 | # def students(self, reset_pw=None): |
42 | 39 | def students(self, **reset_pw): |
43 | 40 | uid = cherrypy.session.get('userid') |
44 | - | |
45 | 41 | if uid != '0': |
46 | 42 | raise cherrypy.HTTPRedirect('/') #FIXME use authorization @require(admin) |
47 | 43 | |
... | ... | @@ -51,16 +47,15 @@ class Root(object): |
51 | 47 | cherrypy.log.error('Password updated for student %s.' % str(num), 'APPLICATION') |
52 | 48 | |
53 | 49 | students = self.database.students() |
54 | - # print(students) | |
55 | 50 | template = self.templates.get_template('students.html') |
56 | 51 | return template.render(students=students, loggedin=self.loggedin) |
57 | 52 | |
58 | 53 | # --- RESULTS ------------------------------------------------------------ |
59 | 54 | @cherrypy.expose |
60 | 55 | def results(self): |
61 | - results = self.database.test_grades(self.testconf['ref']) | |
56 | + r = self.database.test_grades(self.testconf['ref']) | |
62 | 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 | 60 | # --- TEST --------------------------------------------------------------- |
66 | 61 | @cherrypy.expose |
... | ... | @@ -77,7 +72,7 @@ class Root(object): |
77 | 72 | cherrypy.session['test'] = t = test.Test(self.testconf) |
78 | 73 | t['number'] = uid |
79 | 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 | 77 | # Generate question |
83 | 78 | template = self.templates.get_template('test.html') |
... | ... | @@ -109,7 +104,7 @@ class Root(object): |
109 | 104 | t.correct() |
110 | 105 | if t['save_answers']: |
111 | 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 | 109 | # ---- Expire session ---- |
115 | 110 | self.loggedin.discard(t['number']) | ... | ... |
test.py
... | ... | @@ -6,6 +6,7 @@ import json |
6 | 6 | import sqlite3 |
7 | 7 | from datetime import datetime |
8 | 8 | import questions |
9 | +import database | |
9 | 10 | |
10 | 11 | # ============================================================================ |
11 | 12 | def read_configuration(filename): |
... | ... | @@ -68,7 +69,6 @@ def read_configuration(filename): |
68 | 69 | |
69 | 70 | # ============================================================================ |
70 | 71 | class Test(dict): |
71 | - '''Creates an instance of a test''' | |
72 | 72 | # ----------------------------------------------------------------------- |
73 | 73 | def __init__(self, d): |
74 | 74 | super().__init__(d) |
... | ... | @@ -113,38 +113,9 @@ class Test(dict): |
113 | 113 | |
114 | 114 | # ----------------------------------------------------------------------- |
115 | 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 | 116 | filename = ' -- '.join((str(self['number']), self['ref'], |
127 | 117 | str(self['finish_time']))) + '.json' |
128 | 118 | filepath = os.path.abspath(os.path.join(path, filename)) |
129 | 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 | ... | ... |