""" Django settings for servala project. Servala is run using environment variables. Documentation: - README.md for project information - .env.example for environment variables in use - Django settings guide: https://docs.djangoproject.com/en/5.2/topics/settings/ - Django settings reference: https://docs.djangoproject.com/en/5.2/ref/settings/ """ import os from pathlib import Path from django.contrib import messages SERVALA_ENVIRONMENT = os.environ.get("SERVALA_ENVIRONMENT", "development") DEBUG = SERVALA_ENVIRONMENT == "development" SECRET_KEY = os.environ.get("SERVALA_SECRET_KEY") if previous_secret_key := os.environ.get("SERVALA_PREVIOUS_SECRET_KEY"): SECRET_KEY_FALLBACKS = [previous_secret_key] SALT_KEY = os.environ.get("SERVALA_SALT_KEY") if previous_salt := os.environ.get("SERVALA_PREVIOUS_SALT_KEY"): SALT_KEY = [SALT_KEY, previous_salt] BASE_DIR = Path(__file__).resolve().parent.parent ALLOWED_HOSTS = [] if allowed_hosts := os.environ.get("SERVALA_ALLOWED_HOSTS"): ALLOWED_HOSTS = allowed_hosts.split(",") CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS] db_name = os.environ.get("SERVALA_DB_NAME", "") if SERVALA_ENVIRONMENT == "development" and not db_name: DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", "OPTIONS": {"timeout": 10}, } } else: DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": db_name or "servala", "USER": os.environ.get("SERVALA_DB_USER", "servala"), "PASSWORD": os.environ.get("SERVALA_DB_PASSWORD"), "HOST": os.environ.get("SERVALA_DB_HOST", "localhost"), "PORT": os.environ.get("SERVALA_DB_PORT", "5432"), "CONN_MAX_AGE": 120, "CONN_HEALTH_CHECKS": True, } } MEDIA_ROOT = os.environ.get("SERVALA_MEDIA_ROOT", "media") if MEDIA_ROOT.startswith("/"): MEDIA_ROOT = Path(MEDIA_ROOT) else: MEDIA_ROOT = BASE_DIR / MEDIA_ROOT EMAIL_HOST = os.environ.get("SERVALA_EMAIL_HOST", "localhost") EMAIL_PORT = int(os.environ.get("SERVALA_EMAIL_PORT", "25")) EMAIL_HOST_USER = os.environ.get("SERVALA_EMAIL_USER", "") EMAIL_HOST_PASSWORD = os.environ.get("SERVALA_EMAIL_PASSWORD", "") EMAIL_USE_TLS = os.environ.get("SERVALA_EMAIL_TLS", "False") == "True" EMAIL_USE_SSL = os.environ.get("SERVALA_EMAIL_SSL", "False") == "True" SERVALA_DEFAULT_ORIGIN = int(os.environ.get("SERVALA_DEFAULT_ORIGIN", "1")) SOCIALACCOUNT_PROVIDERS = { "openid_connect": { "APPS": [ { "provider_id": "keycloak", "name": "VSHN Account", "client_id": os.environ.get("SERVALA_KEYCLOAK_CLIENT_ID"), "secret": os.environ.get("SERVALA_KEYCLOAK_CLIENT_SECRET"), "settings": { "server_url": os.environ.get("SERVALA_KEYCLOAK_SERVER_URL"), }, } ] } } ####################################### # Non-configurable settings below # ####################################### WSGI_APPLICATION = "servala.wsgi.application" INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "django.forms", "template_partials", "rules.apps.AutodiscoverRulesConfig", # The frontend app is loaded early in order to supersede some allauth views/behaviour "servala.frontend", "allauth", "allauth.account", "allauth.socialaccount", "allauth.socialaccount.providers.openid_connect", "servala.core", ] 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", "allauth.account.middleware.AccountMiddleware", "django.contrib.auth.middleware.LoginRequiredMiddleware", "servala.core.middleware.OrganizationMiddleware", ] LOGIN_URL = "account_login" ROOT_URLCONF = "servala.urls" STATIC_URL = "static/" # CSS, JavaScript, etc. # Collected static files as provided by ``collectstatic`` management command are stored here ready to be served by a web server. STATIC_ROOT = BASE_DIR / "static.dist" MEDIA_URL = "media/" # User uploads, e.g. images # Additional locations of static files STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) STATICFILES_DIRS = [BASE_DIR / "servala" / "static"] template_loaders = ( "django.template.loaders.filesystem.Loader", "django.template.loaders.app_directories.Loader", ) if not DEBUG: template_loaders = (("django.template.loaders.cached.Loader", template_loaders),) TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [], "APP_DIRS": False, "OPTIONS": { "context_processors": [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", "django.template.context_processors.static", "servala.frontend.context_processors.add_organizations", ], "loaders": template_loaders, }, }, ] FORM_RENDERER = "servala.frontend.forms.renderers.VerticalFormRenderer" MESSAGE_TAGS = { messages.ERROR: "danger", } AUTH_USER_MODEL = "core.User" ACCOUNT_USER_MODEL_USERNAME_FIELD = None ACCOUNT_UNIQUE_EMAIL = True ACCOUNT_LOGIN_METHODS = {"email"} ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] ACCOUNT_SIGNUP_FORM_CLASS = "servala.frontend.forms.auth.ServalaSignupForm" if ALLOWED_HOSTS or not DEBUG: ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https" AUTHENTICATION_BACKENDS = [ "rules.permissions.ObjectPermissionBackend", # Needed to login by username in Django admin, regardless of `allauth` "django.contrib.auth.backends.ModelBackend", "allauth.account.auth_backends.AuthenticationBackend", ] 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"}, ] PASSWORD_HASHERS = [ "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ] CSRF_COOKIE_NAME = "servala_csrf" LANGUAGE_COOKIE_NAME = "servala_lang" SESSION_COOKIE_NAME = "servala_sess" SESSION_COOKIE_SECURE = not DEBUG DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # TODO TIME_ZONE = "UTC" if SERVALA_ENVIRONMENT in ("staging", "production"): SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")