diff --git a/.credentials/HCAPTCHA_SECRET b/.credentials/HCAPTCHA_SECRET new file mode 100644 index 00000000..7daa69d3 --- /dev/null +++ b/.credentials/HCAPTCHA_SECRET @@ -0,0 +1 @@ +0x0000000000000000000000000000000000000000 diff --git a/.credentials/HCAPTCHA_SITEKEY b/.credentials/HCAPTCHA_SITEKEY new file mode 100644 index 00000000..f5093057 --- /dev/null +++ b/.credentials/HCAPTCHA_SITEKEY @@ -0,0 +1 @@ +10000000-ffff-ffff-ffff-000000000001 diff --git a/.credentials/KFETOPEN_TOKEN b/.credentials/KFETOPEN_TOKEN new file mode 100644 index 00000000..4cbb2bf5 --- /dev/null +++ b/.credentials/KFETOPEN_TOKEN @@ -0,0 +1 @@ +k-feste_token diff --git a/.credentials/SECRET_KEY b/.credentials/SECRET_KEY new file mode 100644 index 00000000..de873cc2 --- /dev/null +++ b/.credentials/SECRET_KEY @@ -0,0 +1 @@ +insecure-key diff --git a/gestioasso/settings_bds.py b/gestioasso/settings_bds.py new file mode 100644 index 00000000..82d4a520 --- /dev/null +++ b/gestioasso/settings_bds.py @@ -0,0 +1,194 @@ +""" +Django settings for the gestioBDS project. +""" + +import os +from pathlib import Path + +from loadcredential import Credentials + +credentials = Credentials(env_prefix="GESTIOBDS_") + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# WARNING: keep the secret key used in production secret! +SECRET_KEY = credentials["SECRET_KEY"] + +# WARNING: don't run with debug turned on in production! +DEBUG = credentials.get_json("DEBUG", False) + +ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", []) +ADMINS = credentials.get_json("ADMINS", []) + +SERVER_EMAIL = credentials.get("SERVER_EMAIL") +EMAIL_HOST = credentials.get("EMAIL_HOST") + +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + + +## +# Installed Apps configuration + +INSTALLED_APPS = [ + "shared", + # Must be before 'django.contrib.admin'. + # https://django-autocomplete-light.readthedocs.io/en/master/install.html + "dal", + "dal_select2", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.messages", + "django.contrib.admin", + "django.contrib.admindocs", + "gestioasso.apps.IgnoreSrcStaticFilesConfig", + "django_cas_ng", + "bootstrapform", + "widget_tweaks", + "bds", + "events", + "clubs", + "authens", +] + + +## +# Middleware configuration + +MIDDLEWARE = [ + "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", + "django.middleware.security.SecurityMiddleware", + "django.middleware.locale.LocaleMiddleware", +] + + +## +# URL configuration + +ROOT_URLCONF = "gestioasso.urls" + + +## +# Templates configuration + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "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", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.static", + ] + }, + } +] + + +## +# Database configuration + +DATABASES = credentials.get_json( + "DATABASES", + default={ + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": (BASE_DIR / "db.sqlite3"), + } + }, +) + +CACHES = credentials.get_json( + "CACHES", + default={ + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + }, + }, +) + +CORS_ORIGIN_WHITELIST = credentials.get("CORS_ORIGIN_WHITELIST", []) + + +SITE_ID = 1 + + +### +# Staticfiles configuration + +STATIC_ROOT = credentials["STATIC_ROOT"] +STATIC_URL = "/gestion/static/" + +MEDIA_ROOT = credentials.get("MEDIA_ROOT", (BASE_DIR / "media")) +MEDIA_URL = "/gestion/media/" + + +## +# Authens and Authentication configuration + +AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "authens.backends.ENSCASBackend", + "authens.backends.OldCASBackend", +] + +AUTHENS_USE_OLDCAS = False + +LOGIN_URL = "authens:login" +LOGIN_REDIRECT_URL = "bds:home" +LOGOUT_REDIRECT_URL = "bds:home" + + +# --- +# Internationalization +# https://docs.djangoproject.com/en/1.8/topics/i18n/ +# --- + +LANGUAGE_CODE = "fr-fr" +TIME_ZONE = "Europe/Paris" +USE_I18N = True +USE_L10N = True +USE_TZ = True +LANGUAGES = (("fr", "Français"), ("en", "English")) +FORMAT_MODULE_PATH = "gestioasso.locale" + +## +# Development configuration + +if DEBUG: + EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + + 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…) + """ + + env_no_ddt = bool(os.environ.get("DJANGO_NO_DDT", None)) + return not (env_no_ddt or request.path.startswith("/admin/")) + + ## + # Django Debug Toolbar configuration + + DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar} + INSTALLED_APPS += ["debug_toolbar"] + MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE diff --git a/gestioasso/settings_cof.py b/gestioasso/settings_cof.py new file mode 100644 index 00000000..433f5e38 --- /dev/null +++ b/gestioasso/settings_cof.py @@ -0,0 +1,318 @@ +""" +Django settings for the gestioCOF project. +""" + +import os +from datetime import datetime, timedelta +from pathlib import Path + +from django.urls import reverse_lazy +from loadcredential import Credentials + +credentials = Credentials(env_prefix="GESTIOCOF_") + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# WARNING: keep the secret key used in production secret! +SECRET_KEY = credentials["SECRET_KEY"] + +# WARNING: don't run with debug turned on in production! +DEBUG = credentials.get_json("DEBUG", False) + +ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", []) +ADMINS = credentials.get_json("ADMINS", []) + +SERVER_EMAIL = credentials.get("SERVER_EMAIL") +EMAIL_HOST = credentials.get("EMAIL_HOST") + +LDAP_SERVER_URL = credentials.get("LDAP_SERVER_URL") + +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + + +## +# Installed Apps configuration + +INSTALLED_APPS = [ + "gestioncof", + # Must be before django admin + # https://github.com/infoportugal/wagtail-modeltranslation/issues/193 + "wagtail_modeltranslation", + "wagtail_modeltranslation.makemigrations", + "wagtail_modeltranslation.migrate", + "modeltranslation", + "shared", + # Must be before 'django.contrib.admin'. + # https://django-autocomplete-light.readthedocs.io/en/master/install.html + "dal", + "dal_select2", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.messages", + "django.contrib.admin", + "django.contrib.admindocs", + "gestioasso.apps.IgnoreSrcStaticFilesConfig", + "django_cas_ng", + "bootstrapform", + "widget_tweaks", + "bda", + "petitscours", + "hcaptcha", + "kfet", + "kfet.open", + "channels", + "djconfig", + "wagtail.contrib.forms", + "wagtail.contrib.redirects", + "wagtail.embeds", + "wagtail.sites", + "wagtail.users", + "wagtail.snippets", + "wagtail.documents", + "wagtail.images", + "wagtail.search", + "wagtail.admin", + "wagtail", + # "wagtail.contrib.modeladmin", + "wagtail.contrib.routable_page", + "wagtailmenus", + "modelcluster", + "taggit", + "kfet.auth", + "kfet.cms", + "gestioncof.cms", + "django_js_reverse", +] + + +## +# Middleware configuration + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + "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", + "django.middleware.security.SecurityMiddleware", + "django.middleware.locale.LocaleMiddleware", + "djconfig.middleware.DjConfigMiddleware", + "wagtail.contrib.redirects.middleware.RedirectMiddleware", +] + + +## +# URL configuration + +ROOT_URLCONF = "gestioasso.urls" + + +## +# Templates configuration + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "wagtailmenus.context_processors.wagtailmenus", + "djconfig.context_processors.config", + "gestioncof.shared.context_processor", + "kfet.auth.context_processors.temporary_auth", + "kfet.context_processors.config", + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.static", + ] + }, + } +] + + +## +# Wagtail configuration + +WAGTAIL_SITE_NAME = "GestioCOF" +WAGTAIL_ENABLE_UPDATE_CHECK = False +TAGGIT_CASE_INSENSITIVE = True + +## +# Django-js-reverse settings + +JS_REVERSE_JS_VAR_NAME = "django_urls" +# Quand on aura namespace les urls... +# JS_REVERSE_INCLUDE_ONLY_NAMESPACES = ['k-fet'] + +## +# K-Fêt history configuration + +# L'historique n'est accesible que d'aujourd'hui +# à aujourd'hui - KFET_HISTORY_DATE_LIMIT +KFET_HISTORY_DATE_LIMIT = timedelta(days=7) + +# Limite plus longue pour les chefs/trez +# (qui ont la permission kfet.access_old_history) +KFET_HISTORY_LONG_DATE_LIMIT = timedelta(days=30) + +# These accounts don't represent actual people and can be freely accessed +# Identification based on trigrammes +KFET_HISTORY_NO_DATE_LIMIT_TRIGRAMMES = ["LIQ", "#13"] +KFET_HISTORY_NO_DATE_LIMIT = datetime(1794, 10, 30) # AKA the distant past + + +## +# Database configuration + +DATABASES = credentials.get_json( + "DATABASES", + default={ + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": (BASE_DIR / "db.sqlite3"), + } + }, +) + +CACHES = credentials.get_json( + "CACHES", + default={ + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + }, + }, +) + +CHANNEL_LAYERS = credentials.get_json( + "CHANNEL_LAYERS", + default={ + "default": { + "BACKEND": "channels.layers.InMemoryChannelLayer", + } + }, +) + +CORS_ORIGIN_WHITELIST = credentials.get("CORS_ORIGIN_WHITELIST", []) + + +SITE_ID = 1 + + +### +# Staticfiles configuration + +STATIC_ROOT = credentials["STATIC_ROOT"] +STATIC_URL = "/gestion/static/" + +MEDIA_ROOT = credentials.get("MEDIA_ROOT", (BASE_DIR / "media")) +MEDIA_URL = "/gestion/media/" + + +## +# Authentication configuration + +AUTHENTICATION_BACKENDS = [ + "kfet.auth.backends.BlockFrozenAccountBackend", # Must be in first + "django.contrib.auth.backends.ModelBackend", + "gestioncof.shared.COFCASBackend", + "kfet.auth.backends.GenericBackend", +] + +LOGIN_URL = "cof-login" +LOGIN_REDIRECT_URL = reverse_lazy("home") + +# FIXME: Switch to authens +CAS_SERVER_URL = "https://cas.eleves.ens.fr/" +CAS_VERSION = "2" +CAS_LOGIN_MSG = None +CAS_IGNORE_REFERER = True +CAS_REDIRECT_URL = "/" +CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" + + +## +# h-captcha configuration + +HCAPTCHA_SITEKEY = credentials["HCAPTCHA_SITEKEY"] +HCAPTCHA_SECRET = credentials["HCAPTCHA_SECRET"] + +## +# K-Fêt token for the openness indicator + +KFETOPEN_TOKEN = credentials["KFETOPEN_TOKEN"] + + +## +# Mail configuration + +MAIL_DATA = { + "petits_cours": { + "FROM": "Le COF ", + "BCC": "archivescof@gmail.com", + "REPLYTO": "cof@ens.fr", + }, + "rappels": { + "FROM": "Le BdA ", + "REPLYTO": "Le BdA ", + }, + "rappel_negatif": { + "FROM": "La K-Fêt ", + "REPLYTO": "La K-Fêt ", + }, + "revente": { + "FROM": "BdA-Revente ", + "REPLYTO": "BdA-Revente ", + }, +} + + +# --- +# Internationalization +# https://docs.djangoproject.com/en/1.8/topics/i18n/ +# --- + +LANGUAGE_CODE = "fr-fr" +TIME_ZONE = "Europe/Paris" +USE_I18N = True +USE_L10N = True +USE_TZ = True +LANGUAGES = (("fr", "Français"), ("en", "English")) +FORMAT_MODULE_PATH = "gestioasso.locale" + +## +# Development configuration + +if DEBUG: + EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + + 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…) + """ + + env_no_ddt = bool(os.environ.get("DJANGO_NO_DDT", None)) + return not (env_no_ddt or request.path.startswith("/admin/")) + + ## + # Django Debug Toolbar configuration + + DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar} + INSTALLED_APPS += ["debug_toolbar"] + MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE diff --git a/shell.nix b/shell.nix index ee150476..16185568 100644 --- a/shell.nix +++ b/shell.nix @@ -1,11 +1,21 @@ +{ + sources ? import ./npins, + pkgs ? import sources.nixpkgs { }, +}: + let - sources = import ./npins; - pkgs = import sources.nixpkgs { }; nix-pkgs = import sources.nix-pkgs { inherit pkgs; }; kat-pkgs = import sources.kat-pkgs { inherit pkgs; }; + python3 = pkgs.python3.override { packageOverrides = final: prev: { - inherit (nix-pkgs) authens django-bootstrap-form django-cas-ng; + inherit (nix-pkgs) + authens + django-bootstrap-form + django-cas-ng + loadcredential + ; + inherit (kat-pkgs.python3Packages) django-djconfig django-hCaptcha @@ -17,9 +27,22 @@ let in pkgs.mkShell { shellHook = '' - export DJANGO_SETTINGS_MODULE=gestioasso.settings.local + if [ ! -d .static ]; then + mkdir .static + fi ''; + env = { + CREDENTIALS_DIRECTORY = builtins.toString ./.credentials; + DJANGO_SETTINGS_MODULE = "gestioasso.settings.local"; + + GESTIOCOF_DEBUG = true; + GESTIOCOF_STATIC_ROOT = builtins.toString ./.static; + + GESTIOBDS_DEBUG = true; + GESTIOBDS_STATIC_ROOT = builtins.toString ./.static; + }; + packages = [ (python3.withPackages ( ps: with ps; [ @@ -37,6 +60,7 @@ pkgs.mkShell { django-js-reverse django-widget-tweaks icalendar + loadcredential python-dateutil statistics wagtail-modeltranslation