diff --git a/.deploy/apache/elgeopaso.conf b/.deploy/apache/elgeopaso.conf index 2cf7ad72..33a3e891 100644 --- a/.deploy/apache/elgeopaso.conf +++ b/.deploy/apache/elgeopaso.conf @@ -1,12 +1,11 @@ - ServerAdmin webmaster@georezo.net + ServerAdmin elpaso@georezo.net ServerName geotribu.georezo.net ServerAlias elgeopaso.georezo.net - ServerAlias elgeopaso.fr Redirect permanent / https://elgeopaso.georezo.net/ - ErrorLog /var/log/apache2/elpaso_error.log + ErrorLog /var/log/apache2/elgeopaso_error.log LogLevel warn - CustomLog /var/log/apache2/elpaso_access.log combined + CustomLog /var/log/apache2/elgeopaso_access.log combined diff --git a/.deploy/release-tasks.sh b/.deploy/release-tasks.sh index 54431013..c0ce5472 100644 --- a/.deploy/release-tasks.sh +++ b/.deploy/release-tasks.sh @@ -4,6 +4,7 @@ python manage.py migrate # load fixtures +python manage.py loaddata ./elgeopaso/fixtures/sites.json python manage.py loaddata ./elgeopaso/jobs/fixtures/contracts.json python manage.py loaddata ./elgeopaso/jobs/fixtures/jobs.json python manage.py loaddata ./elgeopaso/jobs/fixtures/places.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2e7af838 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +version: 2 +updates: + + - package-ecosystem: pip + directory: ".deploy/apache/" + schedule: + interval: monthly + time: "04:00" + timezone: Europe/Paris + reviewers: + - Guts + labels: + - dependencies + + - package-ecosystem: pip + directory: "/requirements" + schedule: + interval: monthly + time: "04:00" + timezone: Europe/Paris + reviewers: + - Guts + labels: + - dependencies + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + reviewers: + - Guts + labels: + - ci-cd + - dependencies diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index ea9d16a8..9f8b3966 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -20,16 +20,16 @@ jobs: uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2.2.1 with: python-version: ${{ matrix.python-version }} - name: Cache pip - uses: actions/cache@v1 + uses: actions/cache@v2.1.3 with: path: ~/.cache/pip # This path is specific to Ubuntu # Look to see if there is a cache hit for the corresponding requirements file - key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*.txt') }} restore-keys: | ${{ runner.os }}-pip- ${{ runner.os }}- @@ -37,7 +37,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements/local.txt + python -m pip install -r requirements/local.txt # download NLTK packages - please refer to `ntlk.txt` python -m nltk.downloader punkt stopwords @@ -65,7 +65,7 @@ jobs: - uses: actions/checkout@v2 # Install Python runtime and dependencies - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v2.2.1 with: python-version: 3.x diff --git a/.github/workflows/pr-auto-labeler.yml b/.github/workflows/pr-auto-labeler.yml index dcafb97d..b70f4c56 100644 --- a/.github/workflows/pr-auto-labeler.yml +++ b/.github/workflows/pr-auto-labeler.yml @@ -6,6 +6,6 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v2 + - uses: actions/labeler@v3 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/pre-commit_autoupdate.yml b/.github/workflows/pre-commit_autoupdate.yml new file mode 100644 index 00000000..9883d98f --- /dev/null +++ b/.github/workflows/pre-commit_autoupdate.yml @@ -0,0 +1,47 @@ +# Run pre-commit autoupdate every day at midnight +# and create a pull request if any changes + + +name: Pre-commit auto-update + +on: + schedule: + - cron: "0 0 1 * *" + workflow_dispatch: # to trigger manually + +env: + PYTHON_VERSION: 3.8 + +jobs: + auto-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2.2.1 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - uses: actions/cache@v2.1.3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install pre-commit + run: | + python -m pip install -U pip setuptools wheel + python -m pip install -U pre-commit + + - name: Run pre-commit autoupdate + run: pre-commit autoupdate + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3.6.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: update/pre-commit-autoupdate + title: Auto-update pre-commit hooks + commit-message: Auto-update pre-commit hooks + body: Update versions of tools in pre-commit configs to latest version + labels: update diff --git a/.gitignore b/.gitignore index d6227397..d0da178e 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ coverage.xml # Sphinx documentation docs/_build/ +docs/_apidoc/ # PyBuilder target/ @@ -101,6 +102,7 @@ nltk_data/* # bash .bash_history +# tests and PEP8 *.whl dev_flake8_report.txt junit/test-results.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14de1fca..24921c5f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ exclude: "node_modules|migrations|.venv|tests/dev/|tests/fixtures/" fail_fast: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.5.0 + rev: v3.4.0 hooks: - id: check-added-large-files args: ['--maxkb=500'] @@ -18,7 +18,7 @@ repos: args: [--markdown-linebreak-ext=md] - repo: https://github.com/python/black - rev: 19.10b0 + rev: 20.8b1 hooks: - id: black exclude_types: [directory,] diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..582b88c6 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,28 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# VCS +submodules: + exclude: all + recursive: false + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Build documentation with MkDocs +#mkdocs: +# configuration: mkdocs.yml + +# Optionally build your docs in additional formats such as PDF and ePub +formats: all + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - requirements: requirements/local.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index 15697bcb..f0bf1a3b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "python.linting.pylintArgs": [ "--load-plugins=pylint_django" ], - "python.pythonPath": "${workspaceFolder}\\.venv\\Scripts\\python.exe", + "python.pythonPath": ".venv/bin/python3.8", "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ "-c", @@ -19,4 +19,5 @@ "python.testing.nosetestsEnabled": false, "autoDocstring.customTemplatePath": ".vscode\\docstring-config.mustache", "autoDocstring.generateDocstringOnEnter": false, + "restructuredtext.confPath": "${workspaceFolder}\\docs", } diff --git a/README.md b/README.md index 8b74ac29..7f1c9beb 100644 --- a/README.md +++ b/README.md @@ -3,65 +3,12 @@ ![Continuous integration and deployment](https://github.com/Guts/elgeopaso/workflows/Continuous%20integration%20and%20deployment/badge.svg) [![codecov](https://codecov.io/gh/Guts/elgeopaso/branch/master/graph/badge.svg)](https://codecov.io/gh/Guts/elgeopaso) !["Python 3.7.x"](https://img.shields.io/badge/python-3.7-blue.svg) +[![Documentation Status](https://readthedocs.org/projects/elgeopaso/badge/?version=latest)](https://elgeopaso.readthedocs.io/fr/latest/?badge=latest) [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) ----- +Envie d'en savoir plus ? Tout (enfin presque) est dans la documentation : -## Développement +[![](docs/_static/icon_doc.png)](https://elgeopaso.rtfd.io/) -### Docker - -```shell -docker-compose -f "docker-compose.dev.yml" up --build -``` - -Ouvrir le site sur . - ----- - -> TO MOVE - -## Description fonctionnelle - -### Récupération à partir de GeoRezo - -1. Toutes les heures, les dernières offres publiées sont récupérées à partir du [flux RSS du forum Job de GeoRezo](https://georezo.net/extern.php?fid=10) et stockées en brut dans une table dédiée ; -2. Chaque nouvelle offre est analysée en s'appuyant sur le kit de traitement du langage naturel NLTK et des correspondances personnalisables en base de données via l'interface d'administration ; - -### Représentation des données - -Les données sont ensuite représentées dans différents modes : - -* métriques globales ; -* valeurs absolues du nombre d'offre par période ; -* valeurs proportionnelles selon le différents critères (types de contrats...) - ----- - -## Description technique - -Pour dupliquer le projet, la documentation est dans [le wiki du dépôt](https://github.com/Guts/elgeopaso/wiki). - -### Base de données - -!["El Géo Paso - Modèle graphique de la base de données"](docs/elpaso_db_models_graph.png "El Geo Paso - DB") - - *Modèle généré automatiquement par Django Extensions graph-models (pydot)* - -### Briques logicielles - -Le projet est développé en Python 3.5.x avec le framework Django et des extensions : - -* [feedparser](https://pypi.org/project/feedparser/) pour la consommation du flux RSS -* [NLTK](http://www.nltk.org/) pour l'analyse sémantique -* [DRF (Django REST Framework)](http://www.django-rest-framework.org/) et [drf-yasg](https://github.com/axnsan12/drf-yasg/) pour la mise en place de l'API REST et sa documentation automatisée -* [Django Extensions](https://github.com/django-extensions/django-extensions) pour la boîte à outils de dév Django - -Du côté de l'interface du site web, on retrouve les classiques : - -* [Bootstrap](https://getbootstrap.com/) -* [D3.js](https://d3js.org/), via la surcouche [NVD3](http://nvd3.org) -* [Django Suit](https://djangosuit.com/) pour l'habillage de l'interface d'administration - -Le site est servi sur le Web par [gunicorn](https://gunicorn.org/) et nginx ou Apache selon les plateformes (dév ou production). +> Source icône : Book by Smalllike from the Noun Project diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/icon_doc.png b/docs/_static/icon_doc.png new file mode 100644 index 00000000..1b95186b Binary files /dev/null and b/docs/_static/icon_doc.png differ diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..53f12cde --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,161 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) + +# 3rd party +import django +import recommonmark +from recommonmark.transform import AutoStructify + +# Project +from elgeopaso import __about__ + + +# -- Build environment ----------------------------------------------------- +on_rtd = os.environ.get("READTHEDOCS", None) == "True" +os.environ["DJANGO_SETTINGS_MODULE"] = "elgeopaso.settings.local" +django.setup() + +# -- Project information ----------------------------------------------------- + +project = __about__.__title__ +author = __about__.__author__ +copyright = __about__.__copyright__ + +# The full version, including alpha/beta/rc tags +version = release = __about__.__version__ + +# replacement variables +rst_epilog = ".. |title| replace:: %s" % project +rst_epilog += "\n.. |author| replace:: %s" % author +rst_epilog += "\n.. |repo_url| replace:: %s" % __about__.__uri__ + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + # markdown + "recommonmark", + # Sphinx included + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", + # 3rd party + "sphinx_autodoc_typehints", + "sphinx_copybutton", + "sphinx_markdown_tables", + "sphinx_rtd_theme", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# source_suffix = ['.rst', '.md'] +source_suffix = {".rst": "restructuredtext", ".md": "markdown"} + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "fr" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "samples/*", "Thumbs.db", ".DS_Store", "*env*", "libs/*"] + + +# -- Options for HTML output ------------------------------------------------- + +# html_favicon = "static/img/sqlitetoairtable_logo.svg" +# html_logo = "static/img/sqlitetoairtable_logo.svg" + +# Ensure sidebar is the same along the pages +html_sidebars = { + "**": ["globaltoc.html", "relations.html", "sourcelink.html", "searchbox.html"] +} +html_static_path = ["_static"] +html_theme = "sphinx_rtd_theme" +html_theme_options = { + # "canonical_url": __about__.__uri_homepage__, + "display_version": True, + "logo_only": False, + "prev_next_buttons_location": "both", + "style_external_links": True, + "style_nav_header_background": "SteelBlue", + # Toc options + "collapse_navigation": False, + "includehidden": False, + "navigation_depth": 4, + "sticky_navigation": False, + "titles_only": False, +} + + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +html_search_language = "fr" + +# The master toctree document. +master_doc = "index" + +# -- Options for extensions ------------------------------------------------- + +# -- intersphinx: refer to others sphinx docs +intersphinx_mapping = { + "python": ("https://docs.python.org/fr/3/", None), + "django": ("https://django.readthedocs.org/en/stable/", None), +} + +# -- recommonmark +github_doc_root = __about__.__uri__ + "tree/master/docs" + +# -- API autodoc +# run api doc +def run_apidoc(_): + from sphinx.ext.apidoc import main + + cur_dir = os.path.normpath(os.path.dirname(__file__)) + output_path = os.path.join(cur_dir, "_apidoc") + modules = os.path.normpath(os.path.join(cur_dir, "../elgeopaso")) + exclusions = [] + main(["-e", "-f", "-M", "-o", output_path, modules] + exclusions) + + +# launch setup +def setup(app): + # api autodoc + app.connect("builder-inited", run_apidoc) + + # structify + app.add_config_value( + "recommonmark_config", + { + "url_resolver": lambda url: github_doc_root + url, + "auto_toc_tree_section": "Contents", + "enable_auto_toc_tree": True, + "enable_eval_rst": True, + }, + True, + ) + app.add_transform(AutoStructify) + app.connect("builder-inited", run_apidoc) diff --git a/docs/database/backup.md b/docs/database/backup.md new file mode 100644 index 00000000..1ef4adb2 --- /dev/null +++ b/docs/database/backup.md @@ -0,0 +1,88 @@ +# Sauvegarde et restauration de la base de données + +La base de données en production est motorisée par PostgreSQL/PostGIS (celle de développement par SQLite3) : + +```sql +elpaso=> SELECT version(); +elpaso=> PostgreSQL 9.6.9 on x86_64-pc-linux-gnu (Ubuntu 9.6.9-2.pgdg16.04+1), compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609, 64-bit +elpaso=> SELECT PostGIS_full_version(); +elpaso=> POSTGIS="2.4.4 r16526" PGSQL="96" GEOS="3.5.1-CAPI-1.9.1 r4246" PROJ="Rel. 4.9.2, 08 September 2015" GDAL="GDAL 1.11.3, released 2015/09/16" LIBXML="2.9.3" LIBJSON="0.11.99" LIBPROTOBUF="1.2.1" (core procs from "2.4.1 r16012" need upgrade) RASTER (raster procs from "2.4.1 r16012" need upgrade) +``` + +Les données sont de plusieurs types dans le projet : + +* les offres d'emploi : + * la version brute récupérée depuis les sources (RSS GeoRezo...) + * la version analysée + +* les données de référence qui servent à l'analyse : + + * les lieux et leurs variantes + * les types de contrats et leurs variantes + * les technologies et leurs variantes + * les métiers et leurs variantes + +* les contenus éditoriaux (page d'accueil, section aide...) + +* les tables liées à l'administration et à Django : utilisateurs, migrations... + +La base est sauvegardée : + +* via des tâches planifiées liées à l'infrastructure et à l'hébergeur +* via les outils de sauvegardes et restauration intégrés à Django (voir ci-dessous) +* la base sur le serveur de développement est régulièrement synchronisée dans le dépôt via Git LFS + +A l'avenir, il peut être envisagé d'utiliser [Django Smuggler](https://github.com/semente/django-smuggler) pour faciliter les opérations. + +---- + +## Utilitaires Django + +Les opérations doivent se faire dans l'environnement virtuel. Documentation de référence : + +* sauvegarder : [dumpdata](https://docs.djangoproject.com/en/dev/ref/django-admin/#dumpdata) +* restaurer : [loaddata](https://docs.djangoproject.com/en/dev/ref/django-admin/#loaddata) + +### Sauvegarder l'ensemble des données + +Utile pour effectuer une sauvegarde complète ou bien basculer les données entre développement et production. Attention, le fichier JSON produit est lourd (~90 Mo en juin 2018). + +#### Sauvegarder + +```bash +python manage.py dumpdata --exclude auth.permission --exclude contenttypes > elgeopaso_bkp_db.json +``` + +#### Restaurer + +```bash +python manage.py loaddata elgeopaso_bkp_db.json +``` + +### Sauvegarder les données de départ + +Pour un usage léger, des "fixtures" des principaux éléments nécessaires pour amorcer l'usage du projet sont exportes (avec indentation optionnelle) et stockées dans le dépôt du code. + +#### Sauvegarder + +```bash +python manage.py dumpdata jobs.Contract jobs.ContractVariations > elgeopaso/jobs/fixtures/contracts.json +python manage.py dumpdata jobs.JobPosition jobs.JobPositionVariations > elgeopaso/jobs/fixtures/metiers.json +python manage.py dumpdata jobs.Place jobs.PlaceVariations > elgeopaso/jobs/fixtures/places.json +python manage.py dumpdata jobs.Source > elgeopaso/jobs/fixtures/sources.json +python manage.py dumpdata jobs.Technology jobs.TechnologyVariations > elgeopaso/jobs/fixtures/technos.json +python manage.py dumpdata --exclude auth.permission --exclude contenttypes cms.Article cms.Category > elgeopaso/cms/fixtures/content.json +python manage.py dumpdata sites > elgeopaso/fixtures/sites.json +``` + +#### Restaurer + +```bash +python manage.py loaddata elgeopaso/jobs/fixtures/contracts.json +python manage.py loaddata elgeopaso/jobs/fixtures/metiers.json +python manage.py loaddata elgeopaso/jobs/fixtures/places.json +python manage.py loaddata elgeopaso/jobs/fixtures/sources.json +python manage.py loaddata elgeopaso/jobs/fixtures/technos.json +python manage.py loaddata elgeopaso/cms/fixtures/content.json +python manage.py loaddata elgeopaso/fixtures/sites.json +``` diff --git a/docs/database/index.md b/docs/database/index.md new file mode 100644 index 00000000..0d3e075c --- /dev/null +++ b/docs/database/index.md @@ -0,0 +1,79 @@ +# Administration de la base de données + +## Configuration initiale + +Ouvrir la session super-admin avec l'utilisateur `postgres` (créé par défaut lors de l'installation) : + +```bash +sudo -u postgres psql + +psql (12.2 (Ubuntu 12.2-2.pgdg16.04+1), serveur 9.6.17) +Saisissez « help » pour l'aide. + +postgres=# +``` + +Une fois dans l'invite de commandes `psql` : + +```psql +CREATE DATABASE elgeopaso; +``` + +Créer l'utilisateur avec les options recommandées pour Django : + +```psql +CREATE USER "elgeopaso-db-uzr"; +ALTER ROLE "elgeopaso-db-uzr" SET client_encoding TO 'utf8'; +ALTER ROLE "elgeopaso-db-uzr" SET default_transaction_isolation TO 'read committed'; +ALTER ROLE "elgeopaso-db-uzr" SET timezone TO 'UTC'; + +GRANT ALL PRIVILEGES ON DATABASE elgeopaso TO "elgeopaso-db-uzr"; + +\password "elgeopaso-db-uzr" +``` + +Ressources : + +* [Configuration PostgreSQL recommandée par Django](https://docs.djangoproject.com/fr/2.2/ref/databases/#postgresql-notes) +* [Doc officielle sur `ALTER ROLE` et la création protégée de mot de passe](https://docs.postgresql.fr/12/sql-alterrole.html) + +---- + +## Opérations courantes + +Après connexion en tant que super utilisateur : + +```bash +sudo -u postgres psql +``` + +### Lister les bases + +```psql +\l + + Liste des bases de données + Nom | Propriétaire | Encodage | Collationnement | Type caract. | Droits d'accès +-----------+--------------+----------+-----------------+--------------+----------------------- + elpaso | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 | =Tc/postgres + + | | | | | postgres=CTc/postgres+ + | | | | | geotribu=CTc/postgres + postgres | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 | + template0 | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres + + | | | | | postgres=CTc/postgres +(4 lignes) +``` + +### Lister les utilisateurs + +```psql +\du+ + + Liste des rôles + Nom du rôle | Attributs | Membre de | Description +-------------+---------------------------------------------------------------------------------+-----------+------------- + geotribu | | {} | + postgres | Superutilisateur, Créer un rôle, Créer une base, Réplication, Contournement RLS | {} | +``` diff --git a/docs/deployment/apache.md b/docs/deployment/apache.md new file mode 100644 index 00000000..c0738086 --- /dev/null +++ b/docs/deployment/apache.md @@ -0,0 +1,148 @@ +# Utiliser Apache pour servir le site + +Pour servir l'application avec Apache, retenir ces quelques points de vigilance : + +- par défaut, Apache ne support pas [WSGI](https://wsgi.readthedocs.io/en/latest/what.html). Il faut donc utiliser le module `mod_wsgi` pour Apache. +- par défaut sur Ubuntu 18.04, ce module est compilé ave Python 3.6. **Or, il faut utiliser la version compilée avec la même version de Python que celle utilisée par l'application**. + +## Prérequis + +```sh +# add repo with latest Apache version +sudo add-apt-repository ppa:ondrej/apache2 +# install apache and dependencies +sudo apt install apache2 apache2-dev brotli +# enable brotli module +sudo a2enmod brotli +``` + +## Déployer l'application Django avec le module Apache WSGI + +### 1. Identifier la bonne version du module et le chemin Python + +#### Installer et utiliser le module inclus dans l'environnement virtuel de l'application + +```sh +# in project folder +cd /var/www/elgeopaso +source .venv/bin/activate + +# install mod_wsgi Python module +python -m pip install mod-wsgi==4.7.* + +# run the config command to get the directives values +mod_wsgi-express module-config +> LoadModule wsgi_module "/var/www/elgeopaso/.venv/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so" +> WSGIPythonHome "/var/www/elgeopaso/.venv" +``` + +#### Installer et utiliser le module directement dans Apache + +```sh +# open root input +sudo su - +# in project folder +cd /var/www/elgeopaso +source .venv/bin/activate + +# install mod_wsgi Python module +python -m pip install mod-wsgi==4.7.* + +# run the config command to get the directives values +mod_wsgi-express install-module +> LoadModule wsgi_module "/usr/lib/apache2/modules/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so" +> WSGIPythonHome "/var/www/elgeopaso/.venv" +``` + +---- + +### 2. Mettre à jour la configuration Apache + +```sh +# edit Apache module wsgi loader +sudo nano /etc/apache2/mods-available/wsgi.load + +# paste the line output in the previous step. For example: +LoadModule wsgi_module "/usr/lib/apache2/modules/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so" +``` + +---- + +### 3. Enable site, reload and restart + +Validate configuration syntax: + +```sh +sudo apache2ctl -t +``` + +Enable virtual hosts: + +```sh +sudo a2ensite elpaso.conf +sudo a2ensite elpaso-ssl.conf +``` + +At the end, restart Apache server: + +```sh +sudo service apache2 restart +``` + +---- + +### 4. Générer le certificat SSL avec Let's Encrypt + +Il s'agit principalement de la reproduction de la doc officielle : . + +```sh +# travailler dans home +mkdir ~/letsencrypt +cd ~/letsencrypt + +# enregistrer le dépôt des paquets de certbot - letsencrypt +sudo apt update +sudo apt install software-properties-common +sudo add-apt-repository universe +sudo add-apt-repository ppa:certbot/certbot +sudo apt update + +# installer le certbot +sudo apt-get install certbot python3-certbot-apache + +# lancer le processus en choisiasant elgeopaso.georezo.net +sudo certbot --apache +``` + +Tester le renouvellement automatique : + +```sh +sudo certbot renew --dry-run +``` + +---- + +## Commandes habituelles + +```bash +# check full version and compilation details +apache2ctl -V + +# help +apache2ctl -h + +# list enabled modules +apache2ctl -M + +``` + +---- + +## Resources + +- [Django avec Apache et mod_wsgi](https://docs.djangoproject.com/fr/2.2/howto/deployment/wsgi/modwsgi/) +- [Déployer Apache sur Ubuntu](https://doc.ubuntu-fr.org/apache2) +- [documentation officielle du module mod_wsgi](https://modwsgi.readthedocs.io/en/develop/installation.html) +- [Le package Python correspondant au module WSGI pour Apache](https://pypi.org/project/mod-wsgi/) +- [Procédure de création d'un certificat SSL avec Let's Encrypt pour Apache](https://certbot.eff.org/lets-encrypt/ubuntuxenial-apache) +- [Outil de génération de configuration Apache par Mozilla](https://ssl-config.mozilla.org/) diff --git a/docs/deployment/git_flow.md b/docs/deployment/git_flow.md new file mode 100644 index 00000000..da134116 --- /dev/null +++ b/docs/deployment/git_flow.md @@ -0,0 +1,98 @@ +# Git Flow + +Le projet s'appuie sur l'intégration d'Heroku avec Github pour déployer des versions de test/développement et de pré-production : + +- [les *Review Apps*](https://devcenter.heroku.com/articles/github-integration-review-apps#changes) : des déploiements temporaires correspondant à une *Pull Request* +- [une application gratuite](https://www.heroku.com/pricing) : déploiement automatisé à partir de `master` sur . + +## Branches + +- `origin/master` : + - branche principale + - correspond à la pré-production + - *pull request* obligatoire : aucun commit ne peut être poussé directement + - automatiquement déployée sur Heroku : + +- `origin/develop` : + - branche générique pour le développement actif + +- `origin/housekeeping` : + - branche dédiée aux opérations courantes de maintenance, mise à jour des dépendances, etc. + +## Processus type + +1. Une nouvelle branche est créée ou une existante est utilisée + +2. Des changements sont apportés dans cette branche et poussés vers la branche principale (master) via une pull-request. Un déploiement temporaire est effectué sur une URL mi-aléatoire. Exemple : + + - travail sur l'amélioration de la lecture du RSS pour gérer les problèmes d'encodage : + - déploiement temporaire correspondant : - l'URL est indiqué sur la pull request + +3. Une fois les changements achevés et validés, ils sont fusionnés dans la branche principale (*merged*) qui est automatiquement déployée sur Heroku : + +4. Lorsqu'une nouvelle version est finalisée, un [numéro de version](../global/product_life.md) est ajouté via un `git tag`. + +> Pour comprendre l'étiquetage des commits, voir ou [Divers - Utilitaires](../misc/miscellaneous.md). + +---- + +## Déploiement + +### Depuis le serveur de production + +#### Configuration initiale de Git + +1. S'ajouter aux utilisateurs + + ```bash + sudo adduser geotribu users + ``` + +2. Générer une paire de clés SSH : + + ```bash + ssh-keygen -f ~/.ssh/git_elgeopaso_rsa -t rsa -b 4096 -C "elpaso@georezo.net" + ``` + +3. Ajouter la clé publique dans la partie **Deploy keys** du dépôt en lecture seule : . + +> Voir la documentation officielle de GitHub : + +#### Configurer le dossier de destination + +On utilise le fork du [script de François Romain](https://gist.github.com/francoisromain/58cabf43c2977e48ef0804848dee46c3) : + +```bash +# récupérer le script +mkdir ~/scripts +cd ~/scripts +git clone git@gist.github.com:36672e8730244764b4a047f6584bd66d.git git-flow-deploy + +# lancer le script +source git-flow-deploy/project-create elgeopaso + +# modifier le git hook +cd /srv/git/elgeopaso.git/hooks/ +sudo nano post-receive + +# copier le contenu du fichier : .deploy/git-hooks/post-receive +``` + +Ressources : + +- [le fichier du hook post-receive dans le dépôt](https://github.com/Guts/elgeopaso/blob/master/.deploy/git-hooks/post-receive.sh) +- Voir le billet de blog lié : + +### Depuis la machine locale + +Ajouter le dépôt distant correspondant au serveur : + +```powershell +git remote add deploy-prod ssh://geotribu@elgeopaso.georezo.net/srv/git/elgeopaso.git/ +``` + +Pour publier (par exemple depuis master) : + +```powershell +git push --follow-tags deploy-prod master +``` diff --git a/docs/deployment/preproduction.md b/docs/deployment/preproduction.md new file mode 100644 index 00000000..65bfc488 --- /dev/null +++ b/docs/deployment/preproduction.md @@ -0,0 +1,56 @@ +# Pré-production + +Le site est déployé en pré-production sur [Heroku](https://dashboard.heroku.com/apps). + +## Prérequis + +- compte Heroku : le niveau gratuit suffit pour un déploiement basique +- outil en ligne de commande Heroku : [CLI Heroku](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) + +## Déployer + +### Déploiement automatisé + +L'application peut être déployée automatiquement via le fichier `app.json`. + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +> Plus d'informations : + +### Déploiement pas à pas + +> Commandes lancées sous Windows 10 avec WSL activé. + +```powershell +# authenticate +heroku login + +# add convenient plugin to pull/push from/to `.env` files +# https://github.com/xavdid/heroku-config +heroku plugins:install heroku-config + +# create app in Europe +heroku create elgeopaso-dev --region eu + +# add PostgreSQL database and schedule backup +heroku addons:create heroku-postgresql:hobby-dev --version=12 +heroku pg:backups schedule --at "02:00 Europe/Paris" DATABASE_URL +# On bash, use simple quotes for the time zone: heroku pg:backups schedule --at '02:00 Europe/Paris' DATABASE_URL + +# set some environment variables pointing to application's settings +heroku config:set PYTHONHASHSEED=random +heroku config:set WEB_CONCURRENCY=4 +heroku config:set DJANGO_DEBUG=False +heroku config:set DJANGO_SETTINGS_MODULE=elgeopaso.settings.production +heroku config:set DJANGO_ALLOWED_HOSTS=elgeopaso-dev.herokuapp.com +heroku config:set DJANGO_ADMIN_URL=admin +heroku config:set DJANGO_SECRET_KEY=$(wsl -- openssl rand -base64 64) +# on bash: heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" + +# now, let's deploy +git push heroku master:master +heroku run python manage.py migrate +heroku run python manage.py createsuperuser --email elpaso@georezo.net +heroku run python manage.py check --deploy +heroku open +``` diff --git a/docs/deployment/production.md b/docs/deployment/production.md new file mode 100644 index 00000000..12ceb36d --- /dev/null +++ b/docs/deployment/production.md @@ -0,0 +1,65 @@ +# Déploiement + +> Ce guide se base sur Ubuntu Server 18.04 (Bionic) + +## Dépendances + +Avant, tout mettre à jour la liste des paquets + +```bash +sudo apt update +``` + +### Installer Python 3.7 + +Par défaut c'est Python 3.6 qui est livré avec Ubuntu 18.04 Bionic. Il nous faut donc : + +- installer Python 3.7 +- le définir comme version par défaut lorsque l'on tape `python3` + +```bash +# ajouter le dépôt dans lequel trouver Python 3.7 +sudo apt install software-properties-common +sudo add-apt-repository ppa:deadsnakes/ppa +sudo apt update +sudo apt install libpq-dev python3-pip python3.7 python3.7-dev python3.7-venv +``` + +Au passage, on installe tout ce qu'il faut pour builder [psycopg2](https://tekshinobi.com/install-psycopg2-on-ubuntu-18-04/). + +#### Personnaliser bash + +Configurer `bash` pour faire correspondre `python3` à Python 3.7 : + +```bash +nano ~/.bashrc +``` + +Ajouter les lignes en fin de fichier : + +```config +# Custom python3 alias +alias python='/usr/bin/python3.7' +``` + +Charger la configuration : + +```bash +. ~/.bashrc +``` + +### Installer git + +On a besoin d'utiliser les versions récentes de `git`. + +```bash +sudo add-apt-repository ppa:git-core/ppa +sudo apt update +sudo apt install git +``` + +---- + +## Configurer un serveur web + +- [servir avec Apache](apache) diff --git a/docs/deployment/scheduled_tasks.md b/docs/deployment/scheduled_tasks.md new file mode 100644 index 00000000..51eaacfc --- /dev/null +++ b/docs/deployment/scheduled_tasks.md @@ -0,0 +1,34 @@ +# Tâches planifiées + +Le projet repose sur certaines tâches récurrentes : + +* la récupération des offres d'emploi depuis GeoRezo +* le vidage du cache +* la génération des rapports envoyés par mail +* la génération des fichiers GeoJSON pour les cartes interactives +* le renouvellement du certificat SSL par Let's Encrypt + +En production, c'est [cron](https://fr.wikipedia.org/wiki/Cron) qui est utilisé. + +## Paramètres de planification + +Pour éditer les tâches planifiées lancées par cron avec nano : + +```bash +export VISUAL=nano; crontab -e +``` + +Insérer : + +```conf +# El Paso +@hourly cd /var/www/elgeopaso && /var/www/elgeopaso/.venv/bin/python /var/www/elgeopaso/manage.py rss2db +@daily cd /var/www/elgeopaso && /var/www/elgeopaso/.venv/bin/python /var/www/elgeopaso/manage.py clear_cache +30 23 * * 7 cd /var/www/elgeopaso && /var/www/elgeopaso/.venv/bin/python /var/www/elgeopaso/manage.py report +05 00 * * 7 cd /var/www/elgeopaso && /var/www/elgeopaso/.venv/bin/python /var/www/elgeopaso/manage.py map_builder + +# Let's Encrypt +0 2 * * * root /bin/bash /home/geotribu/letsencrypt/scripts/cron.sh > /home/geotribu/log/cron/letsencrypt.log +``` + +Pour la syntaxe, le site [crontab.guru](https://crontab.guru/) est une bonne ressource. diff --git a/docs/development/build.md b/docs/development/build.md new file mode 100644 index 00000000..c50e1db3 --- /dev/null +++ b/docs/development/build.md @@ -0,0 +1,9 @@ +# Build and deploy + +## Build + +> TO DOC + +## Deploy + +> TO DOC diff --git a/docs/development/code.md b/docs/development/code.md new file mode 100644 index 00000000..4cfc792b --- /dev/null +++ b/docs/development/code.md @@ -0,0 +1,43 @@ +# Structure du code + +## Règles + +### Nommage des dossiers et fichiers + +* les sous-dossiers/fichiers précédés par un `.` sont liés au développement + +### Formatage du code + +Le projet s'appuie sur [black](https://github.com/python/black) pour formater automatiquement le code source. Un ensemble de `git hooks` peut également être utilisé afin de formater le code à chaque commit, via [pre-commit](https://pre-commit.com) en installant les _hooks_ configurés dans le fichier `.pre-commit-config.yaml` : + +```python +# installer les hooks +pre-commit install +# les exécuter manuellement +pre-commit run -a +``` + +---- + +## Dossier `.vscode` + +Configuration pour l'éditeur Visual Studio Code : + +* extensions recommandées (`extensions.json`) +* tâches (`tasks.json`) +* paramètres d'environnement de travail sur le projet (tests, etc.) (`settings.json`) +* paramètres de débogage (`launch.json`) + +---- + +## Dossier `tests` + +Tests unitaires et leurs éventuelles [*fixtures*](https://fr.wikipedia.org/wiki/Test_fixture). + +---- + +## Divers + +* `.coveragerc`: configuration pour le calcul de la couverture des tests (_coverage_ / _codecov_) +* `example.env`: modèle de fichier d'environnement +* `setup.cfg` : configuration de l'environnement Python diff --git a/docs/development/documentation.md b/docs/development/documentation.md new file mode 100644 index 00000000..9fb4bc36 --- /dev/null +++ b/docs/development/documentation.md @@ -0,0 +1,9 @@ +# Documentation + +## Générer la documentation + +```powershell +sphinx-build -b html docs docs/_build +``` + +Ouvrir le fichier `docs/_build/index.html` dans un navigateur. diff --git a/docs/development/index.md b/docs/development/index.md new file mode 100644 index 00000000..dc08b31e --- /dev/null +++ b/docs/development/index.md @@ -0,0 +1,173 @@ +# Développement + +## Prérequis + +### OS + +#### Windows + +Version 10 minimum + +* activer le [sous-système Linux (WSL)](https://docs.microsoft.com/fr-fr/windows/wsl/install-win10) : + * installer [Debian](https://www.microsoft.com/store/apps/9MSVKQC78PK6) ou Ubuntu ([16.04](https://www.microsoft.com/store/apps/9pjn388hp8c9) ou [18.04](https://www.microsoft.com/store/apps/9N9TNGVNDL3Q)) + * [initialiser l'instance](https://docs.microsoft.com/fr-fr/windows/wsl/initialize-distro) + * installer les paquest souhaités, par exemple openssl : `sudo apt update && sudo apt upgrade && sudo apt install openssl libssl-dev` +* l'utilisation [du nouveau Terminal](https://www.microsoft.com/fr-fr/p/windows-terminal-preview/9n0dx20hk701?activetab=pivot:overviewtab) est fortement recommandée + +#### Linux + +Distributions compatibles : + +* Debian +* Ubuntu 16.04 ou 18.04 + +### Logiciels + +* Docker (Engine et Compose a minima) +* Python 3.7 64 bits +* PostgreSQL 12 + +---- + +## Lancer en local + +> Commandes lancées sous Windows 10 avec WSL activé. + +### Installation + +```powershell +# create virtual env +# on Linux: python3.7 -m venv .venv +py -3.7 -m venv .venv + +# enter into +.\.venv\Scripts\activate +# on Linux: source .venv/bin/activate + +# upgrade install tooling +python -m pip install --upgrade pip + +# install requirements +python -m pip install -U -r .\requirements\local.txt +# on Linux: python -m pip install -U -r requirements/local.txt + +# download NLTK packages - please refer to `ntlk.txt` +python -m nltk.downloader punkt stopwords + +# optionally, install pre-commit git-hooks +pre-commit install +``` + +### Configuration + +Renommer le fichier `example.env` en `.env` et le compléter. Pour info, il est possible de générer une clé Django Secret en passant par OpenSSL sur WSl : `wsl -- openssl rand -base64 64` (copier/coller dans le fichier `.env`). + +### Base de données + +Initialiser la base de données : + +```powershell +# apply migrations to database +python manage.py migrate + +# create the super user +python manage.py createsuperuser +``` + +Pour charger des enregistrements de base (technologies, métiers, types de contrats, etc.), utiliser `loaddata` : + +* voir les commandes dans le fichier de déploiement : `.deploy/release-tasks.sh` +* voir ["Restaurer les données"](backup#restaurer-1) + +### Lancer + +```powershell +# launch development web server +python .\manage.py runserver +# on Linux: python manage.py runserver + +# alternatively, use the enhanced command from django-extensions +python .\manage.py runserver_plus +``` + +Ouvrir le navigateur à l'adresse indiquée dans le terminal. Par défaut : . + +#### Avec HTTPS + +Pour développer au mieux, il est préférable de servir l'application en HTTPS. C'est possible via `runserver_plus` de Django Extensions ([voir la documentation](https://django-extensions.readthedocs.io/en/latest/runserver_plus.html#ssl)). + +```powershell +# create folder where to store certificate and key +mkdir certs +# generate SSL certificate and key +wsl -- openssl req -nodes -new -x509 -days 365 -keyout certs/serverKey.key -out certs/serverCert.cert +# on Linux: remove 'wsl -- ' + +# alternatively, use the enhanced command from django-extensions +python .\manage.py runserver_plus --cert-file .\certs\serverCert.cert --key-file .\certs\serverKey.key +``` + +Ouvrir le navigateur à l'adresse indiquée dans le terminal. Par défaut : . Accepter [le risque lié aux certificats auto-signés](https://support.mozilla.org/fr/kb/comment-regler-codes-erreur-securite-sur-sites-securises?as=u&utm_source=inproduct#w_certificats-auto-signaes). + +---- + +## Docker + +### Prérequis Docker + +* Docker 2.2+ ou dans le détail : + * Docker Engine : 19.03+ + * Docker Compose 1.25+ + +### Configuration Docker + +Renommer fichier `example.env` en `docker.env` et compléter : + +```ini +# DEVELOPMENT +DJANGO_DEBUG=1 +USE_DOCKER=1 + +# GLOBAL +DJANGO_ADMIN_URL="admin" +DJANGO_PROJECT_FOLDER="elgeopaso" +DJANGO_SECURE_SSL_REDIRECT=0 +DJANGO_SETTINGS_MODULE="elgeopaso.settings.production" +WEB_CONCURRENCY=4 + +# SECURITY +DJANGO_SECRET_KEY="change_me_with_generated_key" +DJANGO_ALLOWED_HOSTS="localhost, 0.0.0.0, 127.0.0.1" + +# EMAIL +REPORT_RECIPIENTS="elpaso@georezo.net," +SMTP_USER="elpaso@georezo.net" +SMTP_PSWD= + +# PostgreSQL +# ------------------------------------------------------------------------------ +POSTGRES_HOST=database +POSTGRES_PORT=5432 +POSTGRES_DB=elgeopaso-dev +POSTGRES_USER=elgeopaso +POSTGRES_PASSWORD=elgeopaso +DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}" +``` + +### Usage + +#### Lancer l'application + +```shell +docker-compose -f docker-compose.dev.yml up -d +``` + +Ouvrir le navigateur sur . + +#### Données et analyses de base + +Après que l'application soit lancée : + +```shell +docker-compose -f docker-compose.dev.yml run --rm webapp sh .deploy/release-tasks.sh +``` diff --git a/docs/development/settings.md b/docs/development/settings.md new file mode 100644 index 00000000..f199e66a --- /dev/null +++ b/docs/development/settings.md @@ -0,0 +1,11 @@ +# Configuration + +L'application tente de respecter les [12-Factor et notamment la partie concernant la configuration](https://www.12factor.net/config). L'essentiel de la configuration se fait donc à l'aide de variables d'environnement. + +## Structure de la configuration + +> TO DO + +## Fichier de configuration + +Fichier `.env`. diff --git a/docs/development/tests.md b/docs/development/tests.md new file mode 100644 index 00000000..892a06e8 --- /dev/null +++ b/docs/development/tests.md @@ -0,0 +1,3 @@ +# Tests + +> TO DOC diff --git a/docs/global/history.md b/docs/global/history.md new file mode 100644 index 00000000..3d232ed8 --- /dev/null +++ b/docs/global/history.md @@ -0,0 +1,13 @@ +# Histoire du Projet + +## Auteurs + +L'idée initiale est celle de [Pierre Vernier](https://github.com/pvernier) et de [Julien Moura](https://github.com/Guts), portés que nous étions par la regrettée dynamique de [Geotribu](http://geotribu.net) ! + +Les bénévoles de GeoRezo ont aussi contribué à relancer la dynamique lorsqu'elle s'éteignait, que ce soit [Yves Jacolin](https://github.com/yjacolin) pour les aspects techniques, [Marc Isenmann](https://www.linkedin.com/in/marc-isenmann-9b764b109/) pour son intérêt jamais démenti pour l'analyse des offres qu'il modère depuis tant d'années et Bruno Iratchet pour son soutien ponctuel mais non moins fidèle. + +## Pourquoi El Paso + +Pourquoi El Paso ? Depuis des temps immémoriaux, le choix d'un nom de projet informatique est cornélien (le mot est sûrement trop faible). Né autour de fajitas et de rhum, le nom El Paso s'est imposé comme une évidence. Bien traduit, il représente le petit pas qui sépare un chercheur d'emploi d'un poste. Une simple offre, un simple pas... non, en fait, rien de tout cela, c'est juste parce-que les fajitas étaient bonnes ! + +![Logo - Old El Paso](https://upload.wikimedia.org/wikipedia/en/2/27/Logo_for_Old_El_Paso,_Oct_2014.png "Fajitas + rhum = El Géo Paso") diff --git a/docs/global/index.md b/docs/global/index.md new file mode 100644 index 00000000..369f17e4 --- /dev/null +++ b/docs/global/index.md @@ -0,0 +1,49 @@ +# Introduction + +Documentation technique du projet El Géo Paso, statistiques dynamiques sur les offres d'emploi en géomatique publiées sur le forum francophone de géomatique [GeoRezo](https://georezo.net/forum/viewforum.php?id=10). + +Base de connaissances techniques sur le projet El Géo Paso. Cette base, enrichie au gré du temps disponible et de l'envie (autant dire qu'elle est incomplète), a vocation à éviter que le projet ne soit une boîte noire et à faciliter les phases de reprise du développement, celui-ci étant discontinu et irrégulier (bénévolat mon amour). + +## Description fonctionnelle + +### Récupération à partir de GeoRezo + +1. Toutes les heures, les dernières offres publiées sont récupérées à partir du [flux RSS du forum Job de GeoRezo](https://georezo.net/extern.php?fid=10) et stockées en brut dans une table dédiée ; +2. Chaque nouvelle offre est analysée en s'appuyant sur le kit de traitement du langage naturel NLTK et des correspondances personnalisables en base de données via l'interface d'administration ; + +### Représentation des données + +Les données sont ensuite représentées dans différents modes : + +* métriques globales ; +* valeurs absolues du nombre d'offre par période ; +* valeurs proportionnelles selon le différents critères (types de contrats...) + +---- + +## Description technique + +Pour dupliquer le projet, la documentation est dans [le wiki du dépôt](https://github.com/Guts/elgeopaso/wiki). + +### Base de données + +!["El Géo Paso - Modèle graphique de la base de données"](docs/elpaso_db_models_graph.png "El Geo Paso - DB") + + *Modèle généré automatiquement par Django Extensions graph-models (pydot)* + +### Briques logicielles + +Le projet est développé en Python 3.5.x avec le framework Django et des extensions : + +* [feedparser](https://pypi.org/project/feedparser/) pour la consommation du flux RSS +* [NLTK](http://www.nltk.org/) pour l'analyse sémantique +* [DRF (Django REST Framework)](http://www.django-rest-framework.org/) et [drf-yasg](https://github.com/axnsan12/drf-yasg/) pour la mise en place de l'API REST et sa documentation automatisée +* [Django Extensions](https://github.com/django-extensions/django-extensions) pour la boîte à outils de dév Django + +Du côté de l'interface du site web, on retrouve les classiques : + +* [Bootstrap](https://getbootstrap.com/) +* [D3.js](https://d3js.org/), via la surcouche [NVD3](http://nvd3.org) +* [Django Suit](https://djangosuit.com/) pour l'habillage de l'interface d'administration + +Le site est servi sur le Web par [gunicorn](https://gunicorn.org/) et nginx ou Apache selon les plateformes (dév ou production). diff --git a/docs/global/product_life.md b/docs/global/product_life.md new file mode 100644 index 00000000..c6a0b1a5 --- /dev/null +++ b/docs/global/product_life.md @@ -0,0 +1,16 @@ +# Gestion du projet + +## Nommage des versions + +Le projet respecte SemVer, pour *Semantic Versioning*. + +Consulter : + +- le [manifeste officiel de SemVer](https://semver.org/lang/fr/) +- le [paragraphe Wikipédia](https://en.wikipedia.org/wiki/Software_versioning#Change_significance) dédié à cette convention de nommage + +Exemples : + +```txt +1.0.0 +``` diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..14053f75 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,73 @@ +.. El Géo Paso documentation master file, created by + sphinx-quickstart on Sun May 3 23:02:56 2020. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +El Géo Paso - Documentation +=========================== + +.. |date| date:: + +:Author: |author| +:Source code: |repo_url| +:Package version: |version| +:Documentation update: |date| + +Raccourcis +++++++++++ + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. toctree:: + :maxdepth: 2 + :caption: Global + + global/index + global/history + global/product_life + +.. toctree:: + :maxdepth: 1 + :caption: Développement + + development/index + development/code + development/documentation + development/build + development/settings + development/tests + +.. toctree:: + :maxdepth: 1 + :caption: Déployer + + deployment/preproduction + deployment/production + deployment/git_flow + deployment/apache + deployment/scheduled_tasks + +.. toctree:: + :maxdepth: 1 + :caption: Base de données + + database/index + database/backup + +.. toctree:: + :maxdepth: 1 + :caption: Autres + + misc/miscellaneous + misc/resources + + +---- + +.. toctree:: + :maxdepth: 3 + :caption: Code source + + _apidoc/modules diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..922152e9 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/misc/miscellaneous.md b/docs/misc/miscellaneous.md new file mode 100644 index 00000000..77a9091b --- /dev/null +++ b/docs/misc/miscellaneous.md @@ -0,0 +1,56 @@ +# Utilitaires et divers + +## Etiqueter un commit pour publier une version + +Commande exemple dans un terminal *git*, où `XXXXXX` est la signature (hash) du commit : + +```git +git tag -a 1.5.0 XXXXXXX -m "Mars 2020" +git push origin 1.5.0 +``` + +En cas d'erreur, il est possible de renommer une étiquette : + +```git +git tag new old +git tag -d old +git push origin :refs/tags/old +git push --tags +``` + +---- + +## Générer le modèle graphique de la base de données + +[Graph models, inclus dans la boîte à outils Django Extensions](http://django-extensions.readthedocs.io/en/latest/graph_models.html), permet de générer un graphique récapitulatif de la base de données : + +![DB Model Graph](https://raw.githubusercontent.com/Guts/elpaso/master/docs/elpaso_db_models_graph.png) + +### Dépendances + +Il s'appuie sur l'une des 2 bibliohtèques : + +* pydot - celle que nous utilisons, car bien plus légère +* pygraphviz + +```bash +sudo apt install pkg-config python-pydot graphviz graphviz-dev +``` + +Puis, dans l'environnement virtuel du projet : + +```bash +source ./virtenv/bin/activate +pip install pydot +``` + +> Note : il peut être nécessaire d'installer une version spécifique de pyparsing, une dépendance de pydot : +> `pip install pyparsing==1.5.7` + +### Génération + +Dans l'environnement virtuel du projet : + +```bash +python manage.py graph_models --pydot -a -g -o docs/elpaso_db_models_graph.png +``` diff --git a/docs/misc/resources.md b/docs/misc/resources.md new file mode 100644 index 00000000..46223036 --- /dev/null +++ b/docs/misc/resources.md @@ -0,0 +1,33 @@ +# Ressources + +## Python + +- [Alléger les GeoJSON](http://makina-corpus.com/blog/metier/2014/reduire-le-poids-dun-geojson) + +## Django + +- +- [Écriture de tests dans Django](https://docs.djangoproject.com/fr/2.2/topics/testing/overview/) +- [Articulation entre PyTest, Coverage et le lanceur de tests intégrés à Django ](https://adamj.eu/tech/2019/04/30/getting-a-django-application-to-100-percent-coverage/) + +---- + +## Déploiement + +### Heroku + +- [`app.json` et déploiement automatique](https://devcenter.heroku.com/articles/heroku-butto) + +### Serveur + +- [Django with Postgres, Nginx, and Gunicorn on Debian 8](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-debian-8#create-a-gunicorn-systemd-service-file) + +#### Git flow + +- [Deploy to remote server with Git](https://medium.com/@francoisromain/vps-deploy-with-git-fea605f1303b) + +#### Nginx + +- +- +- diff --git a/elgeopaso/__about__.py b/elgeopaso/__about__.py index e4b81c96..acba8f51 100644 --- a/elgeopaso/__about__.py +++ b/elgeopaso/__about__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- #! python3 # noqa: E265 # noqa: E265 """ @@ -20,7 +19,7 @@ ] -__author__ = "Julien M. (guts@github)" +__author__ = "Julien M. (guts@github, geojulien@twitter)" __copyright__ = "2018 - {0}, {1}".format(date.today().year, __author__) __email__ = "elpaso@georezo.net" __license__ = "GNU Lesser General Public License v3.0" diff --git a/elgeopaso/fixtures/sites.json b/elgeopaso/fixtures/sites.json new file mode 100644 index 00000000..3423a129 --- /dev/null +++ b/elgeopaso/fixtures/sites.json @@ -0,0 +1 @@ +[{"model": "sites.site", "pk": 1, "fields": {"domain": "elgeopaso.georezo.net", "name": "El G\u00e9o Paso (GeoRezo)"}}] diff --git a/requirements/base.txt b/requirements/base.txt index 2a1fc97c..a82aa669 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -9,27 +9,27 @@ wheel # Django # ----------------------- django==2.2.* # pyup: < 3.0 -django-allauth==0.41.* # https://django-allauth.readthedocs.io +django-allauth==0.42.* # https://django-allauth.readthedocs.io django-crispy-forms==1.9.* # https://django-crispy-forms.readthedocs.io django-ckeditor==5.9.* -django-filter==2.2.* +django-filter==2.3.* django-widgets-improved==1.5.* -whitenoise[brotli]==5.0.* # https://github.com/evansd/whitenoise +whitenoise[brotli]==5.1.* # https://github.com/evansd/whitenoise # Django REST Framework (DRF) # -------------------------- djangorestframework==3.11.* djangorestframework-filters==1.0.* -drf-yasg[validation]==1.17.* +drf-yasg[validation]==1.20.* # Utils # -------------------------- -argon2-cffi==19.2.0 # https://github.com/hynek/argon2_cffi +argon2-cffi==20.1.0 # https://github.com/hynek/argon2_cffi arrow==0.12.* -beautifulsoup4==4.8.* +beautifulsoup4==4.9.* lxml==4.5.* -Pillow==7.1.* # https://github.com/python-pillow/Pillow -python-dotenv==0.13.* # https://saurabh-kumar.com/python-dotenv/#django +Pillow==7.2.* # https://github.com/python-pillow/Pillow +python-dotenv==0.14.* # https://saurabh-kumar.com/python-dotenv/#django pytz==2020.1 # https://github.com/stub42/pytz # Database diff --git a/requirements/local.txt b/requirements/local.txt index 0e2e1b71..4111cf26 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -11,28 +11,30 @@ Werkzeug==1.0.* # https://github.com/pallets/werkzeug # Documentation # ----------------------- -recommonmark==0.6.* -Sphinx==2.4.* # https://github.com/sphinx-doc/sphinx -sphinx-markdown-tables==0.0.12 # to render markdown tables -sphinx-rtd-theme==0.4.* +recommonmark>=0.6,<0.8 +Sphinx>=3.1,<3.5 # https://github.com/sphinx-doc/sphinx +sphinx-autodoc-typehints==1.11.* +sphinx-copybutton==0.3.* +sphinx-markdown-tables==0.0.15 # to render markdown tables +sphinx-rtd-theme==0.5.* # Testing # ---------------------- -pytest==5.3.* # https://github.com/pytest-dev/pytest -pytest-cov==2.8.* -pytest-django==3.8.* # https://github.com/pytest-dev/pytest-django -semver==2.9.* # https://github.com/python-semver/python-semver -validator-collection== 1.4.* # https://github.com/insightindustry/validator-collection +pytest>=6.2,<6.3 # https://github.com/pytest-dev/pytest +pytest-cov>=2.10,<2.11 +pytest-django>=4.1,<4.2 # https://github.com/pytest-dev/pytest-django +semver>=2.13,<2.14 # https://github.com/python-semver/python-semver +validator-collection== 1.5.* # https://github.com/insightindustry/validator-collection # Code quality # ---------------------- -black==19.10b0 # https://github.com/ambv/black +black==20.8b1 # https://github.com/ambv/black django-coverage-plugin==1.8.* # https://github.com/nedbat/django_coverage_plugin -flake8==3.7.* # https://github.com/PyCQA/flake8 -pre-commit==2.3.* # https://github.com/pre-commit/pre-commit -pylint-django==2.0.* # https://github.com/PyCQA/pylint-django +flake8>=3.8,<3.9 # https://github.com/PyCQA/flake8 +pre-commit>=2.9,<2.10 # https://github.com/pre-commit/pre-commit +pylint-django==2.3.* # https://github.com/PyCQA/pylint-django # Django # ------------------------------------------------------------------------------ -django-debug-toolbar==2.2.* # https://github.com/jazzband/django-debug-toolbar +django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar django-extensions==2.2.* # https://github.com/django-extensions/django-extensions