diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..b37fb7ae --- /dev/null +++ b/.env.example @@ -0,0 +1,82 @@ +HTTPS=off +DEBUG=true + +# This is not the real key used in prod +SECRET_KEY=(4sjxvhz@m5$0a$j0_pqicnc$s!vbve)z+&++m%g%bjhlz4+g2 + +DATABASE_URL=sqlite:///db.sqlite3 +# uncomment the next line if you want to use a postgres database +#DATABASE_URL=postgres://user:password@127.0.0.1:5432/sith +CACHE_URL=redis://127.0.0.1:6379/0 + +MEDIA_ROOT=data +STATIC_ROOT=static + +DEFAULT_FROM_EMAIL=bibou@git.an +SITH_COM_EMAIL=bibou_com@git.an + +HONEYPOT_VALUE=content +HONEYPOT_FIELD_NAME=body2 +HONEYPOT_FIELD_NAME_FORUM=message2 + +EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend +EMAIL_HOST=localhost +EMAIL_PORT=25 + +SITH_URL=127.0.0.1:8000 +SITH_NAME="AE UTBM" + +SITH_MAIN_CLUB_ID=1 + +SITH_GROUP_ROOT_ID=1 +SITH_GROUP_PUBLIC_ID=2 +SITH_GROUP_SUBSCRIBERS_ID=3 +SITH_GROUP_OLD_SUBSCRIBERS_ID=4 +SITH_GROUP_ACCOUNTING_ADMIN_ID=5 +SITH_GROUP_COM_ADMIN_ID=6 +SITH_GROUP_COUNTER_ADMIN_ID=7 +SITH_GROUP_BANNED_ALCOHOL_ID=8 +SITH_GROUP_BANNED_COUNTER_ID=9 +SITH_GROUP_BANNED_SUBSCRIPTION_ID=10 +SITH_GROUP_SAS_ADMIN_ID=11 +SITH_GROUP_FORUM_ADMIN_ID=12 +SITH_GROUP_PEDAGOGY_ADMIN_ID=13 + +SITH_CLUB_REFOUND_ID=89 +SITH_COUNTER_REFOUND_ID=38 +SITH_PRODUCT_REFOUND_ID=5 + +# Counter + +SITH_COUNTER_ACCOUNT_DUMP_ID=39 + +# Defines which product type is the refilling type, and thus increases the account amount +SITH_COUNTER_PRODUCTTYPE_REFILLING=3 + +SITH_ECOCUP_CONS=1152 +SITH_ECOCUP_DECO=1151 + +# Defines which product is the one year subscription and which one is the six month subscription +SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER=1 +SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS=2 +SITH_PRODUCTTYPE_SUBSCRIPTION=2 + +# Defines which clubs let its members the ability to see users subscription history +SITH_CAN_CREATE_SUBSCRIPTION_HISTORY=1 +SITH_CAN_READ_SUBSCRIPTION_HISTORY=1 + +# SAS variables +SITH_SAS_ROOT_DIR_ID=4 + +# ET variables +SITH_EBOUTIC_CB_ENABLED=true +SITH_EBOUTIC_ET_URL="https://preprod-tpeweb.e-transactions.fr/cgi/MYchoix_pagepaiement.cgi" +SITH_EBOUTIC_PBX_SITE=1999888 +SITH_EBOUTIC_PBX_RANG=32 +SITH_EBOUTIC_PBX_IDENTIFIANT=2 +SITH_EBOUTIC_HMAC_KEY=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +SITH_EBOUTIC_PUB_KEY_PATH=sith/et_keys/pubkey.pem + +SITH_MAILING_FETCH_KEY=IloveMails +SENTRY_DSN= +SENTRY_ENV=production \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b08cdcf5..bd82d805 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: branches: [master, taiste] workflow_dispatch: +env: + SECRET_KEY: notTheRealOne + DATABASE_URL: sqlite:///db.sqlite3 + jobs: pre-commit: name: Launch pre-commits checks (ruff) diff --git a/.gitignore b/.gitignore index 264833db..c6dc865a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ node_modules/ # compiled documentation site/ +.env diff --git a/docs/howto/prod.md b/docs/howto/prod.md index 769f681f..472f8c3e 100644 --- a/docs/howto/prod.md +++ b/docs/howto/prod.md @@ -2,13 +2,13 @@ Pour connecter l'application à une instance de sentry (ex: https://sentry.io), il est nécessaire de configurer la variable `SENTRY_DSN` -dans le fichier `settings_custom.py`. +dans le fichier `.env`. Cette variable est composée d'un lien complet vers votre projet sentry. ## Récupérer les statiques Nous utilisons du SCSS dans le projet. -En environnement de développement (`DEBUG=True`), +En environnement de développement (`DEBUG=true`), le SCSS est compilé à chaque fois que le fichier est demandé. Pour la production, le projet considère que chacun des fichiers est déjà compilé. diff --git a/docs/tutorial/install-advanced.md b/docs/tutorial/install-advanced.md index 0c156f4f..d6a30cfb 100644 --- a/docs/tutorial/install-advanced.md +++ b/docs/tutorial/install-advanced.md @@ -47,19 +47,19 @@ Commencez par installer les dépendances système : === "Debian/Ubuntu" ```bash - sudo apt install postgresql redis libq-dev nginx + sudo apt install postgresql libq-dev nginx ``` === "Arch Linux" ```bash - sudo pacman -S postgresql redis nginx + sudo pacman -S postgresql nginx ``` === "macOS" ```bash - brew install postgresql redis lipbq nginx + brew install postgresql lipbq nginx export PATH="/usr/local/opt/libpq/bin:$PATH" source ~/.zshrc ``` @@ -77,34 +77,6 @@ poetry install --with prod C'est parce que ces dépendances compilent certains modules à l'installation. -## Configurer Redis - -Redis est utilisé comme cache. -Assurez-vous qu'il tourne : - -```bash -sudo systemctl redis status -``` - -Et s'il ne tourne pas, démarrez-le : - -```bash -sudo systemctl start redis -sudo systemctl enable redis # si vous voulez que redis démarre automatiquement au boot -``` - -Puis ajoutez le code suivant à la fin de votre fichier -`settings_custom.py` : - -```python -CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.redis.RedisCache", - "LOCATION": "redis://127.0.0.1:6379", - } -} -``` - ## Configurer PostgreSQL PostgreSQL est utilisé comme base de données. @@ -139,26 +111,19 @@ en étant connecté en tant que postgres : psql -d sith -c "GRANT ALL PRIVILEGES ON SCHEMA public to sith"; ``` -Puis ajoutez le code suivant à la fin de votre -`settings_custom.py` : +Puis modifiez votre `.env`. +Dedans, décommentez l'url de la base de données +de postgres et commentez l'url de sqlite : -```python -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": "sith", - "USER": "sith", - "PASSWORD": "password", - "HOST": "localhost", - "PORT": "", # laissez ce champ vide pour que le choix du port soit automatique - } -} +```dotenv +#DATABASE_URL=sqlite:///db.sqlite3 +DATABASE_URL=postgres://sith:password@localhost:5432/sith ``` Enfin, créez vos données : ```bash -poetry run ./manage.py populate +poetry run ./manage.py setup ``` !!! note @@ -247,7 +212,7 @@ Puis lancez ou relancez nginx : sudo systemctl restart nginx ``` -Dans votre `settings_custom.py`, remplacez `DEBUG=True` par `DEBUG=False`. +Dans votre `.env`, remplacez `DEBUG=true` par `DEBUG=false`. Enfin, démarrez le serveur Django : diff --git a/docs/tutorial/install.md b/docs/tutorial/install.md index c3b0756e..4fea58f1 100644 --- a/docs/tutorial/install.md +++ b/docs/tutorial/install.md @@ -8,6 +8,7 @@ Certaines dépendances sont nécessaires niveau système : - zlib1g-dev - python - gettext +- redis ### Installer WSL @@ -79,7 +80,7 @@ cd /mnt//vos/fichiers/comme/dhab ```bash sudo apt install build-essential libssl-dev libjpeg-dev zlib1g-dev python-dev npm \ libffi-dev python-dev-is-python3 pkg-config \ - gettext git pipx + gettext git pipx redis pipx install poetry ``` @@ -91,7 +92,7 @@ cd /mnt//vos/fichiers/comme/dhab sudo pacman -S python - sudo pacman -S gcc git gettext pkgconf python-poetry npm + sudo pacman -S gcc git gettext pkgconf python-poetry redis npm ``` === "macOS" @@ -100,7 +101,7 @@ cd /mnt//vos/fichiers/comme/dhab Il est également nécessaire d'avoir installé xcode ```bash - brew install git python pipx npm + brew install git python pipx redis npm pipx install poetry # Pour bien configurer gettext @@ -112,6 +113,15 @@ cd /mnt//vos/fichiers/comme/dhab Si vous rencontrez des erreurs lors de votre configuration, n'hésitez pas à vérifier l'état de votre installation homebrew avec :code:`brew doctor` +Parmi les dépendances installées se trouve redis (que nous utilisons comme cache). +Redis est un service qui doit être activé pour être utilisé. +Pour cela, effectuez les commandes : + +```bash +sudo systemctl start redis +sudo systemctl enable redis # si vous voulez que redis démarre automatiquement au boot +``` + ## Finaliser l'installation Clonez le projet (depuis votre console WSL, si vous utilisez WSL) @@ -133,20 +143,24 @@ poetry run ./manage.py install_xapian de texte à l'écran. C'est normal, il ne faut pas avoir peur. -Maintenant que les dépendances sont installées, nous -allons créer la base de données, la remplir avec des données de test, -et compiler les traductions. -Cependant, avant de faire cela, il est nécessaire de modifier -la configuration pour signifier que nous sommes en mode développement. -Pour cela, nous allons créer un fichier `sith/settings_custom.py` -et l'utiliser pour surcharger les settings de base. +Une fois les dépendances installées, il faut encore +mettre en place quelques éléments de configuration, +qui peuvent varier d'un environnement à l'autre. +Ces variables sont stockées dans un fichier `.env`. +Pour le créer, vous pouvez copier le fichier `.env.example` : ```bash -echo "DEBUG=True" > sith/settings_custom.py -echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py +cp .env.example .env ``` -Enfin, nous pouvons lancer les commandes suivantes : +Les variables par défaut contenues dans le fichier `.env` +devraient convenir pour le développement, sans modification. + +Maintenant que les dépendances sont installées +et la configuration remplie, nous allons pouvoir générer +des données utiles pendant le développement. + +Pour cela, lancez les commandes suivantes : ```bash # Activation de l'environnement virtuel @@ -187,6 +201,30 @@ python manage.py runserver [http://localhost:8000/api/docs](http://localhost:8000/api/docs), une interface swagger, avec toutes les routes de l'API. +!!! question "Pourquoi l'installation est aussi complexe ?" + + Cette question nous a été posée de nombreuses fois par des personnes + essayant d'installer le projet. + Il y a en effet un certain nombre d'étapes à suivre, + de paquets à installer et de commandes à exécuter. + + Le processus d'installation peut donc sembler complexe. + + En réalité, il est difficile de faire plus simple. + En effet, un site web a besoin de beaucoup de composants + pour être développé : il lui faut au minimum + une base de données, un cache, un bundler Javascript + et un interpréteur pour le code du serveur. + Pour nos besoin particuliers, nous utilisons également + un moteur de recherche full-text. + + Nous avons tenté au maximum de limiter le nombre de dépendances + et de sélecionner les plus simples à installer. + Cependant, il est impossible de retirer l'intégralité + de la complexité du processus. + Si vous rencontrez des difficulté lors de l'installation, + n'hésitez pas à demander de l'aide. + ## Générer la documentation La documentation est automatiquement mise en ligne à chaque envoi de code sur GitHub. diff --git a/docs/tutorial/structure.md b/docs/tutorial/structure.md index efc03c2d..5b15f4fc 100644 --- a/docs/tutorial/structure.md +++ b/docs/tutorial/structure.md @@ -72,11 +72,12 @@ sith/ ├── .gitattributes ├── .gitignore ├── .mailmap -├── .env.exemple -├── manage.py (26) -├── mkdocs.yml (27) +├── .env (26) +├── .env.example (27) +├── manage.py (28) +├── mkdocs.yml (29) ├── poetry.lock -├── pyproject.toml (28) +├── pyproject.toml (30) └── README.md ``` @@ -120,12 +121,16 @@ sith/ de manière transparente pour l'utilisateur. 24. Fichier de configuration de coverage. 25. Fichier de configuration de direnv. -26. Fichier généré automatiquement par Django. C'est lui +26. Contient les variables d'environnement, qui sont susceptibles + de varier d'une machine à l'autre. +27. Contient des valeurs par défaut pour le `.env` + pouvant convenir à un environnment de développement local +28. Fichier généré automatiquement par Django. C'est lui qui permet d'appeler des commandes de gestion du projet avec la syntaxe `python ./manage.py ` -27. Le fichier de configuration de la documentation, +29. Le fichier de configuration de la documentation, avec ses plugins et sa table des matières. -28. Le fichier où sont déclarés les dépendances et la configuration +30. Le fichier où sont déclarés les dépendances et la configuration de certaines d'entre elles. @@ -141,10 +146,9 @@ Il est organisé comme suit : ``` sith/ ├── settings.py (1) -├── settings_custom.py (2) -├── toolbar_debug.py (3) -├── urls.py (4) -└── wsgi.py (5) +├── toolbar_debug.py (2) +├── urls.py (3) +└── wsgi.py (4) ``` @@ -152,13 +156,10 @@ sith/ Ce fichier contient les paramètres de configuration du projet. Par exemple, il contient la liste des applications installées dans le projet. -2. Configuration maison pour votre environnement. - Toute variable que vous définissez dans ce fichier sera prioritaire - sur la configuration donnée dans `settings.py`. -3. Configuration de la barre de debug. +2. Configuration de la barre de debug. C'est inutilisé en prod, mais c'est très pratique en développement. -4. Fichier de configuration des urls du projet. -5. Fichier de configuration pour le serveur WSGI. +3. Fichier de configuration des urls du projet. +4. Fichier de configuration pour le serveur WSGI. WSGI est un protocole de communication entre le serveur et les applications. Ce fichier ne vous servira sans doute pas sur un environnement diff --git a/poetry.lock b/poetry.lock index 311df18a..2503cc32 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "alabaster" @@ -425,6 +425,7 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -435,6 +436,7 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -497,6 +499,32 @@ files = [ {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] +[[package]] +name = "dj-database-url" +version = "2.3.0" +description = "Use Database URLs in your Django Application." +optional = false +python-versions = "*" +files = [ + {file = "dj_database_url-2.3.0-py3-none-any.whl", hash = "sha256:bb0d414ba0ac5cd62773ec7f86f8cc378a9dbb00a80884c2fc08cc570452521e"}, + {file = "dj_database_url-2.3.0.tar.gz", hash = "sha256:ae52e8e634186b57e5a45e445da5dc407a819c2ceed8a53d1fac004cc5288787"}, +] + +[package.dependencies] +Django = ">=4.2" +typing_extensions = ">=3.10.0.0" + +[[package]] +name = "dj-email-url" +version = "1.0.6" +description = "Use an URL to configure email backend settings in your Django Application." +optional = false +python-versions = "*" +files = [ + {file = "dj-email-url-1.0.6.tar.gz", hash = "sha256:55ffe3329e48f54f8a75aa36ece08f365e09d61f8a209773ef09a1d4760e699a"}, + {file = "dj_email_url-1.0.6-py2.py3-none-any.whl", hash = "sha256:cbd08327fbb08b104eac160fb4703f375532e4c0243eb230f5b960daee7a96db"}, +] + [[package]] name = "django" version = "4.2.17" @@ -517,6 +545,17 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""} argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] +[[package]] +name = "django-cache-url" +version = "3.4.5" +description = "Use Cache URLs in your Django application." +optional = false +python-versions = "*" +files = [ + {file = "django-cache-url-3.4.5.tar.gz", hash = "sha256:eb9fb194717524348c95cad9905b70b647452741c1d9e481fac6d2125f0ad917"}, + {file = "django_cache_url-3.4.5-py2.py3-none-any.whl", hash = "sha256:5f350759978483ab85dc0e3e17b3d53eed3394a28148f6bf0f53d11d0feb5b3c"}, +] + [[package]] name = "django-countries" version = "7.6.1" @@ -723,6 +762,29 @@ files = [ {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, ] +[[package]] +name = "environs" +version = "11.2.1" +description = "simplified environment variable parsing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "environs-11.2.1-py3-none-any.whl", hash = "sha256:9d2080cf25807a26fc0d4301e2d7b62c64fbf547540f21e3a30cc02bc5fbe948"}, + {file = "environs-11.2.1.tar.gz", hash = "sha256:e068ae3174cef52ba4b95ead22e639056a02465f616e62323e04ae08e86a75a4"}, +] + +[package.dependencies] +dj-database-url = {version = "*", optional = true, markers = "extra == \"django\""} +dj-email-url = {version = "*", optional = true, markers = "extra == \"django\""} +django-cache-url = {version = "*", optional = true, markers = "extra == \"django\""} +marshmallow = ">=3.13.0" +python-dotenv = "*" + +[package.extras] +dev = ["environs[tests]", "pre-commit (>=3.5,<5.0)", "tox"] +django = ["dj-database-url", "dj-email-url", "django-cache-url"] +tests = ["environs[django]", "pytest"] + [[package]] name = "executing" version = "2.1.0" @@ -1167,6 +1229,25 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +[[package]] +name = "marshmallow" +version = "3.23.2" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.9" +files = [ + {file = "marshmallow-3.23.2-py3-none-any.whl", hash = "sha256:bcaf2d6fd74fb1459f8450e85d994997ad3e70036452cbfa4ab685acb19479b3"}, + {file = "marshmallow-3.23.2.tar.gz", hash = "sha256:c448ac6455ca4d794773f00bae22c2f351d62d739929f761dce5eacb5c468d7f"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.14)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"] +tests = ["pytest", "simplejson"] + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -1953,6 +2034,20 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "python-dotenv" +version = "1.0.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pyyaml" version = "6.0.2" @@ -2724,4 +2819,4 @@ filelock = ">=3.4" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "5836c1a8ad42645d7d045194c8c371754b19957ebdcd2aaa902a2fb3dc97cc53" +content-hash = "2274007f3b99bb7187c4d0176f877399c68de76813717fa584811e257e14d463" diff --git a/pyproject.toml b/pyproject.toml index be892cdf..1c634b79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,8 @@ Sphinx = "^5" # Needed for building xapian tomli = "^2.2.1" django-honeypot = "^1.2.1" pydantic-extra-types = "^2.10.1" +environs = {extras = ["django"], version = "^11.2.1"} +redis = {extras = ["hiredis"], version = "^5.2.0"} [tool.poetry.group.prod.dependencies] # deps used in prod, but unnecessary for development @@ -52,7 +54,6 @@ pydantic-extra-types = "^2.10.1" # The C extra triggers compilation against system libs during install. # Removing it would switch psycopg to a slower full-python implementation psycopg = {extras = ["c"], version = "^3.2.3"} -redis = {extras = ["hiredis"], version = "^5.2.0"} [tool.poetry.group.prod] optional = true diff --git a/sith/settings.py b/sith/settings.py index 5fdc3786..08a95a04 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -34,7 +34,6 @@ https://docs.djangoproject.com/en/1.8/ref/settings/ """ import binascii -import logging import os import sys from datetime import timedelta @@ -43,25 +42,32 @@ from pathlib import Path import sentry_sdk from dateutil.relativedelta import relativedelta from django.utils.translation import gettext_lazy as _ +from environs import Env from sentry_sdk.integrations.django import DjangoIntegration from .honeypot import custom_honeypot_error -BASE_DIR = Path(__file__).parent.parent.resolve() +env = Env() +env.read_env() -os.environ["HTTPS"] = "off" +BASE_DIR = Path(__file__).parent.parent.resolve() # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "(4sjxvhz@m5$0a$j0_pqicnc$s!vbve)z+&++m%g%bjhlz4+g2" +SECRET_KEY = env.str("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = env.bool("DEBUG", default=False) TESTING = "pytest" in sys.modules INTERNAL_IPS = ["127.0.0.1"] +# force csrf tokens and cookies to be secure when in https +CSRF_COOKIE_SECURE = env.bool("HTTPS", default=True) +SESSION_COOKIE_SECURE = env.bool("HTTPS", default=True) +X_FRAME_OPTIONS = "SAMEORIGIN" + ALLOWED_HOSTS = ["*"] # Application definition @@ -207,12 +213,12 @@ WSGI_APPLICATION = "sith.wsgi.application" # Database DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - }, + "default": env.dj_db_url("DATABASE_URL", conn_max_age=None, conn_health_checks=True) } +if "CACHE_URL" in os.environ: + CACHES = {"default": env.dj_cache_url("CACHE_URL")} + SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" # Logging @@ -264,13 +270,13 @@ PHONENUMBER_DEFAULT_REGION = "FR" # Medias MEDIA_URL = "/data/" -MEDIA_ROOT = BASE_DIR / "data" +MEDIA_ROOT = env.path("MEDIA_ROOT", default="data") # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ STATIC_URL = "/static/" -STATIC_ROOT = BASE_DIR / "static" +STATIC_ROOT = env.path("STATIC_ROOT", default="static") # Static files finders which allow to see static folder in all apps STATICFILES_FINDERS = [ @@ -294,24 +300,28 @@ AUTHENTICATION_BACKENDS = ["core.auth_backends.SithModelBackend"] LOGIN_URL = "/login" LOGOUT_URL = "/logout" LOGIN_REDIRECT_URL = "/" -DEFAULT_FROM_EMAIL = "bibou@git.an" -SITH_COM_EMAIL = "bibou_com@git.an" +DEFAULT_FROM_EMAIL = env.str("DEFAULT_FROM_EMAIL", default="bibou@git.an") +SITH_COM_EMAIL = env.str("SITH_COM_EMAIL", default="bibou_com@git.an") # Those values are to be changed in production to be more effective -HONEYPOT_FIELD_NAME = "body2" -HONEYPOT_VALUE = "content" +HONEYPOT_FIELD_NAME = env.str("HONEYPOT_FIELD_NAME", default="body2") +HONEYPOT_VALUE = env.str("HONEYPOT_VALUE", default="content") HONEYPOT_RESPONDER = custom_honeypot_error # Make honeypot errors less suspicious -HONEYPOT_FIELD_NAME_FORUM = "message2" # Only used on forum +HONEYPOT_FIELD_NAME_FORUM = env.str( + "HONEYPOT_FIELD_NAME_FORUM", default="message2" +) # Only used on forum # Email -EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -EMAIL_HOST = "localhost" -EMAIL_PORT = 25 +EMAIL_BACKEND = env.str( + "EMAIL_BACKEND", default="django.core.mail.backends.dummy.EmailBackend" +) +EMAIL_HOST = env.str("EMAIL_HOST", default="localhost") +EMAIL_PORT = env.int("EMAIL_PORT", default=25) # Below this line, only Sith-specific variables are defined -SITH_URL = "my.url.git.an" -SITH_NAME = "Sith website" +SITH_URL = env.str("SITH_URL", default="127.0.0.1:8000") +SITH_NAME = env.str("SITH_NAME", default="AE UTBM") SITH_TWITTER = "@ae_utbm" # Enable experimental features @@ -320,7 +330,7 @@ SITH_ENABLE_GALAXY = False # AE configuration # TODO: keep only that first setting, with the ID, and do the same for the other clubs -SITH_MAIN_CLUB_ID = 1 +SITH_MAIN_CLUB_ID = env.int("SITH_MAIN_CLUB_ID", default=1) SITH_MAIN_CLUB = { "name": "AE", "unix_name": "ae", @@ -355,25 +365,27 @@ SITH_SCHOOL_START_YEAR = 1999 # id of the Root account SITH_ROOT_USER_ID = 0 -SITH_GROUP_ROOT_ID = 1 -SITH_GROUP_PUBLIC_ID = 2 -SITH_GROUP_SUBSCRIBERS_ID = 3 -SITH_GROUP_OLD_SUBSCRIBERS_ID = 4 -SITH_GROUP_ACCOUNTING_ADMIN_ID = 5 -SITH_GROUP_COM_ADMIN_ID = 6 -SITH_GROUP_COUNTER_ADMIN_ID = 7 -SITH_GROUP_BANNED_ALCOHOL_ID = 8 -SITH_GROUP_BANNED_COUNTER_ID = 9 -SITH_GROUP_BANNED_SUBSCRIPTION_ID = 10 -SITH_GROUP_SAS_ADMIN_ID = 11 -SITH_GROUP_FORUM_ADMIN_ID = 12 -SITH_GROUP_PEDAGOGY_ADMIN_ID = 13 +SITH_GROUP_ROOT_ID = env.int("SITH_GROUP_ROOT_ID", default=1) +SITH_GROUP_PUBLIC_ID = env.int("SITH_GROUP_PUBLIC_ID", default=2) +SITH_GROUP_SUBSCRIBERS_ID = env.int("SITH_GROUP_SUBSCRIBERS_ID", default=3) +SITH_GROUP_OLD_SUBSCRIBERS_ID = env.int("SITH_GROUP_OLD_SUBSCRIBERS_ID", default=4) +SITH_GROUP_ACCOUNTING_ADMIN_ID = env.int("SITH_GROUP_ACCOUNTING_ADMIN_ID", default=5) +SITH_GROUP_COM_ADMIN_ID = env.int("SITH_GROUP_COM_ADMIN_ID", default=6) +SITH_GROUP_COUNTER_ADMIN_ID = env.int("SITH_GROUP_COUNTER_ADMIN_ID", default=7) +SITH_GROUP_BANNED_ALCOHOL_ID = env.int("SITH_GROUP_BANNED_ALCOHOL_ID", default=8) +SITH_GROUP_BANNED_COUNTER_ID = env.int("SITH_GROUP_BANNED_COUNTER_ID", default=9) +SITH_GROUP_BANNED_SUBSCRIPTION_ID = env.int( + "SITH_GROUP_BANNED_SUBSCRIPTION_ID", default=10 +) +SITH_GROUP_SAS_ADMIN_ID = env.int("SITH_GROUP_SAS_ADMIN_ID", default=11) +SITH_GROUP_FORUM_ADMIN_ID = env.int("SITH_GROUP_FORUM_ADMIN_ID", default=12) +SITH_GROUP_PEDAGOGY_ADMIN_ID = env.int("SITH_GROUP_PEDAGOGY_ADMIN_ID", default=13) -SITH_CLUB_REFOUND_ID = 89 -SITH_COUNTER_REFOUND_ID = 38 -SITH_PRODUCT_REFOUND_ID = 5 +SITH_CLUB_REFOUND_ID = env.int("SITH_CLUB_REFOUND_ID", default=89) +SITH_COUNTER_REFOUND_ID = env.int("SITH_COUNTER_REFOUND_ID", default=38) +SITH_PRODUCT_REFOUND_ID = env.int("SITH_PRODUCT_REFOUND_ID", default=5) -SITH_COUNTER_ACCOUNT_DUMP_ID = 39 +SITH_COUNTER_ACCOUNT_DUMP_ID = env.int("SITH_COUNTER_ACCOUNT_DUMP_ID", default=39) # Pages SITH_CORE_PAGE_SYNTAX = "Aide_sur_la_syntaxe" @@ -383,7 +395,7 @@ SITH_CORE_PAGE_SYNTAX = "Aide_sur_la_syntaxe" SITH_FORUM_PAGE_LENGTH = 30 # SAS variables -SITH_SAS_ROOT_DIR_ID = 4 +SITH_SAS_ROOT_DIR_ID = env.int("SITH_SAS_ROOT_DIR_ID", default=4) SITH_SAS_IMAGES_PER_PAGE = 60 SITH_BOARD_SUFFIX = "-bureau" @@ -490,9 +502,9 @@ SITH_LOG_OPERATION_TYPE = [ SITH_PEDAGOGY_UTBM_API = "https://extranet1.utbm.fr/gpedago/api/guide" -SITH_ECOCUP_CONS = 1152 +SITH_ECOCUP_CONS = env.int("SITH_ECOCUP_CONS", default=1151) -SITH_ECOCUP_DECO = 1151 +SITH_ECOCUP_DECO = env.int("SITH_ECOCUP_DECO", default=1152) # The limit is the maximum difference between cons and deco possible for a customer SITH_ECOCUP_LIMIT = 3 @@ -507,21 +519,31 @@ SITH_ACCOUNT_DUMP_DELTA = timedelta(days=30) # Defines which product type is the refilling type, # and thus increases the account amount -SITH_COUNTER_PRODUCTTYPE_REFILLING = 3 +SITH_COUNTER_PRODUCTTYPE_REFILLING = env.int( + "SITH_COUNTER_PRODUCTTYPE_REFILLING", default=3 +) # Defines which product is the one year subscription # and which one is the six month subscription -SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER = 1 -SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS = 2 -SITH_PRODUCTTYPE_SUBSCRIPTION = 2 +SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER = env.int( + "SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER", default=1 +) +SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS = env.int( + "SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS", default=2 +) +SITH_PRODUCTTYPE_SUBSCRIPTION = env.int("SITH_PRODUCTTYPE_SUBSCRIPTION", default=2) # Defines which club lets its member the ability to make subscriptions # Elements of this list are club's id -SITH_CAN_CREATE_SUBSCRIPTIONS = [1] +SITH_CAN_CREATE_SUBSCRIPTIONS = env.list( + "SITH_CAN_CREATE_SUBSCRIPTION_HISTORY", default=[1] +) # Defines which clubs lets its members the ability to see users subscription history # Elements of this list are club's id -SITH_CAN_READ_SUBSCRIPTION_HISTORY = [] +SITH_CAN_READ_SUBSCRIPTION_HISTORY = env.list( + "SITH_CAN_READ_SUBSCRIPTION_HISTORY", default=[1] +) # Number of weeks before the end of a subscription when the subscriber can resubscribe SITH_SUBSCRIPTION_END = 10 @@ -630,21 +652,29 @@ SITH_BARMAN_TIMEOUT = 30 SITH_LAST_OPERATIONS_LIMIT = 10 # ET variables -SITH_EBOUTIC_CB_ENABLED = True -SITH_EBOUTIC_ET_URL = ( - "https://preprod-tpeweb.e-transactions.fr/cgi/MYchoix_pagepaiement.cgi" +SITH_EBOUTIC_CB_ENABLED = env.bool("SITH_EBOUTIC_CB_ENABLED", default=True) +SITH_EBOUTIC_ET_URL = env.str( + "SITH_EBOUTIC_ET_URL", + default="https://preprod-tpeweb.e-transactions.fr/cgi/MYchoix_pagepaiement.cgi", ) -SITH_EBOUTIC_PBX_SITE = "1999888" -SITH_EBOUTIC_PBX_RANG = "32" -SITH_EBOUTIC_PBX_IDENTIFIANT = "2" +SITH_EBOUTIC_PBX_SITE = env.str("SITH_EBOUTIC_PBX_SITE", default="1999888") +SITH_EBOUTIC_PBX_RANG = env.str("SITH_EBOUTIC_PBX_RANG", default="32") +SITH_EBOUTIC_PBX_IDENTIFIANT = env.str("SITH_EBOUTIC_PBX_IDENTIFIANT", default="2") SITH_EBOUTIC_HMAC_KEY = binascii.unhexlify( - "0123456789ABCDEF0123456789ABCDEF" - "0123456789ABCDEF0123456789ABCDEF" - "0123456789ABCDEF0123456789ABCDEF" - "0123456789ABCDEF0123456789ABCDEF" + env.str( + "SITH_EBOUTIC_HMAC_KEY", + default=( + "0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF" + ), + ) ) SITH_EBOUTIC_PUB_KEY = "" -with open(os.path.join(os.path.dirname(__file__), "et_keys/pubkey.pem")) as f: +with open( + env.path("SITH_EBOUTIC_PUB_KEY_PATH", default=BASE_DIR / "sith/et_keys/pubkey.pem") +) as f: SITH_EBOUTIC_PUB_KEY = f.read() # Launderette variables @@ -686,24 +716,17 @@ SITH_QUICK_NOTIF = { # Mailing related settings SITH_MAILING_DOMAIN = "utbm.fr" -SITH_MAILING_FETCH_KEY = "IloveMails" +SITH_MAILING_FETCH_KEY = env.str("SITH_MAILING_FETCH_KEY", default="ILoveMails") SITH_GIFT_LIST = [("AE Tee-shirt", _("AE tee-shirt"))] -SENTRY_DSN = "" -SENTRY_ENV = "production" +SENTRY_DSN = env.str("SENRY_DSN", default=None) +SENTRY_ENV = env.str("SENTRY_ENV", default="production") TOXIC_DOMAINS_PROVIDERS = [ "https://www.stopforumspam.com/downloads/toxic_domains_whole.txt", ] -try: - from .settings_custom import * # noqa F403 (this star-import is actually useful) - - logging.getLogger("django").info("Custom settings imported") -except ImportError: - logging.getLogger("django").warning("Custom settings failed") - if DEBUG: INSTALLED_APPS += ("debug_toolbar",) MIDDLEWARE = ("debug_toolbar.middleware.DebugToolbarMiddleware", *MIDDLEWARE) diff --git a/sith/urls.py b/sith/urls.py index 95f22662..f6f7c8bb 100644 --- a/sith/urls.py +++ b/sith/urls.py @@ -81,7 +81,7 @@ def sentry_debug(request): The error will be displayed on Sentry inside the "development" environment - NOTE : you need to specify the SENTRY_DSN setting in settings_custom.py + NOTE : you need to specify the SENTRY_DSN setting in .env """ if settings.SENTRY_ENV != "development" or not settings.SENTRY_DSN: raise Http404