diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8d28c037..f9fde42e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,25 +1,51 @@ -image: python:3.8 - stages: - test - quality-assurance -before_script: - - pip install tox - +# Debian Buster py37-django22: - image: python:3.7 stage: test + image: debian:buster-backports + before_script: + - > + apt-get update && + apt-get install -t buster-backports -y python3-django python3-django-crispy-forms + python3-django-extensions python3-django-filters python3-django-polymorphic + python3-djangorestframework python3-django-cas-server python3-psycopg2 python3-pil + python3-babel python3-lockfile python3-pip python3-phonenumbers ipython3 + gettext libjs-bootstrap4 fonts-font-awesome tox && + rm -rf /var/lib/apt/lists/* script: tox -e py37-django22 +# Ubuntu 20.04 py38-django22: - image: python:3.8 stage: test + image: ubuntu:20.04 + before_script: + # Fix tzdata prompt + - ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone + - > + apt-get update && + apt-get install -y python3-django python3-django-crispy-forms + python3-django-extensions python3-django-filters python3-django-polymorphic + python3-djangorestframework python3-django-cas-server python3-psycopg2 python3-pil + python3-babel python3-lockfile python3-pip python3-phonenumbers ipython3 + gettext libjs-bootstrap4 fonts-font-awesome tox && + rm -rf /var/lib/apt/lists/* script: tox -e py38-django22 linters: - image: python:3.8 stage: quality-assurance + image: debian:buster-backports + before_script: + - > + apt-get update && + apt-get install -t buster-backports -y python3-django python3-django-crispy-forms + python3-django-extensions python3-django-filters python3-django-polymorphic + python3-djangorestframework python3-django-cas-server python3-psycopg2 python3-pil + python3-babel python3-lockfile python3-pip python3-phonenumbers ipython3 + gettext libjs-bootstrap4 fonts-font-awesome tox && + rm -rf /var/lib/apt/lists/* script: tox -e linters # Be nice to new contributors, but please use `tox` diff --git a/Dockerfile b/Dockerfile index 60acc6e3..ef2531a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,26 @@ -FROM python:3-alpine +FROM debian:buster-backports +# Force the stdout and stderr streams to be unbuffered ENV PYTHONUNBUFFERED 1 -# Install LaTeX requirements -RUN apk add --no-cache gettext texlive texmf-dist-latexextra texmf-dist-fontsextra nginx gcc libc-dev libffi-dev postgresql-dev libxml2-dev libxslt-dev jpeg-dev +# Install Django, external apps, LaTeX and dependencies +RUN apt-get update && \ + apt-get install -t buster-backports -y python3-django python3-django-crispy-forms \ + python3-django-extensions python3-django-filters python3-django-polymorphic \ + python3-djangorestframework python3-django-cas-server python3-psycopg2 python3-pil \ + python3-babel python3-lockfile python3-pip python3-phonenumbers ipython3 \ + uwsgi uwsgi-plugin-python3 \ + texlive-latex-extra texlive-fonts-extra texlive-lang-french \ + gettext libjs-bootstrap4 fonts-font-awesome && \ + rm -rf /var/lib/apt/lists/* -RUN apk add --no-cache bash +# Instal PyPI requirements +COPY requirements.txt /var/www/note_kfet/ +RUN pip3 install -r /var/www/note_kfet/requirements.txt --no-cache-dir -RUN mkdir /code -WORKDIR /code -COPY requirements /code/requirements -RUN pip install gunicorn ptpython --no-cache-dir -RUN pip install -r requirements/base.txt -r requirements/cas.txt -r requirements/production.txt --no-cache-dir +# Copy code +WORKDIR /var/www/note_kfet +COPY . /var/www/note_kfet/ -COPY . /code/ - -# Configure nginx -RUN mkdir /run/nginx -RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log -RUN ln -sf /code/nginx_note.conf_docker /etc/nginx/conf.d/nginx_note.conf -RUN rm /etc/nginx/conf.d/default.conf - -ENTRYPOINT ["/code/entrypoint.sh"] -EXPOSE 80 - -CMD ["./manage.py", "shell_plus", "--ptpython"] +EXPOSE 8080 +ENTRYPOINT ["/var/www/note_kfet/entrypoint.sh"] diff --git a/README.md b/README.md index 7087b120..76cc69a3 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,25 @@ Sinon vous pouvez suivre les étapes ici. ### Installation avec Debian/Ubuntu 1. **Installation des dépendances APT.** + On tire les dépendances le plus possible à partir des dépôts de Debian. + On a besoin d'un environnement LaTeX pour générer les factures. ```bash - $ sudo apt install nginx python3 python3-pip python3-dev uwsgi uwsgi-plugin-python3 python3-venv git acl - ``` - - La génération des factures de l'application trésorerie nécessite une installation de LaTeX suffisante, - - ```bash - $ sudo apt install texlive-latex-extra texlive-fonts-extra texlive-lang-french + $ sudo apt update + $ sudo apt install -t buster-backports -y python3-django python3-django-crispy-forms \ + python3-django-extensions python3-django-filters python3-django-polymorphic \ + python3-djangorestframework python3-django-cas-server python3-psycopg2 python3-pil \ + python3-babel python3-lockfile python3-pip python3-phonenumbers ipython3 \ + uwsgi uwsgi-plugin-python3 \ + texlive-latex-extra texlive-fonts-extra texlive-lang-french \ + gettext libjs-bootstrap4 fonts-font-awesome \ + nginx python3-venv git acl ``` 2. **Clonage du dépot** dans `/var/www/note_kfet`, ```bash - $ mkdir -p /var/www/note_kfet && cd /var/www/note_kfet + $ sudo mkdir -p /var/www/note_kfet && cd /var/www/note_kfet $ sudo chown www-data:www-data . $ sudo chmod g+rwx . $ sudo -u www-data git clone git@gitlab.crans.org:bde/nk20.git . @@ -39,8 +43,7 @@ Sinon vous pouvez suivre les étapes ici. ```bash $ python3 -m venv env $ source env/bin/activate - (env)$ pip3 install -r requirements/base.txt - (env)$ pip3 install -r requirements/prod.txt # uniquement en prod, nécessite une base postgres + (env)$ pip3 install -r requirements.txt (env)$ deactivate # sortir de l'environnement ``` @@ -144,30 +147,44 @@ Sinon vous pouvez suivre les étapes ici. Il est possible de travailler sur une instance Docker. -1. Cloner le dépôt là où vous voulez : +Pour construire l'image Docker `nk20`, - $ git clone git@gitlab.crans.org:bde/nk20.git +``` +git clone https://gitlab.crans.org/bde/nk20/ && cd nk20 +docker build . -t nk20 +``` -2. Copiez le fichier `.env_example` à la racine du projet vers le fichier `.env`, - et mettez à jour vos variables d'environnement +Ensuite pour lancer la note Kfet en tant que vous (option `-u`), +l'exposer sur son port 80 (option `-p`) et monter le code en écriture (option `-v`), -3. Dans le fichier `docker_compose.yml`, qu'on suppose déjà configuré, - ajouter les lignes suivantes, en les adaptant à la configuration voulue : +``` +docker run -it --rm -u $(id -u):$(id -g) -v "$(pwd):/var/www/note_kfet/" -p 80:8080 nk20 +``` - nk20: - build: /chemin/vers/nk20 - volumes: - - /chemin/vers/nk20:/code/ - env_file: /chemin/vers/nk20/.env - restart: always - labels: - - traefik.domain=ndd.example.com - - traefik.frontend.rule=Host:ndd.example.com - - traefik.port=8000 +Si vous souhaitez lancer une commande spéciale, vous pouvez l'ajouter à la fin, par exemple, -4. Enjoy : +``` +docker run -it --rm -u $(id -u):$(id -g) -v "$(pwd):/var/www/note_kfet/" -p 80:8080 nk20 python3 ./manage.py createsuperuser +``` - $ docker-compose up -d nk20 +#### Avec Docker Compose + +On vous conseilles de faire un fichier d'environnement `.env` en prenant exemple sur `.env_example`. + +Pour par exemple utiliser le Docker de la note Kfet avec Traefik pour réaliser le HTTPS, + +```YAML +nk20: + build: /chemin/vers/le/code/nk20 + volumes: + - /chemin/vers/le/code/nk20:/var/www/note_kfet/ + env_file: /chemin/vers/le/code/nk20/.env + restart: always + labels: + - traefik.domain=ndd.example.com + - traefik.frontend.rule=Host:ndd.example.com + - traefik.port=8080 +``` ### Lancer un serveur de développement @@ -183,7 +200,7 @@ un serveur de développement par exemple sur son ordinateur. $ python3 -m venv venv $ source venv/bin/activate - (env)$ pip install -r requirements/base.txt + (env)$ pip install -r requirements.txt 3. Copier le fichier `.env_example` vers `.env` à la racine du projet et mettre à jour ce qu'il faut diff --git a/ansible/roles/1-apt-basic/tasks/main.yml b/ansible/roles/1-apt-basic/tasks/main.yml index eba6e5c3..105fbf36 100644 --- a/ansible/roles/1-apt-basic/tasks/main.yml +++ b/ansible/roles/1-apt-basic/tasks/main.yml @@ -13,6 +13,8 @@ - git - acl - gettext + - libjs-bootstrap4 + - fonts-font-awesome - texlive-latex-extra - texlive-fonts-extra - texlive-lang-french diff --git a/ansible/roles/4-nginx/templates/nginx_note.conf b/ansible/roles/4-nginx/templates/nginx_note.conf index 9be2d980..b195e739 100644 --- a/ansible/roles/4-nginx/templates/nginx_note.conf +++ b/ansible/roles/4-nginx/templates/nginx_note.conf @@ -53,7 +53,7 @@ server { # Finally, send all non-media requests to the Django server. location / { uwsgi_pass note; - include /var/www/note_kfet/uwsgi_params; # the uwsgi_params file you installed + include /etc/nginx/uwsgi_params; } ssl_certificate /etc/letsencrypt/live/nk20-beta.crans.org/fullchain.pem; diff --git a/apps/member/templates/member/base.html b/apps/member/templates/member/base.html index bb99595e..e1e9335b 100644 --- a/apps/member/templates/member/base.html +++ b/apps/member/templates/member/base.html @@ -69,11 +69,11 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endif %} {% if can_lock_note %} {% elif can_unlock_note %} {% endif %} @@ -181,4 +181,4 @@ SPDX-License-Identifier: GPL-3.0-or-later }); } -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/apps/member/templates/member/user_list.html b/apps/member/templates/member/user_list.html index ce0b14a7..a41d7e69 100644 --- a/apps/member/templates/member/user_list.html +++ b/apps/member/templates/member/user_list.html @@ -7,7 +7,7 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block content %} {% if "member.change_profile_registration_valid"|has_perm:user %} - {% trans "Registrations" %} + {% trans "Registrations" %} {% endif %} diff --git a/apps/permission/templates/permission/all_rights.html b/apps/permission/templates/permission/all_rights.html index 107f8f25..69b74714 100644 --- a/apps/permission/templates/permission/all_rights.html +++ b/apps/permission/templates/permission/all_rights.html @@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
- {% trans "Superusers have all rights on everything, to manage the website." %} + {% trans "Superusers have all rights on everything, to manage the website." %}
@@ -116,4 +116,4 @@ SPDX-License-Identifier: GPL-3.0-or-later update(); }); -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/apps/wei/templates/wei/base.html b/apps/wei/templates/wei/base.html index dd343f8e..a6521bd2 100644 --- a/apps/wei/templates/wei/base.html +++ b/apps/wei/templates/wei/base.html @@ -43,14 +43,14 @@ SPDX-License-Identifier: GPL-3.0-or-later {% with bde_kfet_fee=club.parent_club.membership_fee_paid|add:club.parent_club.parent_club.membership_fee_paid %}
{% trans 'WEI fee (paid students)'|capfirst %}
{{ club.membership_fee_paid|add:bde_kfet_fee|pretty_money }} -
{% endwith %} {% with bde_kfet_fee=club.parent_club.membership_fee_unpaid|add:club.parent_club.parent_club.membership_fee_unpaid %}
{% trans 'WEI fee (unpaid students)'|capfirst %}
{{ club.membership_fee_unpaid|add:bde_kfet_fee|pretty_money }} -
{% endwith %} {% endif %} @@ -106,4 +106,4 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block profile_content %}{% endblock %}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/entrypoint.sh b/entrypoint.sh index 09cbc3c8..ab33fbe8 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -5,20 +5,29 @@ if [ -z ${NOTE_URL+x} ]; then echo "Warning: your env files are not configurated." else - sed -i -e "s/example.com/$DOMAIN/g" /code/apps/member/fixtures/initial.json - sed -i -e "s/localhost/$NOTE_URL/g" /code/note_kfet/fixtures/initial.json - sed -i -e "s/\"\.\*\"/\"https?:\/\/$NOTE_URL\/.*\"/g" /code/note_kfet/fixtures/cas.json - sed -i -e "s/REPLACEME/La Note Kfet \\\\ud83c\\\\udf7b/g" /code/note_kfet/fixtures/cas.json + sed -i -e "s/example.com/$DOMAIN/g" /var/www/note_kfet/apps/member/fixtures/initial.json + sed -i -e "s/localhost/$NOTE_URL/g" /var/www/note_kfet/note_kfet/fixtures/initial.json + sed -i -e "s/\"\.\*\"/\"https?:\/\/$NOTE_URL\/.*\"/g" /var/www/note_kfet/note_kfet/fixtures/cas.json + sed -i -e "s/REPLACEME/La Note Kfet \\\\ud83c\\\\udf7b/g" /var/www/note_kfet/note_kfet/fixtures/cas.json fi -python manage.py compilemessages -python manage.py makemigrations -python manage.py migrate +# Set up Django project +python3 manage.py collectstatic --noinput +python3 manage.py compilemessages +python3 manage.py makemigrations +python3 manage.py migrate -nginx - -if [ "$DJANGO_APP_STAGE" = "prod" ]; then - gunicorn -b 0.0.0.0:8000 --workers=2 --threads=4 --worker-class=gthread note_kfet.wsgi --access-logfile '-' --error-logfile '-'; +if [ "$1" ]; then + # Command passed + echo "Running $@..." + $@ else - python manage.py runserver 0.0.0.0:8000; + # Launch server + if [ "$DJANGO_APP_STAGE" = "prod" ]; then + uwsgi --http-socket 0.0.0.0:8080 --master --plugins python3 \ + --module note_kfet.wsgi:application --env DJANGO_SETTINGS_MODULE=note_kfet.settings \ + --processes 4 --static-map /static=/var/www/note_kfet/static --harakiri=20 --max-requests=5000 --vacuum + else + python3 manage.py runserver 0.0.0.0:8080; + fi fi diff --git a/nginx_note.conf_docker b/nginx_note.conf_docker deleted file mode 100644 index 020fe204..00000000 --- a/nginx_note.conf_docker +++ /dev/null @@ -1,27 +0,0 @@ -# This is an example NGINX site configuration for note_kfet in Docker -# Only HTTP, please use a reverse proxy to secure it! - -server { - # Serve this site by default on HTTP - listen 80 default_server; - listen [::]:80 default_server; - - # Max upload size - client_max_body_size 75M; - - # Django statics and media - location /static { - alias /code/static; - } - location /media { - alias /code/media; - } - - # Send all non-media requests to the Django server. - location / { - proxy_pass http://127.0.0.1:8000; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_redirect off; - } -} diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index 2aa303ed..230bf441 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -164,8 +164,10 @@ LANGUAGES = [ STATIC_URL = '/static/' # Add some custom statics from /note_kfet/static +# Because we are using Debian, also include /usr/share/javascript STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'note_kfet/static'), + '/usr/share/javascript', ] # Collect statics to /static/ diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html index df38eac9..3381c78e 100644 --- a/note_kfet/templates/base.html +++ b/note_kfet/templates/base.html @@ -24,24 +24,14 @@ SPDX-License-Identifier: GPL-3.0-or-later {# Bootstrap, Font Awesome and custom CSS #} - - - + + {# JQuery, Bootstrap and Turbolinks JavaScript #} - - - + + + @@ -69,54 +59,54 @@ SPDX-License-Identifier: GPL-3.0-or-later {% if "note.transactiontemplate"|not_empty_model_list %} {% endif %} {% if "note.transaction"|not_empty_model_list %} {% endif %} {% if "auth.user"|model_list_length >= 2 %} {% endif %} {% if "member.club"|not_empty_model_list %} {% endif %} {% if "activity.activity"|not_empty_model_list %} {% endif %} {% if "treasury.invoice"|not_empty_model_list %} {% endif %} {% if "wei.weiclub"|not_empty_model_list %} {% endif %} {% if request.user.is_authenticated %} {% endif %} {% if request.user.is_staff and ""|has_perm:user %} {% endif %} @@ -124,16 +114,16 @@ SPDX-License-Identifier: GPL-3.0-or-later {% if request.user.is_authenticated %} @@ -141,14 +131,14 @@ SPDX-License-Identifier: GPL-3.0-or-later {% if request.path != "/registration/signup/" %} {% endif %} {% if request.path != "/accounts/login/" %} {% endif %} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..ac2104e2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +django-htcpcp-tea==0.3.1 +django-mailer==2.0.1 +django-phonenumber-field==4.0.0 +django-tables2==2.1.0 +django-rest-polymorphic==0.1.8 +django-bootstrap-datepicker-plus==3.0.5 +django-colorfield==0.3.2 diff --git a/requirements/base.txt b/requirements/base.txt deleted file mode 100644 index ba380f73..00000000 --- a/requirements/base.txt +++ /dev/null @@ -1,31 +0,0 @@ -beautifulsoup4==4.9.1 -certifi==2019.6.16 -chardet==3.0.4 -defusedxml==0.6.0 -Django~=2.2 -django-allauth==0.39.1 -django-crispy-forms==1.7.2 -django-extensions==2.1.9 -django-filter==2.2.0 -django-htcpcp-tea==0.3.1 -django-mailer==2.0.1 -django-phonenumber-field==4.0.0 -django-polymorphic==2.0.3 -django-tables2==2.1.0 -docutils==0.14 -idna==2.8 -lxml==4.5.2 -oauthlib==3.1.0 -phonenumbers==8.12.7 -Pillow==7.1.2 -python3-openid==3.1.0 -pytz==2019.1 -requests==2.22.0 -requests-oauthlib==1.2.0 -six==1.12.0 -sqlparse==0.3.0 -djangorestframework==3.9.0 -django-rest-polymorphic==0.1.8 -urllib3==1.25.3 -django-bootstrap-datepicker-plus==3.0.5 -django-colorfield==0.3.2 diff --git a/requirements/cas.txt b/requirements/cas.txt deleted file mode 100644 index 8a0baa85..00000000 --- a/requirements/cas.txt +++ /dev/null @@ -1 +0,0 @@ -django-cas-server==1.2.0 diff --git a/requirements/production.txt b/requirements/production.txt deleted file mode 100644 index fe939cce..00000000 --- a/requirements/production.txt +++ /dev/null @@ -1 +0,0 @@ -psycopg2-binary==2.8.4 diff --git a/tox.ini b/tox.ini index e47e699f..240c9523 100644 --- a/tox.ini +++ b/tox.ini @@ -10,12 +10,11 @@ envlist = skipsdist = True [testenv] +sitepackages = True setenv = - PYTHONWARNINGS = all + PYTHONWARNINGS = all deps = - -r{toxinidir}/requirements/base.txt - -r{toxinidir}/requirements/cas.txt - -r{toxinidir}/requirements/production.txt + -r{toxinidir}/requirements.txt coverage commands = ./manage.py makemigrations @@ -24,9 +23,7 @@ commands = [testenv:linters] deps = - -r{toxinidir}/requirements/base.txt - -r{toxinidir}/requirements/cas.txt - -r{toxinidir}/requirements/production.txt + -r{toxinidir}/requirements.txt flake8 flake8-colors flake8-import-order diff --git a/uwsgi_params b/uwsgi_params deleted file mode 100644 index 827deedb..00000000 --- a/uwsgi_params +++ /dev/null @@ -1,26 +0,0 @@ - -uwsgi_param QUERY_STRING $query_string; -uwsgi_param REQUEST_METHOD $request_method; -uwsgi_param CONTENT_TYPE $content_type; -uwsgi_param CONTENT_LENGTH $content_length; - -uwsgi_param REQUEST_URI $request_uri; -uwsgi_param PATH_INFO $document_uri; -uwsgi_param DOCUMENT_ROOT $document_root; -uwsgi_param SERVER_PROTOCOL $server_protocol; -uwsgi_param REQUEST_SCHEME $scheme; -uwsgi_param HTTPS $https if_not_empty; - -uwsgi_param REMOTE_ADDR $remote_addr; -uwsgi_param REMOTE_PORT $remote_port; -uwsgi_param SERVER_PORT $server_port; -uwsgi_param SERVER_NAME $server_name; - - - - - - - - -