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 | ... | ... |