From 4d5275676340f5ebb86d87824ba7266a8d5e9b38 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Tue, 31 Jan 2023 13:43:05 +0100 Subject: [PATCH] =?UTF-8?q?annuaire/settings:=20S=C3=A9pare=20les=20param?= =?UTF-8?q?=C3=A8tres=20de=20prod=20et=20de=20d=C3=A9veloppement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + annuaire/settings.py | 167 ---------------------------- annuaire/settings/__init__.py | 0 annuaire/settings/common.py | 139 +++++++++++++++++++++++ annuaire/settings/dev.py | 62 +++++++++++ annuaire/settings/prod.py | 67 +++++++++++ annuaire/settings/secret_example.py | 4 + manage.py | 2 +- shell.nix | 2 + 9 files changed, 276 insertions(+), 168 deletions(-) delete mode 100644 annuaire/settings.py create mode 100644 annuaire/settings/__init__.py create mode 100644 annuaire/settings/common.py create mode 100644 annuaire/settings/dev.py create mode 100644 annuaire/settings/prod.py create mode 100644 annuaire/settings/secret_example.py diff --git a/.gitignore b/.gitignore index 44bf8a6..42c4872 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ fiches/static/fiches/css_old/ .vscode .direnv +annuaire/settings/secret.py diff --git a/annuaire/settings.py b/annuaire/settings.py deleted file mode 100644 index 07c0bf7..0000000 --- a/annuaire/settings.py +++ /dev/null @@ -1,167 +0,0 @@ -""" -Django settings for annuaire project. - -Generated by 'django-admin startproject' using Django 2.2b1. - -For more information on this file, see -https://docs.djangoproject.com/en/dev/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/dev/ref/settings/ -""" - -import os -from django.urls import reverse_lazy - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "84=n(@@wl(04oc$(-+3surgrlf&uq3=m)=(hpg$immi1h69s)p" - -# À bouger dans un ficher secret quand il sera créé ? -LDAP = { - "SPI": { - "PROTOCOL": "ldaps", - "URL": "ldap.spi.ens.fr", - "PORT": 636, - }, - "CRI": { - "PROTOCOL": "ldap", - "URL": "annuaire.ens.fr", - "PORT": 389, - }, -} - -ANNUAIRE = { - "PROTOCOL": "http", - "URL": "annuaireweb.ens.fr", - "PORT": 80, -} - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - -# Application definition - -INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "authens", - "fiches", -] - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.locale.LocaleMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "annuaire.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -AUTHENTICATION_BACKENDS = ( - "django.contrib.auth.backends.ModelBackend", - "fiches.backends.BackendFiches", -) - -WSGI_APPLICATION = "annuaire.wsgi.application" - - -# Database -# https://docs.djangoproject.com/en/dev/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } -} - -DEFAULT_AUTO_FIELD = "django.db.models.AutoField" - - -# Password validation -# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/dev/topics/i18n/ - -LANGUAGE_CODE = "fr-fr" - -LANGUAGES = [ - ("fr", "Français"), - ("en", "English"), -] - -LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")] - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_L10N = False - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/dev/howto/static-files/ - -STATIC_URL = "/static/" - -MEDIA_ROOT = os.path.join(BASE_DIR, "media") - -MEDIA_URL = "/media/" - -LOGIN_URL = reverse_lazy("authens:login") -LOGOUT_REDIRECT_URL = reverse_lazy("home") -AUTHENS_USE_OLDCAS = False - -EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" diff --git a/annuaire/settings/__init__.py b/annuaire/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/annuaire/settings/common.py b/annuaire/settings/common.py new file mode 100644 index 0000000..65bc2ba --- /dev/null +++ b/annuaire/settings/common.py @@ -0,0 +1,139 @@ +""" +Paramètres communs pour l'annuaire. +""" + +from pathlib import Path + +from django.urls import reverse_lazy + +# ############################################################################# +# Secrets +# ############################################################################# + +try: + from . import secret +except ImportError: + raise ImportError( + "Le fichier `secret.py` est manquant.\n" + "Pour un environnement de développement, copiez `secret_example.py`." + ) + + +def get_secret(name: str): + """Shortcut to get a value from the `secret.py` file.""" + + if hasattr(secret, name): + return getattr(secret, name) + else: + raise RuntimeError(f"Le secret `{name}` est manquant.") + + +SECRET_KEY = get_secret("SECRET_KEY") +ADMINS = get_secret("ADMINS") +SERVER_EMAIL = get_secret("SERVER_EMAIL") +EMAIL_HOST = get_secret("EMAIL_HOST") + +# ############################################################################# +# Valeurs par défaut de Django +# ############################################################################# + +DEBUG = False + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + +# Application definition +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "authens", + "fiches", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "annuaire.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +AUTHENTICATION_BACKENDS = ( + "django.contrib.auth.backends.ModelBackend", + "fiches.backends.BackendFiches", +) + +WSGI_APPLICATION = "annuaire.wsgi.application" + +# ############################################################################# +# Paramètres de langue +# ############################################################################# + +LANGUAGE_CODE = "fr-fr" + +LANGUAGES = [ + ("fr", "Français"), + ("en", "English"), +] + +LOCALE_PATHS = [BASE_DIR / "locale"] + +TIME_ZONE = "UTC" + +USE_I18N = True +USE_L10N = True + +USE_TZ = True + +# ############################################################################# +# Paramètres CAS et LDAP +# ############################################################################# + +LOGIN_URL = reverse_lazy("authens:login") +LOGOUT_REDIRECT_URL = reverse_lazy("home") +AUTHENS_USE_OLDCAS = False +AUTHENS_USE_PASSWORD = False + +LDAP = { + "SPI": { + "PROTOCOL": "ldaps", + "URL": "ldap.spi.ens.fr", + "PORT": 636, + }, + "CRI": { + "PROTOCOL": "ldap", + "URL": "annuaire.ens.fr", + "PORT": 389, + }, +} + +ANNUAIRE = { + "PROTOCOL": "http", + "URL": "annuaireweb.ens.fr", + "PORT": 80, +} diff --git a/annuaire/settings/dev.py b/annuaire/settings/dev.py new file mode 100644 index 0000000..c1bad77 --- /dev/null +++ b/annuaire/settings/dev.py @@ -0,0 +1,62 @@ +""" +Paramètres de développement pour l'annuaire. +""" + +from django.urls import reverse_lazy + +from .common import * # noqa +from .common import BASE_DIR, INSTALLED_APPS, MIDDLEWARE + +# --- +# Tweaks for debug/local development +# --- + +ALLOWED_HOSTS = [] + +DEBUG = True +EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + +STATIC_URL = "/static/" +MEDIA_URL = "/media/" +MEDIA_ROOT = BASE_DIR / "media" + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + +# Use the default cache backend for local development +CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}} + +# Pas besoin de sécurité en local +AUTH_PASSWORD_VALIDATORS = [] +PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] + +LOGIN_URL = reverse_lazy("authens:login") +AUTHENS_USE_PASSWORD = True + +# ############################################################################# +# Debug tool bar +# ############################################################################# + + +def show_toolbar(request): + """ + On active la debug-toolbar en mode développement local sauf : + - dans l'admin où ça ne sert pas à grand chose; + - si la variable d'environnement DJANGO_NO_DDT est à 1 → ça permet de la désactiver + sans modifier ce fichier en exécutant `export DJANGO_NO_DDT=1` dans le terminal + qui lance `./manage.py runserver`. + + Autre side effect de cette fonction : on ne fait pas la vérification de INTERNAL_IPS + que ferait la debug-toolbar par défaut, ce qui la fait fonctionner aussi à + l'intérieur de Vagrant (comportement non testé depuis un moment…) + """ + return DEBUG and not request.path.startswith("/admin/") + + +INSTALLED_APPS = INSTALLED_APPS + ["debug_toolbar"] +MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE +DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar} diff --git a/annuaire/settings/prod.py b/annuaire/settings/prod.py new file mode 100644 index 0000000..49c1943 --- /dev/null +++ b/annuaire/settings/prod.py @@ -0,0 +1,67 @@ +""" +Paramètres de production pour l'annuaire. +""" + +import os + +from .common import * # noqa +from .common import BASE_DIR, get_secret + +# ############################################################################# +# Prod-specific secrets +# ############################################################################# + +REDIS_PASSWD = get_secret("REDIS_PASSWD") +REDIS_DB = get_secret("REDIS_DB") +REDIS_HOST = get_secret("REDIS_HOST") +REDIS_PORT = get_secret("REDIS_PORT") + +DBNAME = get_secret("DBNAME") +DBUSER = get_secret("DBUSER") +DBPASSWD = get_secret("DBPASSWD") + +ALLOWED_HOSTS = ["annuaire.eleves.ens.fr", "www.annuaire.eleves.ens.fr"] + +STATIC_ROOT = BASE_DIR.parent / "public" / "annuaire" / "static" + +STATIC_URL = "/static/" +MEDIA_ROOT = BASE_DIR / "media" +MEDIA_URL = "/media/" + +# ############################################################################# +# Cache settings +# ############################################################################# + +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://:{passwd}@{host}:{port}/{db}".format( + passwd=REDIS_PASSWD, host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB + ), + } +} + +# ############################################################################# +# Prod database settings +# ############################################################################# + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": DBNAME, + "USER": DBUSER, + "PASSWORD": DBPASSWD, + "HOST": os.environ.get("DBHOST", "localhost"), + } +} + + +AUTH_PASSWORD_VALIDATORS = map( + lambda v: {"NAME": f"django.contrib.auth.password_validation.{v}"}, + [ + "UserAttributeSimilarityValidator", + "MinimumLengthValidator", + "CommonPasswordValidator", + "NumericPasswordValidator", + ], +) diff --git a/annuaire/settings/secret_example.py b/annuaire/settings/secret_example.py new file mode 100644 index 0000000..163a0aa --- /dev/null +++ b/annuaire/settings/secret_example.py @@ -0,0 +1,4 @@ +SECRET_KEY = "$=kp$3e=xh)*4h8(_g#lprlmve_vs9_xv9hlgse%+uk9nhc==x" +ADMINS = None +SERVER_EMAIL = "root@localhost" +EMAIL_HOST = None diff --git a/manage.py b/manage.py index e1a3af7..ed92cea 100755 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ import sys def main(): - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "annuaire.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "annuaire.settings.prod") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/shell.nix b/shell.nix index 4246825..477bf9d 100644 --- a/shell.nix +++ b/shell.nix @@ -34,5 +34,7 @@ pkgs.mkShell { shellHook = '' ${pre-commit-check.shellHook} + + export DJANGO_SETTINGS_MODULE="annuaire.settings.dev" ''; }