# SMart SCHeduling [](https://git-r3lab.uni.lu/NCER-PD/scheduling-system/commits/master) ## Docker version If you'd like to try out the application without preparing the environment, you can use Docker (you must have _Docker_ and _docker-compose_ installed): ``` # Navigate to the project's directory docker-compose build && docker-compose up # To add a new user, type in the new terminal: docker-compose exec web sh python manage.py createsuperuser ``` ## Required software (on ubuntu's OS family): - `sudo apt-get install libpq-dev python-dev postgresql postgresql-contrib python virtualenv python-virtualenv gcc python-lxml libxml2-dev libcurl4-openssl-dev libcurl4-gnutls-dev libgnutls28-dev` ## Postgres installation - If you don't have postgres installed, complete step seven from [https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-django-with-postgres-nginx-and-gunicorn](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-django-with-postgres-nginx-and-gunicorn) (remember to save all the credentials, they will be necessary to run the application). ## Developer project installation - `mkdir -p ~/dev/smash` - `cd ~/dev/smash` - `git clone ssh://git@git-r3lab-server.uni.lu:8022/NCER-PD/scheduling-system.git` - `cd scheduling-system` - `virtualenv env` to create new virtualenv (contains clean python working environment) - `. env/bin/activate` (to start using virtualenv) - `pip install -r requirements.txt` to install project's dependencies - Create `local_settings.py` file in `(./scheduling-system)/smash/smash` directory by copying the template in `(./scheduling-system)/smash/smash/local_settings.template` and edit your local_setttings.py file to change your database connection data. - Update migration db scrpit from file structure (`./scheduling-system/smash/manage.py makemigrations`) - Create the database by applying migrations (`./scheduling-system/smash/manage.py migrate`) - Create the first, administrative, user- (`./scheduling-system/smash/manage.py createsuperuser`) ## Development - Remember, that before working you have to activate _virtualenv_, by: `devel@host ~/home/smash/scheduling-system $ . env/bin/activate` - In order to run development server, run: `devel@host ~/home/smash/scheduling-system/smash $ ./manage.py runserver` and go to `127.0.0.1:8000` in browser - For reference of HTML tempalte, see [https://almsaeedstudio.com/themes/AdminLTE/pages/widgets.html#](https://almsaeedstudio.com/themes/AdminLTE/pages/widgets.html#) ### Mac Developers In case of problems with the openssl version installed on the system: ``` export PYCURL_SSL_LIBRARY=openssl pip install pycurl --global-option=build_ext --global-option="-I/usr/local/Cellar/openssl/1.0.2k/include" --global-option="-L/usr/local/Cellar/openssl/1.0.2k/lib" --upgrade pip install psycopg2 --global-option=build_ext --global-option="-I/usr/local/Cellar/openssl/1.0.2k/include" --global-option="-L/usr/local/Cellar/openssl/1.0.2k/lib" --upgrade ``` ## Production deployment - git pull and other project installation should be performed in a dir where this django app should be installed, in this tutorial it's /var/www/scheduling-system/ - install nginx: `apt-get install nginx` - create gunicorn service in systemd (http://docs.gunicorn.org/en/stable/deploy.html#systemd): ### /etc/systemd/system/gunicorn.service ``` [Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] PIDFile=/run/gunicorn/pid User=www-data Group=www-data WorkingDirectory=/var/www/scheduling-system/smash ExecStart=/var/www/scheduling-system/env/bin/gunicorn --pid /run/gunicorn/pid smash.wsgi --error-logfile /var/log/gunicorn.log --log-level DEBUG --capture-output --limit-request-line 8192 ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target ``` Don't forget to change ownership of `/run/gunicorn/` folder and `/var/log/gunicorn.log` file. ``` chown -R www-data:www-data /run/gunicorn/ touch /var/log/gunicorn.log chown www-data:www-data /var/log/gunicorn.log ``` ### /etc/systemd/system/gunicorn.socket ``` [Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn/socket ListenStream=0.0.0.0:9000 ListenStream=[::]:8000 [Install] WantedBy=sockets.target ``` - modify nginx configuration ### /etc/nginx/nginx.conf ``` user www-data; worker_processes auto; pid /run/nginx.pid; events { worker_connections 768; # multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_disable "msie6"; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } ``` ### /etc/nginx/sites-enabled/default ``` upstream app_server { # fail_timeout=0 means we always retry an upstream even if it failed # to return a good HTTP response # for UNIX domain socket setups server unix:/run/gunicorn/socket fail_timeout=0; # for a TCP configuration # server 192.168.0.7:8000 fail_timeout=0; } server { listen 80 default_server; listen [::]:80 default_server; listen 443 ssl; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name prc.parkinson.lu; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; #configuration for static and media files hosted by nginx location /media/ { root /var/www/scheduling-system-files; } location /static/ { root /var/www/scheduling-system-files; } location / { # checks for static file, if not found proxy to app proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # enable this if and only if you use HTTPS # proxy_set_header X-Forwarded-Proto https; proxy_set_header Host $http_host; # we don't want nginx trying to do something clever with # redirects, we set the Host: header above already. proxy_redirect off; proxy_pass http://app_server; } } ``` - extract static files and make them available via nginx: `./manage.py collectstatic` - you start application by starting gunicorn and nginx: `service gunicorn start`, `service nginx start` ## Cron jobs (weekly emails) If weekly emails are required then cron must be edited to fire periodically django function that send emails. ``` > crontab -e SHELL=/bin/bash */30 * * * * source /var/www/scheduling-system/env/bin/activate && python /var/www/scheduling-system/smash/manage.py runcrons >> /var/log/django-cronjob.log 2>&1 ``` ## Operations ### Disable two steps authentication for a specific user ``` ./manage.py two_factor_disable ${USERNAME} ``` ### Public holidays to import public holidays run: ``` ./manage.py holidays ${YEARS} ``` where ${YEARS} should be a space separated list of years for which the holidays will be imported. example: ``` ./manage.py holidays 2017 2018 2019 ```