Name Last Update
aprendizations Loading commit data...
config Loading commit data...
demo Loading commit data...
.gitignore Loading commit data...
BUGS.md Loading commit data...
LICENSE Loading commit data...
MANIFEST.in Loading commit data...
QUESTIONS.md Loading commit data...
README.md Loading commit data...
mypy.ini Loading commit data...
package-lock.json Loading commit data...
package.json Loading commit data...
setup.py Loading commit data...

README.md

Getting Started

Requirements

This application requires python3.7+ and a few additional python packages. It also uses npm (Node package management) to install javascript libraries.

Install python3.7 with sqlite3 support and npm

This can be done using the system package management, downloaded from http://www.python.org, or compiled from sources.

  • Installing from the system package manager:
sudo port install python37 npm5              # MacOS
sudo pkg install python37 py37-sqlite3 npm   # FreeBSD
sudo apt install python3.7 npm               # Linux
  • Installing from source:

Download from http://www.python.org and

unxz Python-3.7.tar.xz
tar xvf Python-3.7.tar
cd Python-3.7
./configure --prefix=$HOME/.local/bin
make && make install

This will install python locally under ~/.local/bin. Make sure to add it to your PATH (edit ~/.profile in MacOS or FreeBSD).

Install pip

If the pip command is not yet installed, run one of these:

sudo apt install python3.7-pip     # Ubuntu
sudo pkg py37-pip                  # FreeBSD
sudo port install py37-pip         # MacOS
python3.7 -m ensurepip --user      # otherwise

The latter will install pip in your user account under ~/.local/bin. In the end you should be able to run pip3 --version and python3 -c "import sqlite3" without errors (sometimes pip3 is pip, pip3.7 or pip-3.7).

If you want to always install python modules on the user account (recommended), edit the pip configuration file ~/.config/pip/pip.conf (FreeBSD, Linux) or Library/Application Support/pip/pip.conf (MacOS) and add the lines

[global]
user = yes

Install python packages and javascript libraries:

Replace USER by your bitbucket username:

cd somewhere
git clone https://git.xdi.uevora.pt/mjsb/aprendizations.git
cd aprendizations
pip install .           # install aprendizations and dependencies
npm install             # install javascript libraries

Python packages are usually installed in:

  • ~/.local/lib/python3.7/site-packages/ in Linux/FreeBSD.
  • ~/Library/python/3.7/lib/python/site-packages/ in MacOS.

Javascript libraries are installed in aprendizations/node_modules directory. This libraries have symbolic links from aprendizations/aprendizations/static.

At this point aprendizations is installed in

~/Library/Python/3.7/bin              # MacOS
~/.local/bin                          # FreeBSD/Linux

Make sure this directory is in your $PATH.

The server can be run with the command aprendizations from the terminal.

Configuration

Database

The user data is maintained in a sqlite3 database file. We first need to create the database. At the moment, the database should be located in the same directory as the main configuration file (see below). As an example, do

cd demo                               # contains a small example
initdb-aprendizations                 # show or initialize database
initdb-aprendizations --admin         # add admin user
initdb-aprendizations inscricoes.csv  # add students from CSV
initdb-aprendizations --add 1184 "Aladino da Silva"   # add user
initdb-aprendizations --update 1184 --pw alibaba      # update password
initdb-aprendizations --help          # for the available options

The default password is equal to the user name used to login.

SSL Certificates

We need certificates for https. Certificates can be self-signed or validated by a trusted authority.

Self-signed can be used locally for development and testing, but browsers will complain. LetsEncrypt issues trusted and free certificates, but the server must have a registered publicly accessible domain name.

Selfsigned

Generate a selfsigned certificate and place it in ~/.local/share/certs.

openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out cert.pem -days 365 -nodes

LetsEncrypt

sudo pkg install py27-certbot       # FreeBSD

Shutdown the firewall and any web server that might be running. Then run the script to generate the certificate:

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 under /usr/local/etc/letsencrypt/live/www.example.com/. Copy them to ~/.local/share/certs and change permissions to be readable:

sudo cp /usr/local/etc/letsencrypt/live/www.example.com/cert.pem .
sudo cp /usr/local/etc/letsencrypt/live/www.example.com/privkey.pem .
chmod 400 cert.pem privkey.pem

Renews can be done as follows:

sudo service pf stop   # shutdown firewall
sudo certbot renew
sudo service pf start  # start firewall

and then copy the cert.pem and privkey.pem files to ~/.local/share/certs directory. Change permissions and ownership as appropriate.

Testing

The application includes a small example in demo/demo.yaml. Run it with

cd demo
aprendizations demo.yaml

and open a browser at https://127.0.0.1:8443. If it everything looks good, check at the correct address https://www.example.com (requires port forward in the firewall). The option --debug provides more verbose logging and might be useful during testing. The option --check generates all the questions once before running the server to check for any obvious syntax error.

Firewall configuration

Ports 80 and 443 are only usable by root. For security reasons it is better to run the server as an unprivileged user on higher ports like 8080 for http and 8443 for https. For this, we can configure port forwarding in the firewall to redirect incoming tcp traffic from 80 to 8080 and 443 to 8443.

FreeBSD and pf

Edit /etc/pf.conf:

ext_if="em0"                # this should be the correct network interface
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

Under virtualbox with guest additions use ext_if="vtnet0".

Edit /etc/rc.conf

pf_enable="YES"
pf_flags=""
pf_rules="/etc/pf.conf"

# optional logging:
pflog_enable="YES"
pflog_flags=""
pflog_logfile="/var/log/pflog"

Reboot or sudo service pf start.

Troubleshooting

To help with troubleshooting, use the option --debug when running the server. This will increase logs in the terminal and will present the python exception errors in the browser.

Logging levels can be adjusted in ~/.config/aprendizations/logger.yaml and ~/.config/aprendizations/logger-debug.yaml.

If these files do not yet exist, there are examples in aprendizations/config that can be copied to ~/.config/aprendizations.

UnicodeEncodeError

The server should not generate this error, but when using external scripts to generate questions or to correct, these scripts can print unicode strings to stdout. If the terminal does not support unicode, python will generate this exception.

  • FreeBSD fix: edit ~/.login_conf to use UTF-8, for example:
me:\
    :charset=UTF-8:\
    :lang=en_US.UTF-8:
  • Debian fix: check locale...

FAQ

  • Which students did at least one topic?
sqlite3 students.db "select distinct student_id from studenttopic"
  • How many topics has each student done?
sqlite3 students.db "select student_id, count(topic_id) from studenttopic group by student_id order by count(topic_id) desc"
  • Which questions have more wrong answers?
sqlite3 students.db "select count(ref), ref from answers where grade<1.0 group by ref order by count(ref) desc"