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,13 +23,7 @@ These can be installed for a single user (recommended), in a python virtual envi | ||
23 | #### Installing packages for a single user (recommended) | 23 | #### Installing packages for a single user (recommended) |
24 | 24 | ||
25 | ```.bash | 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 | #### Installing packages in a virtual environment | 29 | #### Installing packages in a virtual environment |
@@ -38,13 +32,7 @@ pip install --user bcrypt | @@ -38,13 +32,7 @@ pip install --user bcrypt | ||
38 | pyvenv-3.5 venv/perguntations # or other virtualenv directory | 32 | pyvenv-3.5 venv/perguntations # or other virtualenv directory |
39 | source venv/perguntations/bin/activate # activate virtualenv | 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 | #### Installing packages system wide | 38 | #### Installing packages system wide |
@@ -65,15 +53,16 @@ where USERNAME is your account on bitbucket. | @@ -65,15 +53,16 @@ where USERNAME is your account on bitbucket. | ||
65 | 53 | ||
66 | ## Running a demo | 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 | ```.bash | 58 | ```.bash |
71 | cd WHERE/YOU/INSTALLED/perguntations | 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 | ./initdb.py students.csv # from CSV file | 62 | ./initdb.py students.csv # from CSV file |
75 | ./initdb.py --demo # initialize with fake students | 63 | ./initdb.py --demo # initialize with fake students |
76 | ./initdb.py # empty | 64 | ./initdb.py # empty |
65 | + | ||
77 | mv students.db demo/ | 66 | mv students.db demo/ |
78 | 67 | ||
79 | # edit test configuration and check if everything looks right | 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,6 +88,10 @@ The server can be stoped from the terminal with <kbd>^C</kbd>. | ||
99 | 88 | ||
100 | ## Troubleshooting | 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 | * 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: | 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 | - debian: fix it with `sudo dpkg-reconfigure locales`, select your UTF-8 locales and try again. | 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,6 +46,11 @@ class App(object): | ||
46 | else: | 46 | else: |
47 | logger.info('Database has {} students registered.'.format(n)) | 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 | # helper to manage db sessions using the `with` statement, for example | 56 | # helper to manage db sessions using the `with` statement, for example |
@@ -59,7 +64,8 @@ class App(object): | @@ -59,7 +64,8 @@ class App(object): | ||
59 | 64 | ||
60 | # ----------------------------------------------------------------------- | 65 | # ----------------------------------------------------------------------- |
61 | def exit(self): | 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 | logger.critical('----------- !!! Server terminated !!! -----------') | 69 | logger.critical('----------- !!! Server terminated !!! -----------') |
64 | 70 | ||
65 | # ----------------------------------------------------------------------- | 71 | # ----------------------------------------------------------------------- |
demo/test.yaml
@@ -11,10 +11,8 @@ title: Exame de Demonstração | @@ -11,10 +11,8 @@ title: Exame de Demonstração | ||
11 | # The database is an sqlite3 file generate with the script initdb.py | 11 | # The database is an sqlite3 file generate with the script initdb.py |
12 | database: demo/students.db | 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 | # It includes the questions, answers and grades. | 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 | answers_dir: demo/ans | 16 | answers_dir: demo/ans |
19 | 17 | ||
20 | # (optional, default: False) Show points for each question, scale 0-20. | 18 | # (optional, default: False) Show points for each question, scale 0-20. |
models.py
@@ -20,8 +20,8 @@ class Student(Base): | @@ -20,8 +20,8 @@ class Student(Base): | ||
20 | tests = relationship('Test', back_populates='student') | 20 | tests = relationship('Test', back_populates='student') |
21 | questions = relationship('Question', back_populates='student') | 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,8 +42,18 @@ class Test(Base): | ||
42 | student = relationship('Student', back_populates='tests') | 42 | student = relationship('Student', back_populates='tests') |
43 | questions = relationship('Question', back_populates='test') | 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,17 +71,15 @@ class Question(Base): | ||
61 | student = relationship('Student', back_populates='questions') | 71 | student = relationship('Student', back_populates='questions') |
62 | test = relationship('Test', back_populates='questions') | 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,6 +285,8 @@ def parse_arguments(): | ||
285 | argparser.add_argument('--conf', default=serverconf_file, type=str, help='server configuration file') | 285 | argparser.add_argument('--conf', default=serverconf_file, type=str, help='server configuration file') |
286 | argparser.add_argument('--debug', action='store_true', | 286 | argparser.add_argument('--debug', action='store_true', |
287 | help='Show datastructures when rendering questions') | 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 | argparser.add_argument('testfile', type=str, nargs='+', help='test/exam in YAML format.') # FIXME only one exam supported at the moment | 290 | argparser.add_argument('testfile', type=str, nargs='+', help='test/exam in YAML format.') # FIXME only one exam supported at the moment |
289 | return argparser.parse_args() | 291 | return argparser.parse_args() |
290 | 292 | ||
@@ -368,5 +370,8 @@ if __name__ == '__main__': | @@ -368,5 +370,8 @@ if __name__ == '__main__': | ||
368 | 370 | ||
369 | cherrypy.engine.start() | 371 | cherrypy.engine.start() |
370 | cherrypy.engine.block() | 372 | cherrypy.engine.block() |
373 | + | ||
371 | # ...App running... | 374 | # ...App running... |
375 | + | ||
372 | app.exit() | 376 | app.exit() |
377 | + # --- Server terminated | ||
373 | \ No newline at end of file | 378 | \ No newline at end of file |