Commit a0a8b360e0926b910f8a4efc412687fc466e46f5
1 parent
09cc7eba
Exists in
master
and in
1 other branch
- addded command line option --allow-all
Showing
5 changed files
with
45 additions
and
35 deletions
Show diff stats
README.md
... | ... | @@ -23,13 +23,7 @@ These can be installed for a single user (recommended), in a python virtual envi |
23 | 23 | #### Installing packages for a single user (recommended) |
24 | 24 | |
25 | 25 | ```.bash |
26 | -pip install --user cherrypy | |
27 | -pip install --user mako | |
28 | -pip install --user markdown | |
29 | -pip install --user pyyaml | |
30 | -pip install --user pygments | |
31 | -pip install --user sqlalchemy | |
32 | -pip install --user bcrypt | |
26 | +pip install --user cherrypy mako markdown pyyaml pygments sqlalchemy bcrypt | |
33 | 27 | ``` |
34 | 28 | |
35 | 29 | #### Installing packages in a virtual environment |
... | ... | @@ -38,13 +32,7 @@ pip install --user bcrypt |
38 | 32 | pyvenv-3.5 venv/perguntations # or other virtualenv directory |
39 | 33 | source venv/perguntations/bin/activate # activate virtualenv |
40 | 34 | |
41 | -pip install cherrypy | |
42 | -pip install mako | |
43 | -pip install markdown | |
44 | -pip install pyyaml | |
45 | -pip install pygments | |
46 | -pip install sqlalchemy | |
47 | -pip install bcrypt | |
35 | +pip install cherrypy mako markdown pyyaml pygments sqlalchemy bcrypt | |
48 | 36 | ``` |
49 | 37 | |
50 | 38 | #### Installing packages system wide |
... | ... | @@ -65,15 +53,16 @@ where USERNAME is your account on bitbucket. |
65 | 53 | |
66 | 54 | ## Running a demo |
67 | 55 | |
68 | -The following commands will show how to run a demonstration test: | |
56 | +The following commands show how to run a demonstration test: | |
69 | 57 | |
70 | 58 | ```.bash |
71 | 59 | cd WHERE/YOU/INSTALLED/perguntations |
72 | 60 | |
73 | -# create and initialize database either from a CSV file, fake students or empty | |
61 | +# create and initialize database using one of the following methods: | |
74 | 62 | ./initdb.py students.csv # from CSV file |
75 | 63 | ./initdb.py --demo # initialize with fake students |
76 | 64 | ./initdb.py # empty |
65 | + | |
77 | 66 | mv students.db demo/ |
78 | 67 | |
79 | 68 | # edit test configuration and check if everything looks right |
... | ... | @@ -99,6 +88,10 @@ The server can be stoped from the terminal with <kbd>^C</kbd>. |
99 | 88 | |
100 | 89 | ## Troubleshooting |
101 | 90 | |
91 | +* The server tries to run `python3`. If only a `python3.5` command is available, you need to set the default python using the OS package manager or manually create a symbolic link: | |
92 | + - macOS/macports: sudo port select --set python3 python35 | |
93 | + - FreeBSD 11: cd /usr/local/bin; ln -s python3.5 python3 | |
94 | + | |
102 | 95 | * If you are getting any `UnicodeEncodeError` type of errors that's because the terminal is not supporting UTF-8. Try running `locale` on the terminal and see if there is any error messages. Solutions: |
103 | 96 | - debian: fix it with `sudo dpkg-reconfigure locales`, select your UTF-8 locales and try again. |
104 | 97 | ... | ... |
app.py
... | ... | @@ -46,6 +46,11 @@ class App(object): |
46 | 46 | else: |
47 | 47 | logger.info('Database has {} students registered.'.format(n)) |
48 | 48 | |
49 | + if conf['allow_all']: | |
50 | + logger.info('Allowing all students') | |
51 | + for student in self.get_all_students(): | |
52 | + self.allow_student(student[0]) | |
53 | + | |
49 | 54 | |
50 | 55 | # ----------------------------------------------------------------------- |
51 | 56 | # helper to manage db sessions using the `with` statement, for example |
... | ... | @@ -59,7 +64,8 @@ class App(object): |
59 | 64 | |
60 | 65 | # ----------------------------------------------------------------------- |
61 | 66 | def exit(self): |
62 | - # FIXME what if there are online students? | |
67 | + if len(self.online) > 1: | |
68 | + logger.warning('Students still online: {}'.format(', '.join(self.online))) | |
63 | 69 | logger.critical('----------- !!! Server terminated !!! -----------') |
64 | 70 | |
65 | 71 | # ----------------------------------------------------------------------- | ... | ... |
demo/test.yaml
... | ... | @@ -11,10 +11,8 @@ title: Exame de Demonstração |
11 | 11 | # The database is an sqlite3 file generate with the script initdb.py |
12 | 12 | database: demo/students.db |
13 | 13 | |
14 | -# (optional) Generate a file for each test done by a student. | |
14 | +# Generate a file for each test done by a student. | |
15 | 15 | # It includes the questions, answers and grades. |
16 | -# If undefined, then no tests are saved (useful for debug and training). | |
17 | -save_answers: yes | |
18 | 16 | answers_dir: demo/ans |
19 | 17 | |
20 | 18 | # (optional, default: False) Show points for each question, scale 0-20. | ... | ... |
models.py
... | ... | @@ -20,8 +20,8 @@ class Student(Base): |
20 | 20 | tests = relationship('Test', back_populates='student') |
21 | 21 | questions = relationship('Question', back_populates='student') |
22 | 22 | |
23 | - # def __repr__(self): | |
24 | - # return 'Student:\n id: "{0}"\n name: "{1}"\n password: "{2}"'.format(self.id, self.name, self.password) | |
23 | + def __repr__(self): | |
24 | + return 'Student:\n id: "{0}"\n name: "{1}"\n password: "{2}"'.format(self.id, self.name, self.password) | |
25 | 25 | |
26 | 26 | |
27 | 27 | # --------------------------------------------------------------------------- |
... | ... | @@ -42,8 +42,18 @@ class Test(Base): |
42 | 42 | student = relationship('Student', back_populates='tests') |
43 | 43 | questions = relationship('Question', back_populates='test') |
44 | 44 | |
45 | - # def __repr__(self): | |
46 | - # return 'Test:\n id: "{0}"\n ref="{1}"\n grade="{2}"\n starttime="{3}"\n finishtime="{4}"\n student_id="{5}"'.format(self.id, self.ref, self.grade, self.starttime, self.finishtime, self.student_id) | |
45 | + def __repr__(self): | |
46 | + return 'Test:\n\ | |
47 | + id: "{}"\n\ | |
48 | + ref="{}"\n\ | |
49 | + title="{}"\n\ | |
50 | + grade="{}"\n\ | |
51 | + state="{}"\n\ | |
52 | + comment="{}"\n\ | |
53 | + starttime="{}"\n\ | |
54 | + finishtime="{}"\n\ | |
55 | + filename="{}"\n\ | |
56 | + student_id="{}"\n'.format(self.id, self.ref, self.title, self.grade, self.state, self.comment, self.starttime, self.finishtime, self.filename, self.student_id) | |
47 | 57 | |
48 | 58 | |
49 | 59 | # --------------------------------------------------------------------------- |
... | ... | @@ -61,17 +71,15 @@ class Question(Base): |
61 | 71 | student = relationship('Student', back_populates='questions') |
62 | 72 | test = relationship('Test', back_populates='questions') |
63 | 73 | |
64 | -# def __repr__(self): | |
65 | -# return ''' | |
66 | -# Question: | |
67 | -# id: "{0}" | |
68 | -# ref: "{1}" | |
69 | -# grade: "{2}" | |
70 | -# starttime: "{3}" | |
71 | -# finishtime: "{4}" | |
72 | -# student_id: "{5}" | |
73 | -# test_id: "{6}" | |
74 | -# '''.fotmat(self.id, self.ref, self.grade, self.starttime, self.finishtime, self.student_id, self.test_id) | |
74 | + def __repr__(self): | |
75 | + return 'Question:\n\ | |
76 | + id: "{}"\n\ | |
77 | + ref: "{}"\n\ | |
78 | + grade: "{}"\n\ | |
79 | + starttime: "{}"\n\ | |
80 | + finishtime: "{}"\n\ | |
81 | + student_id: "{}"\n\ | |
82 | + test_id: "{}"\n'.fotmat(self.id, self.ref, self.grade, self.starttime, self.finishtime, self.student_id, self.test_id) | |
75 | 83 | |
76 | 84 | |
77 | 85 | # --------------------------------------------------------------------------- | ... | ... |
serve.py
... | ... | @@ -285,6 +285,8 @@ def parse_arguments(): |
285 | 285 | argparser.add_argument('--conf', default=serverconf_file, type=str, help='server configuration file') |
286 | 286 | argparser.add_argument('--debug', action='store_true', |
287 | 287 | help='Show datastructures when rendering questions') |
288 | + argparser.add_argument('--allow-all', action='store_true', | |
289 | + help='Students are initially allowed to login (can be denied later)') | |
288 | 290 | argparser.add_argument('testfile', type=str, nargs='+', help='test/exam in YAML format.') # FIXME only one exam supported at the moment |
289 | 291 | return argparser.parse_args() |
290 | 292 | |
... | ... | @@ -368,5 +370,8 @@ if __name__ == '__main__': |
368 | 370 | |
369 | 371 | cherrypy.engine.start() |
370 | 372 | cherrypy.engine.block() |
373 | + | |
371 | 374 | # ...App running... |
375 | + | |
372 | 376 | app.exit() |
377 | + # --- Server terminated | |
373 | 378 | \ No newline at end of file | ... | ... |