chore: deploy scripts + env
This commit is contained in:
@@ -13,23 +13,54 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# Optional: point this at a KEY=value file (see
|
||||
# deploy/supervisor/polylan-submitter.env.dist for the template, and
|
||||
# deploy/supervisor/polylan-submitter.conf for how it's wired up in
|
||||
# production) to fill in the env vars read throughout this file. override
|
||||
# =False so an already-exported env var always wins over the file - this
|
||||
# only fills gaps, same as every os.environ.get() below already treating a
|
||||
# merely-blank value as "use my own default" rather than "".
|
||||
if os.environ.get("SETTINGS_ENV_FILE_LOCATION"):
|
||||
load_dotenv(os.environ["SETTINGS_ENV_FILE_LOCATION"], override=False)
|
||||
|
||||
os.environ.setdefault("AWS_REQUEST_CHECKSUM_CALCULATION", "when_required")
|
||||
os.environ.setdefault("AWS_RESPONSE_CHECKSUM_VALIDATION", "when_required")
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||
#
|
||||
# All of the settings below that read from os.environ fall back to
|
||||
# quick-start/dev-friendly defaults when the env var is unset, EXCEPT
|
||||
# DJANGO_DEBUG, which defaults to False (secure by default per Django's own
|
||||
# deployment checklist) - export DJANGO_DEBUG=true for local development.
|
||||
#
|
||||
# These all use `os.environ.get(X) or default` rather than
|
||||
# `os.environ.get(X, default)`: an env var that's *defined but blank* (e.g.
|
||||
# systemd's EnvironmentFile represents "not configured" as `KEY=`, not by
|
||||
# omitting the line) must fall through to the default too, not become "".
|
||||
# That distinction matters a lot here - `int(os.environ.get("REDIS_PORT",
|
||||
# "6379"))` would still crash on an empty string.
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "django-insecure-m0ivj_3gpbf281jl1$&n5pdo!5le(bp4z31u(1&4s=n#!tpy=n"
|
||||
SECRET_KEY = (
|
||||
os.environ.get("DJANGO_SECRET_KEY")
|
||||
or "django-insecure-m0ivj_3gpbf281jl1$&n5pdo!5le(bp4z31u(1&4s=n#!tpy=n"
|
||||
)
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
|
||||
|
||||
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
|
||||
ALLOWED_HOSTS = [
|
||||
host
|
||||
for host in (os.environ.get("DJANGO_ALLOWED_HOSTS") or "127.0.0.1,localhost").split(",")
|
||||
if host
|
||||
]
|
||||
|
||||
|
||||
# Application definition
|
||||
@@ -58,6 +89,12 @@ INSTALLED_APPS = [
|
||||
"place",
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
# Was unconditionally added by settingsLocal.py before it was retired in
|
||||
# favor of env-var-driven settings; kept dev-only since it pulls in
|
||||
# shell_plus and similar dev tooling that has no place in production.
|
||||
INSTALLED_APPS += ["django_extensions"]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
@@ -95,13 +132,28 @@ ASGI_APPLICATION = "polylan_submitter.asgi.application"
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||
#
|
||||
# Falls back to sqlite (the quick-start default) when POSTGRES_DB isn't set,
|
||||
# so a fresh checkout with no env configured still works out of the box.
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
if os.environ.get("POSTGRES_DB"):
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"NAME": os.environ["POSTGRES_DB"],
|
||||
"USER": os.environ.get("POSTGRES_USER") or "postgres",
|
||||
"PASSWORD": os.environ.get("POSTGRES_PASSWORD", ""),
|
||||
"HOST": os.environ.get("POSTGRES_HOST") or "localhost",
|
||||
"PORT": os.environ.get("POSTGRES_PORT") or "5432",
|
||||
}
|
||||
}
|
||||
else:
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
@@ -156,15 +208,15 @@ AUTH_USER_MODEL = "accounts.CustomUser"
|
||||
CAS_SERVER_URL = "https://polylan.ch/cas/"
|
||||
|
||||
# Steam API Configuration
|
||||
STEAM_API_KEY = os.environ.get("STEAM_API_KEY", None) # Set via environment variable
|
||||
STEAM_API_KEY = os.environ.get("STEAM_API_KEY") or None # Set via environment variable
|
||||
|
||||
# Base URL of the legacy PolyLAN site, used to sync AAndT matches/members
|
||||
# (see submissions.services.aandt_sync)
|
||||
AANDT_API_BASE_URL = os.environ.get("AANDT_API_BASE_URL", "https://polylan.ch")
|
||||
AANDT_API_BASE_URL = os.environ.get("AANDT_API_BASE_URL") or "https://polylan.ch"
|
||||
|
||||
# Base URL of this site, used to build submission links pushed back to the
|
||||
# legacy AAndT match messages (see submissions.services.aandt_sync)
|
||||
SUBMITTER_BASE_URL = os.environ.get("SUBMITTER_BASE_URL", "http://localhost:7777")
|
||||
SUBMITTER_BASE_URL = os.environ.get("SUBMITTER_BASE_URL") or "http://localhost:7777"
|
||||
|
||||
# File Upload Settings
|
||||
MEDIA_URL = "/media/"
|
||||
@@ -174,11 +226,16 @@ MEDIA_ROOT = BASE_DIR / "media"
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 256 * 1024 * 1024 # 256MB
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 256 * 1024 * 1024 # 256MB
|
||||
|
||||
# Redis host/port shared by the cache, channel layer, RQ, and place's canvas
|
||||
# below - each still uses its own DB number, just on a common host.
|
||||
REDIS_HOST = os.environ.get("REDIS_HOST") or "127.0.0.1"
|
||||
REDIS_PORT = int(os.environ.get("REDIS_PORT") or "6379")
|
||||
|
||||
# Caching Configuration
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/11",
|
||||
"LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/11",
|
||||
"TIMEOUT": 300, # 5 minutes default
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
@@ -191,7 +248,7 @@ CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||
"CONFIG": {
|
||||
"hosts": [("127.0.0.1", 6379)],
|
||||
"hosts": [(REDIS_HOST, REDIS_PORT)],
|
||||
"serializer_format": "cjson",
|
||||
},
|
||||
},
|
||||
@@ -199,7 +256,7 @@ CHANNEL_LAYERS = {
|
||||
|
||||
# Redis for place's live pixel canvas (SETRANGE on the hot path - not a fit
|
||||
# for django-redis's cache API, so it gets its own raw redis-py client).
|
||||
PLACE_REDIS_URL = os.environ.get("PLACE_REDIS_URL", "redis://127.0.0.1:6379/15")
|
||||
PLACE_REDIS_URL = os.environ.get("PLACE_REDIS_URL") or f"redis://{REDIS_HOST}:{REDIS_PORT}/15"
|
||||
|
||||
# Django Tasks Configuration (with RQ backend)
|
||||
TASKS = {
|
||||
@@ -210,8 +267,8 @@ TASKS = {
|
||||
|
||||
RQ_QUEUES = {
|
||||
"default": {
|
||||
"HOST": "127.0.0.1",
|
||||
"PORT": 6379,
|
||||
"HOST": REDIS_HOST,
|
||||
"PORT": REDIS_PORT,
|
||||
"DB": 12,
|
||||
"DEFAULT_RESULT_TTL": 500,
|
||||
}
|
||||
@@ -228,7 +285,7 @@ ALLOWED_SUBMISSION_TYPES = [
|
||||
]
|
||||
|
||||
# Market app settings
|
||||
MARKET_ENABLED = os.environ.get("MARKET_ENABLED", "true").lower() == "true"
|
||||
MARKET_ENABLED = (os.environ.get("MARKET_ENABLED") or "true").lower() == "true"
|
||||
|
||||
# Authentication backends
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
@@ -243,7 +300,7 @@ LOGIN_REDIRECT_URL = "/"
|
||||
LOGOUT_REDIRECT_URL = "/"
|
||||
DJANGO_VITE = {
|
||||
"default": {
|
||||
"dev_mode": False,
|
||||
"dev_mode": DEBUG,
|
||||
}
|
||||
}
|
||||
STATIC_URL = "/static/"
|
||||
@@ -253,24 +310,46 @@ STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static_source/vite"),
|
||||
]
|
||||
|
||||
# Submission/media uploads always go to S3 - there's no local fallback for
|
||||
# that, so these must be set (via env) wherever the app runs, dev included.
|
||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
||||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL") or "https://storage.polylan.ch"
|
||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME") or "dev-submissions"
|
||||
|
||||
_s3_storage_options = {
|
||||
"bucket_name": AWS_STORAGE_BUCKET_NAME,
|
||||
"endpoint_url": AWS_S3_ENDPOINT_URL,
|
||||
"access_key": AWS_ACCESS_KEY_ID,
|
||||
"secret_key": AWS_SECRET_ACCESS_KEY,
|
||||
}
|
||||
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND": "storages.backends.s3.S3Storage",
|
||||
"OPTIONS": _s3_storage_options,
|
||||
},
|
||||
# Static files are collected to local disk and served by WhiteNoise in
|
||||
# DEBUG (no need to push every CSS/JS tweak to S3 while developing);
|
||||
# production collects straight to S3 like everything else here.
|
||||
"staticfiles": {
|
||||
"BACKEND": "storages.backends.s3.S3Storage",
|
||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
if DEBUG
|
||||
else "storages.backends.s3.S3Storage",
|
||||
**({} if DEBUG else {"OPTIONS": _s3_storage_options}),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
SENTRY_ENVIRONMENT = "production"
|
||||
from polylan_submitter.settingsLocal import * # noqa
|
||||
|
||||
SENTRY_ENVIRONMENT = os.environ.get("SENTRY_ENVIRONMENT") or ("development" if DEBUG else "production")
|
||||
SENTRY_DSN = (
|
||||
os.environ.get("SENTRY_DSN") or "https://cc62a4ce3f3470890b43accf02cc6d8c@sentry2.polylan.ch/12"
|
||||
)
|
||||
|
||||
import sentry_sdk # noqa
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn="https://cc62a4ce3f3470890b43accf02cc6d8c@sentry2.polylan.ch/12",
|
||||
dsn=SENTRY_DSN,
|
||||
# Set traces_sample_rate to 1.0 to capture 100%
|
||||
# of transactions for tracing.
|
||||
traces_sample_rate=1.0,
|
||||
|
||||
Reference in New Issue
Block a user