Simplified settings
Migrated settings to typed pydantic settings
This commit is contained in:
parent
d60ba9a051
commit
c758858392
|
@ -29,11 +29,10 @@ jobs:
|
|||
python -m pip install -r requirements-dev.txt
|
||||
- name: Run pytest
|
||||
env:
|
||||
PGHOST: localhost
|
||||
PGPORT: ${{ job.services.postgres.ports[5432] }}
|
||||
PGNAME: postgres
|
||||
PGUSER: postgres
|
||||
PGPASSWORD: postgres
|
||||
TAKAHE_DATABASE_URL: "postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/postgres"
|
||||
TAKAHE_ENVIRONMENT: "test"
|
||||
TAKAHE_SECRET_KEY: "testing_secret"
|
||||
TAKAHE_MAIN_DOMAIN: "example.com"
|
||||
run: |
|
||||
python -m pytest
|
||||
- name: Run pre-commit
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
TAKAHE_DATABASE_URL="postgres://postgres:insecure_password@db/takahe"
|
||||
TAKAHE_DEBUG=true
|
||||
TAKAHE_SECRET_KEY="insecure_secret"
|
||||
TAKAHE_CSRF_TRUSTED_ORIGINS=["http://127.0.0.1:8000", "https://127.0.0.1:8000"]
|
||||
TAKAHE_USE_PROXY_HEADERS=true
|
||||
TAKAHE_EMAIL_BACKEND="console://console"
|
||||
TAKAHE_MAIN_DOMAIN="example.com"
|
||||
TAKAHE_ENVIRONMENT="development"
|
|
@ -20,7 +20,7 @@ def capture_message(message: str):
|
|||
"""
|
||||
Sends the informational message to Sentry if it's configured
|
||||
"""
|
||||
if settings.SENTRY_ENABLED:
|
||||
if settings.SETUP.SENTRY_DSN:
|
||||
from sentry_sdk import capture_message
|
||||
|
||||
capture_message(message)
|
||||
|
@ -32,7 +32,7 @@ def capture_exception(exception: BaseException):
|
|||
"""
|
||||
Sends the exception to Sentry if it's configured
|
||||
"""
|
||||
if settings.SENTRY_ENABLED:
|
||||
if settings.SETUP.SENTRY_DSN:
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
capture_exception(exception)
|
||||
|
|
|
@ -11,8 +11,7 @@ COPY . /takahe
|
|||
|
||||
WORKDIR /takahe
|
||||
|
||||
# We use development here to skip settings checks
|
||||
RUN DJANGO_SETTINGS_MODULE=takahe.settings.development python3 manage.py collectstatic
|
||||
RUN TAKAHE_DATABASE_URL="postgres://dummy:dummy@localhost/postgres" python3 manage.py collectstatic
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
|
|
|
@ -12,11 +12,14 @@ x-takahe-common:
|
|||
|
||||
image: takahe:latest
|
||||
environment:
|
||||
DJANGO_SETTINGS_MODULE: takahe.settings.development
|
||||
PGHOST: db
|
||||
PGDATABASE: takahe
|
||||
PGUSER: postgres
|
||||
PGPASSWORD: insecure_password
|
||||
TAKAHE_DATABASE_URL: "postgres://postgres:insecure_password@db/takahe"
|
||||
TAKAHE_DEBUG: true
|
||||
TAKAHE_SECRET_KEY: "insecure_secret"
|
||||
TAKAHE_CSRF_TRUSTED_ORIGINS: '["http://127.0.0.1:8000", "https://127.0.0.1:8000"]'
|
||||
TAKAHE_USE_PROXY_HEADERS: true
|
||||
TAKAHE_EMAIL_BACKEND: "console://console"
|
||||
TAKAHE_MAIN_DOMAIN: "example.com"
|
||||
TAKAHE_ENVIRONMENT: "development"
|
||||
networks:
|
||||
- external_network
|
||||
- internal_network
|
||||
|
|
|
@ -15,10 +15,10 @@ GUARDED_COMMANDS = [
|
|||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings.production")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings")
|
||||
|
||||
# Guard against running tests in arbitrary environments
|
||||
env_name = os.environ["DJANGO_SETTINGS_MODULE"].rsplit(".", 1)[-1]
|
||||
env_name = os.environ.get("TAKAHE_ENVIRONMENT", "development")
|
||||
if env_name in GUARDED_ENVIRONMENTS:
|
||||
for cmd in sys.argv:
|
||||
if cmd in GUARDED_COMMANDS:
|
||||
|
|
|
@ -14,3 +14,6 @@ django-storages[google,boto3]~=1.13.1
|
|||
whitenoise~=6.2.0
|
||||
sphinx~=5.3.0
|
||||
sentry-sdk~=1.11.0
|
||||
dj_database_url~=1.0.0
|
||||
python-dotenv~=0.21.0
|
||||
email-validator~=1.3.0
|
||||
|
|
|
@ -8,7 +8,7 @@ profile = black
|
|||
multi_line_output = 3
|
||||
|
||||
[tool:pytest]
|
||||
addopts = --tb=short --ds=takahe.settings.testing --import-mode=importlib
|
||||
addopts = --tb=short --ds=takahe.settings --import-mode=importlib
|
||||
filterwarnings =
|
||||
ignore:There is no current event loop
|
||||
|
||||
|
|
|
@ -11,6 +11,6 @@ import os
|
|||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings.production")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
import secrets
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
from typing import List, Literal, Optional, Union
|
||||
|
||||
import dj_database_url
|
||||
import sentry_sdk
|
||||
from pydantic import AnyUrl, BaseSettings, EmailStr, Field, PostgresDsn, validator
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def as_bool(v: Optional[Union[str, List[str]]]):
|
||||
if v is None:
|
||||
return False
|
||||
|
||||
if isinstance(v, str):
|
||||
v = [v]
|
||||
|
||||
return v[0].lower() in ("true", "yes", "t", "1")
|
||||
|
||||
|
||||
Environments = Literal["development", "production", "test"]
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""
|
||||
Pydantic-powered settings, to provide consistent error messages, strong
|
||||
typing, consistent prefixes, .venv support, etc.
|
||||
"""
|
||||
|
||||
#: The default database.
|
||||
DATABASE_URL: Optional[PostgresDsn]
|
||||
#: The currently running environment, used for things such as sentry
|
||||
#: error reporting.
|
||||
ENVIRONMENT: Environments = "development"
|
||||
#: Should django run in debug mode?
|
||||
DEBUG: bool = False
|
||||
#: Set a secret key used for signing values such as sessions. Randomized
|
||||
#: by default, so you'll logout everytime the process restarts.
|
||||
SECRET_KEY: str = Field(default_factory=lambda: secrets.token_hex(128))
|
||||
#: Set a secret key used to protect the stator. Randomized by default.
|
||||
STATOR_TOKEN: str = Field(default_factory=lambda: secrets.token_hex(128))
|
||||
|
||||
#: If set, a list of allowed values for the HOST header. The default value
|
||||
#: of '*' means any host will be accepted.
|
||||
ALLOWED_HOSTS: List[str] = Field(default_factory=lambda: ["*"])
|
||||
#: If set, a list of hosts to accept for CORS.
|
||||
CORS_HOSTS: List[str] = Field(default_factory=list)
|
||||
#: If set, a list of hosts to accept for CSRF.
|
||||
CSRF_HOSTS: List[str] = Field(default_factory=list)
|
||||
#: If enabled, trust the HTTP_X_FORWARDED_FOR header.
|
||||
USE_PROXY_HEADERS: bool = False
|
||||
|
||||
#: An optional Sentry DSN for error reporting.
|
||||
SENTRY_DSN: Optional[str] = None
|
||||
|
||||
#: Fallback domain for links.
|
||||
MAIN_DOMAIN: str = "example.com"
|
||||
|
||||
EMAIL_DSN: AnyUrl = "console://localhost"
|
||||
EMAIL_FROM: EmailStr = "test@example.com"
|
||||
AUTO_ADMIN_EMAIL: Optional[EmailStr] = None
|
||||
ERROR_EMAILS: Optional[List[EmailStr]] = None
|
||||
|
||||
MEDIA_URL: str = "/media/"
|
||||
MEDIA_ROOT: str = str(BASE_DIR / "MEDIA")
|
||||
MEDIA_BACKEND: Optional[AnyUrl] = None
|
||||
|
||||
PGHOST: Optional[str] = None
|
||||
PGPORT: int = 5432
|
||||
PGNAME: str = "takahe"
|
||||
PGUSER: str = "postgres"
|
||||
PGPASSWORD: Optional[str] = None
|
||||
|
||||
@validator("PGHOST", always=True)
|
||||
def validate_db(cls, PGHOST, values): # noqa
|
||||
if not values.get("DATABASE_URL") and not PGHOST:
|
||||
raise ValueError("Either DATABASE_URL or PGHOST are required.")
|
||||
return PGHOST
|
||||
|
||||
class Config:
|
||||
env_prefix = "TAKAHE_"
|
||||
env_file = str(BASE_DIR / ".env")
|
||||
env_file_encoding = "utf-8"
|
||||
# Case sensitivity doesn't work on Windows, so might as well be
|
||||
# consistent from the get-go.
|
||||
case_sensitive = False
|
||||
|
||||
# Override the env_prefix so these fields load without TAKAHE_
|
||||
fields = {
|
||||
"PGHOST": {"env": "PGHOST"},
|
||||
"PGPORT": {"env": "PGPORT"},
|
||||
"PGNAME": {"env": "PGNAME"},
|
||||
"PGUSER": {"env": "PGUSER"},
|
||||
"PGPASSWORD": {"env": "PGPASSWORD"},
|
||||
}
|
||||
|
||||
|
||||
SETUP = Settings()
|
||||
|
||||
SECRET_KEY = SETUP.SECRET_KEY
|
||||
DEBUG = SETUP.DEBUG
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_htmx",
|
||||
"core",
|
||||
"activities",
|
||||
"users",
|
||||
"stator",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"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_htmx.middleware.HtmxMiddleware",
|
||||
"core.middleware.ConfigLoadingMiddleware",
|
||||
"users.middleware.IdentityMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "takahe.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [BASE_DIR / "templates"],
|
||||
"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",
|
||||
"core.context.config_context",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "takahe.wsgi.application"
|
||||
|
||||
if SETUP.DATABASE_URL:
|
||||
DATABASES = {"default": dj_database_url.parse(SETUP.DATABASE_URL, conn_max_age=600)}
|
||||
else:
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
||||
"HOST": SETUP.PGHOST,
|
||||
"PORT": SETUP.PGPORT,
|
||||
"NAME": SETUP.PGNAME,
|
||||
"USER": SETUP.PGUSER,
|
||||
"PASSWORD": SETUP.PGPASSWORD,
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
},
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
LOGIN_URL = "/auth/login/"
|
||||
LOGOUT_URL = "/auth/logout/"
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
LOGOUT_REDIRECT_URL = "/"
|
||||
|
||||
STATICFILES_FINDERS = [
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||
]
|
||||
|
||||
STATICFILES_DIRS = [BASE_DIR / "static"]
|
||||
|
||||
STATIC_ROOT = BASE_DIR / "static-collected"
|
||||
|
||||
ALLOWED_HOSTS = SETUP.ALLOWED_HOSTS
|
||||
|
||||
AUTO_ADMIN_EMAIL = SETUP.AUTO_ADMIN_EMAIL
|
||||
|
||||
STATOR_TOKEN = SETUP.STATOR_TOKEN
|
||||
|
||||
CORS_ORIGIN_WHITELIST = SETUP.CORS_HOSTS
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
CORS_PREFLIGHT_MAX_AGE = 604800
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = SETUP.CSRF_HOSTS
|
||||
|
||||
MEDIA_URL = SETUP.MEDIA_URL
|
||||
MEDIA_ROOT = SETUP.MEDIA_ROOT
|
||||
MAIN_DOMAIN = SETUP.MAIN_DOMAIN
|
||||
|
||||
if SETUP.USE_PROXY_HEADERS:
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
|
||||
if SETUP.SENTRY_DSN:
|
||||
sentry_sdk.init(
|
||||
dsn=SETUP.SENTRY_DSN,
|
||||
integrations=[
|
||||
DjangoIntegration(),
|
||||
],
|
||||
traces_sample_rate=1.0,
|
||||
send_default_pii=True,
|
||||
environment=SETUP.ENVIRONMENT,
|
||||
)
|
||||
|
||||
SERVER_EMAIL = SETUP.EMAIL_FROM
|
||||
if SETUP.EMAIL_DSN:
|
||||
parsed = urllib.parse.urlparse(SETUP.EMAIL_DSN)
|
||||
query = urllib.parse.parse_qs(parsed.query)
|
||||
if parsed.scheme == "console":
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
elif parsed.scheme == "smtp":
|
||||
EMAIL_HOST = parsed.hostname
|
||||
EMAIL_PORT = parsed.port
|
||||
EMAIl_HOST_USER = parsed.username
|
||||
EMAIL_HOST_PASSWORD = parsed.password
|
||||
EMAIL_USE_TLS = as_bool(query.get("tls"))
|
||||
EMAIL_USE_SSL = as_bool(query.get("ssl"))
|
||||
else:
|
||||
raise ValueError("Unknown schema for EMAIL_DSN.")
|
||||
|
||||
|
||||
if SETUP.MEDIA_BACKEND:
|
||||
parsed = urllib.parse.urlparse(SETUP.MEDIA_BACKEND)
|
||||
query = urllib.parse.parse_qs(parsed.query)
|
||||
if parsed.scheme == "gcs":
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
|
||||
GS_BUCKET_NAME = parsed.path.lstrip("/")
|
||||
GS_QUERYSTRING_AUTH = False
|
||||
elif parsed.scheme == "s3":
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
AWS_STORAGE_BUCKET_NAME = parsed.path.lstrip("/")
|
||||
AWS_ACCESS_KEY_ID = parsed.username
|
||||
AWS_SECRET_ACCESS_KEY = parsed.password
|
||||
port = parsed.port or 443
|
||||
AWS_S3_ENDPOINT_URL = f"{parsed.hostname}:{port}"
|
||||
|
||||
if SETUP.ERROR_EMAILS:
|
||||
ADMINS = [("Admin", e) for e in SETUP.ERROR_EMAILS]
|
|
@ -1,120 +0,0 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_htmx",
|
||||
"core",
|
||||
"activities",
|
||||
"users",
|
||||
"stator",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"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_htmx.middleware.HtmxMiddleware",
|
||||
"core.middleware.ConfigLoadingMiddleware",
|
||||
"users.middleware.IdentityMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "takahe.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [BASE_DIR / "templates"],
|
||||
"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",
|
||||
"core.context.config_context",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "takahe.wsgi.application"
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
||||
"HOST": os.environ.get("PGHOST", "localhost"),
|
||||
"PORT": os.environ.get("PGPORT", 5432),
|
||||
"NAME": os.environ.get("PGDATABASE", "takahe"),
|
||||
"USER": os.environ.get("PGUSER", "postgres"),
|
||||
"PASSWORD": os.environ.get("PGPASSWORD"),
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
},
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
LOGIN_URL = "/auth/login/"
|
||||
LOGOUT_URL = "/auth/logout/"
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
LOGOUT_REDIRECT_URL = "/"
|
||||
|
||||
STATICFILES_FINDERS = [
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||
]
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / "static",
|
||||
]
|
||||
|
||||
STATIC_ROOT = BASE_DIR / "static-collected"
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
AUTO_ADMIN_EMAIL: Optional[str] = None
|
||||
|
||||
STATOR_TOKEN: Optional[str] = None
|
||||
|
||||
SENTRY_ENABLED = False
|
|
@ -1,28 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
from .base import * # noqa
|
||||
|
||||
# Load secret key from environment with a fallback
|
||||
SECRET_KEY = os.environ.get("TAKAHE_SECRET_KEY", "insecure_secret")
|
||||
|
||||
# Ensure debug features are on
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
"http://127.0.0.1:8000",
|
||||
"https://127.0.0.1:8000",
|
||||
]
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
SERVER_EMAIL = "test@example.com"
|
||||
|
||||
MAIN_DOMAIN = os.environ.get("TAKAHE_MAIN_DOMAIN", "example.com")
|
||||
if "/" in MAIN_DOMAIN:
|
||||
print("TAKAHE_MAIN_DOMAIN should be just the domain name - no https:// or path")
|
||||
sys.exit(1)
|
||||
|
||||
MEDIA_URL = os.environ.get("TAKAHE_MEDIA_URL", "/media/")
|
||||
MEDIA_ROOT = os.environ.get("TAKAHE_MEDIA_ROOT", BASE_DIR / "media")
|
|
@ -1,96 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from .base import * # noqa
|
||||
|
||||
# Ensure debug features are off
|
||||
DEBUG = bool(os.environ.get("TAKAHE__SECURITY_HAZARD__DEBUG", False))
|
||||
|
||||
# TODO: Allow better setting of allowed_hosts, if we need to
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
CONN_MAX_AGE = 60
|
||||
|
||||
### User-configurable options, pulled from the environment ###
|
||||
|
||||
# Secret key
|
||||
try:
|
||||
SECRET_KEY = os.environ["TAKAHE_SECRET_KEY"]
|
||||
except KeyError:
|
||||
print("You must specify the TAKAHE_SECRET_KEY environment variable!")
|
||||
sys.exit(1)
|
||||
|
||||
# SSL proxy header
|
||||
if "TAKAHE_SECURE_HEADER" in os.environ:
|
||||
SECURE_PROXY_SSL_HEADER = (
|
||||
"HTTP_" + os.environ["TAKAHE_SECURE_HEADER"].replace("-", "_").upper(),
|
||||
"https",
|
||||
)
|
||||
|
||||
# Fallback domain for links
|
||||
MAIN_DOMAIN = os.environ["TAKAHE_MAIN_DOMAIN"]
|
||||
if "/" in MAIN_DOMAIN:
|
||||
print("TAKAHE_MAIN_DOMAIN should be just the domain name - no https:// or path")
|
||||
sys.exit(1)
|
||||
|
||||
# Email config
|
||||
if os.environ.get("TAKAHE_EMAIL_CONSOLE_ONLY"):
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
SERVER_EMAIL = "test@example.com"
|
||||
else:
|
||||
SERVER_EMAIL = os.environ["TAKAHE_EMAIL_FROM"]
|
||||
if "TAKAHE_EMAIL_SENDGRID_KEY" in os.environ:
|
||||
EMAIL_HOST = "smtp.sendgrid.net"
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_HOST_USER: Optional[str] = "apikey"
|
||||
EMAIL_HOST_PASSWORD: Optional[str] = os.environ["TAKAHE_EMAIL_SENDGRID_KEY"]
|
||||
EMAIL_USE_TLS = True
|
||||
else:
|
||||
EMAIL_HOST = os.environ["TAKAHE_EMAIL_HOST"]
|
||||
EMAIL_PORT = int(os.environ["TAKAHE_EMAIL_PORT"])
|
||||
EMAIL_HOST_USER = os.environ.get("TAKAHE_EMAIL_USER")
|
||||
EMAIL_HOST_PASSWORD = os.environ.get("TAKAHE_EMAIL_PASSWORD")
|
||||
EMAIL_USE_SSL = EMAIL_PORT == 465
|
||||
EMAIL_USE_TLS = EMAIL_PORT == 587
|
||||
|
||||
AUTO_ADMIN_EMAIL = os.environ.get("TAKAHE_AUTO_ADMIN_EMAIL")
|
||||
|
||||
# Media storage
|
||||
MEDIA_BACKEND = os.environ.get("TAKAHE_MEDIA_BACKEND", None)
|
||||
if MEDIA_BACKEND == "local":
|
||||
# Note that this MUST be a fully qualified URL in production
|
||||
MEDIA_URL = os.environ.get("TAKAHE_MEDIA_URL", "/media/")
|
||||
MEDIA_ROOT = os.environ.get("TAKAHE_MEDIA_ROOT", BASE_DIR / "media")
|
||||
elif MEDIA_BACKEND == "gcs":
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
|
||||
GS_BUCKET_NAME = os.environ["TAKAHE_MEDIA_BUCKET"]
|
||||
GS_QUERYSTRING_AUTH = False
|
||||
elif MEDIA_BACKEND == "s3":
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
AWS_STORAGE_BUCKET_NAME = os.environ["TAKAHE_MEDIA_BUCKET"]
|
||||
else:
|
||||
print("Unknown TAKAHE_MEDIA_BACKEND value")
|
||||
sys.exit(1)
|
||||
|
||||
# Stator secret token
|
||||
STATOR_TOKEN = os.environ.get("TAKAHE_STATOR_TOKEN")
|
||||
|
||||
# Error email recipients
|
||||
if "TAKAHE_ERROR_EMAILS" in os.environ:
|
||||
ADMINS = [("Admin", e) for e in os.environ["TAKAHE_ERROR_EMAILS"].split(",")]
|
||||
|
||||
# Sentry integration
|
||||
if "SENTRY_DSN" in os.environ:
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn=os.environ["SENTRY_DSN"],
|
||||
integrations=[
|
||||
DjangoIntegration(),
|
||||
],
|
||||
traces_sample_rate=1.0,
|
||||
send_default_pii=True,
|
||||
)
|
||||
SENTRY_ENABLED = True
|
|
@ -1,6 +0,0 @@
|
|||
from .base import * # noqa
|
||||
|
||||
# Fixed secret key
|
||||
SECRET_KEY = "testing_secret"
|
||||
|
||||
MAIN_DOMAIN = "example.com"
|
|
@ -11,6 +11,6 @@ import os
|
|||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings.production")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "takahe.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
|
Loading…
Reference in New Issue