SMart SCHeduling
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
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 (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 to127.0.0.1:8000
in browser - For reference of HTML tempalte, see 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