diff --git a/.gitignore b/.gitignore index bbf59cd..2c886ad 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ static/lib # Python egg metadata, regenerated from source files by setuptools. /*.egg-info -/*.egg \ No newline at end of file +/*.eggnode_modules + +# ignore javascript libraries installed with npm +node_modules/ \ No newline at end of file diff --git a/README.md b/README.md index ffb9541..d389af3 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,17 @@ ## 1. Requirements -The webserver is a python application that requires `python3.6` and `pip` to be -installed. -It's also recommended to install `npm` (Node package management) to install the +The webserver is a python application that requires `>=python3.6` and `pip` to be +installed. `npm` (Node package management) is also necessary to install the javascript libraries. ```bash sudo apt install python3 python3-pip npm # debian, ubuntu, mint, ... sudo pkg install python36 py36-sqlite3 py36-pip py36-setuptools npm # FreeBSD +sudo port install python37 py37-pip py37-setuptools npm6 # MacOS ``` -The file `~/.config/pip/pip.conf` should be configured to the following: +The file `pip.conf` should be configured to the following: ```ini [global] @@ -28,21 +28,25 @@ user=yes format=columns ``` -Note: In MacOS this file is in `~/Library/Application Support/pip/pip.conf`. +The file is in `~/.config/pip/` in Linux/FreeBSD and `~/Library/Application Support/pip/pip.conf` in MacOS. + --- ## 2. Installation -Download and install: +Download and install (`USERNAME` is your account on bitbucket): ```bash git clone https://USERNAME@bitbucket.org/USERNAME/perguntations.git -pip3 install --user perguntations +cd perguntations +npm install +pip3 install . ``` -where `USERNAME` is your account on bitbucket. -This will also install any dependencies required to run the software. +The command `npm` installs the javascript libraries and `pip3` installs the +python webserver. +This will also automatically install the python dependencies required. --- @@ -53,12 +57,11 @@ To generate certificates, there are two possibilities: public server with static IP address or a private server on a local network. Certificates must be saved in the `$XDG_DATA_HOME` path if defined in the -environment, otherwise in `~/.local/share/certs`. - -Create the directory if needed: +environment, otherwise in `~/.local/share/certs` (I will assume the latter +case). ```bash -[ ! -z "$XDG_DATA_HOME" ] || mkdir -p ~/.local/share/certs +mkdir -p ~/.local/share/certs ``` ### Selfsigned certificates @@ -67,7 +70,7 @@ Self-signed certificates are not certified by a recognised authority and browsers will complain that the certificate is not trusted. ```bash -cd WHERE/TO/PUT/CERTS +cd ~/.local/share/certs openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out cert.pem -days 365 -nodes ``` @@ -77,14 +80,14 @@ Generating certificates for a public server (FreeBSD) requires a registered domain with fixed IP. ```sh -sudo pkg install py27-certbot # FreeBSD +sudo pkg install py27-certbot # FreeBSD sudo service pf stop # disable pf firewall (FreeBSD) sudo certbot certonly --standalone -d www.example.com sudo service pf start # enable pf firewall ``` Certificates are saved in `/usr/local/etc/letsencrypt/live/www.example.com/`. -Copy them to the appropriate `certs` directory and change permissions: +Copy them to the `certs` directory and change permissions: ```sh chmod 400 cert.pem privkey.pem @@ -101,77 +104,57 @@ sudo service pf start # start firewall Again, copy certificate files `privkey.pem` and `cert.pem` to the `certs` directory. ---- - -## Installing 3rd party javascript libraries - -The javascript libraries are not included in the repository. -The following libraries are currently necessary (as of 24/1/2019): - -``` -DataTables -MDB-Free_4 -MathJax-2.7.5 -bootstrap-4.2.1-dist -codemirror-5.42.2 -fontawesome-free-5.6.3-web -jquery-3.3.1.min.js -popper.min.js -``` - -Downloaded and install them in the directory perguntations/static/lib. - -FIXME: use `npm` --- ## Running a demo -The directory `demo` includes a demo test that can be used as a template for -your own tests and questions. +The directory `demo` in the repository includes a demo test that can be used +as a template for your own tests and questions. To run the demonstration test you need to initialize the database using one of the following methods: ```.bash -./initdb.py students.csv # initialize from a CSV file -./initdb.py --admin # only adds the administrator account -./initdb.py --add 123 "Asterix Gaules" # add one student +cd demo -# a database file "students.db" is created -mv students.db demo/ +initdb students.csv # initialize from a CSV file +initdb --admin # only adds the administrator account +initdb --add 123 "Asterix Gaules" # add one student -# create directory to save the finished tests -mkdir demo/ans +mkdir ans # directory where the student tests are saved -# edit test configuration and check if everything looks right -vi demo/test-tutorial.yaml -``` +$EDITOR test-tutorial.yaml # edit test configuration -We are now ready to run the server: - -```.bash -./serve.py --help # get help -./serve.py demo/test-tutorial.yaml # run demo test +perguntations --help # get help +perguntations tutorial.yaml # run demo test ``` -By default the server listens on port 8443 and on all IPs of all network interfaces. -Open the browser at `http://127.0.0.1:8443/` and login as user number `0` (administrator) and choose any password. Then +The server listens on port 8443 of all IPs of all network interfaces. +Open the browser at `http://127.0.0.1:8443/` and login as user number `0` +(administrator) and choose any password. The administrator is redirected to the +administration page that shows all the students and their state. 1. Authorize students by clicking the checkboxes. -2. Open a different browser at `http://127.0.0.1:8443/` and login as one of the authorized students. Answer the questions and submit. +2. Open a different browser at `http://127.0.0.1:8443/` and login as one of the +authorized students. Answer the questions and submit. The server can be stoped from the terminal with `^C`. ## Running on lower ports 80 or 443 -Ports 80 and 443 are reserved for the root user and and this software _should NOT be run as root_. Instead, the firewall should be configured to forward tcp traffic from port 443 to 8443 where the server is listening. The details depend on the operating system. +Ports 80 and 443 are reserved for the root user and and this software **should +NOT be run as root**. +Instead, the firewall should be configured to forward tcp traffic from port 443 +to 8443 where the server is listening. +The details depend on the operating system. ### debian: +FIXME: Untested + ```.bash -iptables -t nat -I PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 8080 -FIXME: also for port 443... +iptables -t nat -I PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-ports 8443 ``` Explanation: @@ -181,19 +164,20 @@ Explanation: - `-p tcp` selected protocol. - `-s 0/0` source network address/mask. - `-i eth0` interface via which the packet was received. -- `--dport 80` destination port. +- `--dport 443` destination port. - `-j REDIRECT` what to do when packet matches the rule. -- `--to-ports 8080` where to redirect the packets. +- `--to-ports 8443` where to redirect the packets. ### FreeBSD and pf Edit `/etc/pf.conf`: - ext_if="em0" + ext_if="wlan1" rdr on $ext_if proto tcp from any to any port 80 -> 127.0.0.1 port 8080 rdr on $ext_if proto tcp from any to any port 443 -> 127.0.0.1 port 8443 -or `ext_if="vtnet0"` for guest additions under virtual box. +The `wlan1` should be the name of the network interface. +Use `ext_if="vtnet0"` for guest additions under virtual box. Start firewall with `sudo service pf start`. @@ -211,10 +195,17 @@ Optionally, to activate pf on boot, edit `rc.conf`: ## Troubleshooting -* The server tries to run `python3` so this command must be accessible from user accounts. Currently, the minimum supported python version is 3.6. -* If you are getting any `UnicodeEncodeError` type of errors that's because the terminal is not supporting UTF-8. This error may occur when a unicode character is printed to the screen by the server or, when running question generator or correction scripts, a message is piped between the server and the scripts that includes unicode characters. -Try running `locale` on the terminal and see if there are any error messages. Solutions: - - debian: fix it with `sudo dpkg-reconfigure locales`, select your UTF-8 locales and try again. +* The server tries to run `python3` so this command must be accessible from +user accounts. Currently, the minimum supported python version is 3.6. + +* If you are getting any `UnicodeEncodeError` type of errors that's because the +terminal is not supporting UTF-8. +This error may occur when a unicode character is printed to the screen by the +server or, when running question generator or correction scripts, a message is +piped between the server and the scripts that includes unicode characters. +Try running `locale` on the terminal and see if there are any error messages. +Solutions: + - debian: `sudo dpkg-reconfigure locales` and select your UTF-8 locales. - FreeBSD: edit `~/.login_conf` to use UTF-8, for example: ``` diff --git a/demo/test-tutorial.yaml b/demo/test-tutorial.yaml deleted file mode 100644 index b74c961..0000000 --- a/demo/test-tutorial.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -# ============================================================================ -# The test reference should be a unique identifier. It is saved in the database -# so that queries for the results can be done in the terminal with -# $ sqlite3 students.db "select * from tests where ref='demo'" -ref: tutorial - -# (optional, default: '') You may wish to refer the course, year or kind of test -title: Teste tutorial - -# (optional) duration in minutes, 0 or undefined is infinite -duration: 120 - -# Database with student credentials and grades of all questions and tests done -# The database is an sqlite3 file generate with the script initdb.py -database: demo/students.db - -# Generate a file for each test done by a student. -# It includes the questions, answers and grades. -answers_dir: demo/ans - -# (optional, default: False) Show points for each question, scale 0-20. -show_points: true -# scale_points: True -# scale_max: 20 - -# (optional, default: False) Show hints if available -show_hints: true - -# (optional, default: False) Show lots of information for debugging -# debug: True - - -# ---------------------------------------------------------------------------- -# Base path applied to the questions files and all the scripts -# including question generators and correctors. -# Either absolute path or relative to current directory can be used. -questions_dir: demo - -# (optional) List of files containing questions in yaml format. -# Selected questions will be obtained from these files. -# If undefined, all yaml files in questions_dir are loaded (not recommended). -files: - - questions/questions-tutorial.yaml - -# This is the list of questions that will make up the test. -# The order is preserved. -# There are several ways to define each question (explained below). -questions: - - tut-test - - tut-questions - - - tut-radio - - tut-checkbox - - tut-text - - tut-text-regex - - tut-numeric-interval - - ref: tut-textarea - points: 2.0 - - - tut-information - - tut-success - - tut-warning - - tut-alert diff --git a/demo/tutorial.yaml b/demo/tutorial.yaml new file mode 100644 index 0000000..536696b --- /dev/null +++ b/demo/tutorial.yaml @@ -0,0 +1,57 @@ +--- +# ============================================================================ +# The test reference should be a unique identifier. It is saved in the database +# so that queries for the results can be done in the terminal with +# $ sqlite3 students.db "select * from tests where ref='demo'" +ref: tutorial + +# (optional, default: '') You may wish to refer the course, year or kind of test +title: Teste de demonstração (tutorial) + +# (optional) duration in minutes, 0 or undefined is infinite +duration: 120 + +# Database with student credentials and grades of all questions and tests done +# The database is an sqlite3 file generate with the script initdb.py +database: demo/students.db + +# Generate a file for each test done by a student. +# It includes the questions, answers and grades. +answers_dir: demo/ans + +# (optional, default: False) Show points for each question, scale 0-20. +show_points: true +# scale_points: true +# scale_max: 20 + +# ---------------------------------------------------------------------------- +# Base path applied to the questions files and all the scripts +# including question generators and correctors. +# Either absolute path or relative to current directory can be used. +questions_dir: demo + +# (optional) List of files containing questions in yaml format. +# Selected questions will be obtained from these files. +# If undefined, all yaml files in questions_dir are loaded (not recommended). +files: + - questions/questions-tutorial.yaml + +# This is the list of questions that will make up the test. +# The order is preserved. +# There are several ways to define each question (explained below). +questions: + - tut-test + - tut-questions + + - tut-radio + - tut-checkbox + - tut-text + - tut-text-regex + - tut-numeric-interval + - ref: tut-textarea + points: 2.0 + + - tut-information + - tut-success + - tut-warning + - tut-alert diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..28d19cc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,44 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@fortawesome/fontawesome-free": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.7.1.tgz", + "integrity": "sha512-gukWJ7Mwf0WXQbkcwcm5zi8+H8aT5MMnphf5hpydOw898H1ibgm2cyejHgk6Km/FTvrPp5ppUHLrlFwt0QxsQw==" + }, + "bootstrap": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.0.tgz", + "integrity": "sha512-M0vqY0Z6UDweV2nLFl5dXcb+GIo53EBCGMMVxCGH5vJxl/jsr+HkULBMd4kn9rdpdBZwd3BduCgMOYOwJybo4Q==" + }, + "codemirror": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.43.0.tgz", + "integrity": "sha512-mljwQWUaWIf85I7QwTBryF2ASaIvmYAL4s5UCanCJFfKeXOKhrqdHWdHiZWAMNT+hjLTCnVx2S/SYTORIgxsgA==" + }, + "datatables": { + "version": "1.10.18", + "resolved": "https://registry.npmjs.org/datatables/-/datatables-1.10.18.tgz", + "integrity": "sha512-ntatMgS9NN6UMpwbmO+QkYJuKlVeMA2Mi0Gu/QxyIh+dW7ZjLSDhPT2tWlzjpIWEkDYgieDzS9Nu7bdQCW0sbQ==", + "requires": { + "jquery": ">=1.7" + } + }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, + "mathjax": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", + "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" + }, + "popper.js": { + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz", + "integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..07076e8 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "description": "Javascript libraries required to run the server", + "email": "mjsb@uevora.pt", + "dependencies": { + "@fortawesome/fontawesome-free": "^5.7.1", + "bootstrap": "^4.3.0", + "codemirror": "^5.43.0", + "datatables": "^1.10.18", + "jquery": "^3.3.1", + "mathjax": "^2.7.5", + "popper.js": "^1.14.7" + } +} diff --git a/perguntations/static/README b/perguntations/static/README deleted file mode 100644 index d0c6791..0000000 --- a/perguntations/static/README +++ /dev/null @@ -1,28 +0,0 @@ -# Javascript libraries - -The javascript libraries should be installed in the `lib` directory. -Either make a `lib` directory here or a symbolic link to somewhere else. - -Currently, libs should contain: - - bootstrap - codemirror - DataTables - fontawesome - MathJax - -and the files: - - jquery.min.js - popper.min.js - -The DataTables directory was generated by https://www.datatables.net/download/ -Select: - -- styling: bootstrap4 -- packages: datatables -- extensions: responsive - -This will generate a zip that contains the directory `DataTables`. Expand the -zip into `lib`. - diff --git a/perguntations/static/bootstrap b/perguntations/static/bootstrap new file mode 120000 index 0000000..b3703d9 --- /dev/null +++ b/perguntations/static/bootstrap @@ -0,0 +1 @@ +../../node_modules/bootstrap/dist/ \ No newline at end of file diff --git a/perguntations/static/codemirror b/perguntations/static/codemirror new file mode 120000 index 0000000..de58ef1 --- /dev/null +++ b/perguntations/static/codemirror @@ -0,0 +1 @@ +../../node_modules/codemirror/ \ No newline at end of file diff --git a/perguntations/static/datatables b/perguntations/static/datatables new file mode 120000 index 0000000..7c398c4 --- /dev/null +++ b/perguntations/static/datatables @@ -0,0 +1 @@ +../../node_modules/datatables/media/ \ No newline at end of file diff --git a/perguntations/static/fontawesome-free b/perguntations/static/fontawesome-free new file mode 120000 index 0000000..50141d7 --- /dev/null +++ b/perguntations/static/fontawesome-free @@ -0,0 +1 @@ +../../node_modules/@fortawesome/fontawesome-free/ \ No newline at end of file diff --git a/perguntations/static/jquery b/perguntations/static/jquery new file mode 120000 index 0000000..7908e80 --- /dev/null +++ b/perguntations/static/jquery @@ -0,0 +1 @@ +../../node_modules/jquery/dist/ \ No newline at end of file diff --git a/perguntations/static/mathjax b/perguntations/static/mathjax new file mode 120000 index 0000000..5a0cffa --- /dev/null +++ b/perguntations/static/mathjax @@ -0,0 +1 @@ +../../node_modules/mathjax/ \ No newline at end of file diff --git a/perguntations/static/popper.js b/perguntations/static/popper.js new file mode 120000 index 0000000..8090f8d --- /dev/null +++ b/perguntations/static/popper.js @@ -0,0 +1 @@ +../../node_modules/popper.js/dist/ \ No newline at end of file diff --git a/perguntations/templates/admin.html b/perguntations/templates/admin.html index 14c97d9..7ddadc6 100644 --- a/perguntations/templates/admin.html +++ b/perguntations/templates/admin.html @@ -7,8 +7,8 @@ - - + + - - - - - + + + + + diff --git a/perguntations/templates/grade.html b/perguntations/templates/grade.html index 5df2934..82fa3d1 100644 --- a/perguntations/templates/grade.html +++ b/perguntations/templates/grade.html @@ -7,14 +7,15 @@ - + + - - - - + + + +
diff --git a/perguntations/templates/login.html b/perguntations/templates/login.html index e500ac8..97ffa98 100644 --- a/perguntations/templates/login.html +++ b/perguntations/templates/login.html @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/perguntations/templates/review.html b/perguntations/templates/review.html index f725474..699719d 100644 --- a/perguntations/templates/review.html +++ b/perguntations/templates/review.html @@ -17,15 +17,15 @@ - - - + + + - - - - + + + + diff --git a/perguntations/templates/test.html b/perguntations/templates/test.html index c12facf..13a012d 100644 --- a/perguntations/templates/test.html +++ b/perguntations/templates/test.html @@ -14,22 +14,22 @@ } }); - + - - - - - - - + + + + + + + - + + + - - -- libgit2 0.21.2