Commit a0a8b360e0926b910f8a4efc412687fc466e46f5

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

- addded command line option --allow-all

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