2022-11-27 17:57:13 +00:00
|
|
|
|
import os
|
2022-11-26 17:04:04 +00:00
|
|
|
|
import secrets
|
2022-11-27 07:32:18 +00:00
|
|
|
|
import sys
|
2022-11-26 17:04:04 +00:00
|
|
|
|
import urllib.parse
|
|
|
|
|
from pathlib import Path
|
2022-12-05 17:38:37 +00:00
|
|
|
|
from typing import Literal
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
import dj_database_url
|
2022-12-05 17:55:30 +00:00
|
|
|
|
import django_cache_url
|
2022-12-07 04:59:05 +00:00
|
|
|
|
import httpx
|
2022-11-26 17:04:04 +00:00
|
|
|
|
import sentry_sdk
|
2023-07-25 00:54:58 +00:00
|
|
|
|
from corsheaders.defaults import default_headers
|
2022-12-01 16:53:45 +00:00
|
|
|
|
from pydantic import AnyUrl, BaseSettings, EmailStr, Field, validator
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-12-05 01:08:23 +00:00
|
|
|
|
from takahe import __version__
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
|
|
|
|
|
2022-12-05 17:55:30 +00:00
|
|
|
|
class CacheBackendUrl(AnyUrl):
|
|
|
|
|
host_required = False
|
|
|
|
|
allowed_schemes = django_cache_url.BACKENDS.keys()
|
|
|
|
|
|
|
|
|
|
|
2022-12-01 16:53:45 +00:00
|
|
|
|
class ImplicitHostname(AnyUrl):
|
|
|
|
|
host_required = False
|
|
|
|
|
|
|
|
|
|
|
2022-11-28 17:22:39 +00:00
|
|
|
|
class MediaBackendUrl(AnyUrl):
|
|
|
|
|
host_required = False
|
2023-11-26 18:13:55 +00:00
|
|
|
|
allowed_schemes = {"s3", "s3-insecure", "gs", "local"}
|
2022-11-28 17:22:39 +00:00
|
|
|
|
|
|
|
|
|
|
2022-12-05 17:38:37 +00:00
|
|
|
|
def as_bool(v: str | list[str] | None):
|
2022-11-26 17:04:04 +00:00
|
|
|
|
if v is None:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if isinstance(v, str):
|
|
|
|
|
v = [v]
|
|
|
|
|
|
|
|
|
|
return v[0].lower() in ("true", "yes", "t", "1")
|
|
|
|
|
|
|
|
|
|
|
2023-01-08 00:21:41 +00:00
|
|
|
|
Environments = Literal["debug", "development", "production", "test"]
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-11-27 17:57:13 +00:00
|
|
|
|
TAKAHE_ENV_FILE = os.environ.get(
|
|
|
|
|
"TAKAHE_ENV_FILE", "test.env" if "pytest" in sys.modules else ".env"
|
|
|
|
|
)
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
|
|
|
"""
|
|
|
|
|
Pydantic-powered settings, to provide consistent error messages, strong
|
|
|
|
|
typing, consistent prefixes, .venv support, etc.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
#: The default database.
|
2022-12-05 17:38:37 +00:00
|
|
|
|
DATABASE_SERVER: ImplicitHostname | None
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: The currently running environment, used for things such as sentry
|
|
|
|
|
#: error reporting.
|
|
|
|
|
ENVIRONMENT: Environments = "development"
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: Should django run in debug mode?
|
|
|
|
|
DEBUG: bool = False
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-12-27 23:53:49 +00:00
|
|
|
|
#: Should the debug toolbar be loaded?
|
2022-12-23 08:59:31 +00:00
|
|
|
|
DEBUG_TOOLBAR: bool = False
|
|
|
|
|
|
2022-12-27 23:53:49 +00:00
|
|
|
|
#: Should we atttempt to import the 'local_settings.py'
|
|
|
|
|
LOCAL_SETTINGS: bool = False
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: Set a secret key used for signing values such as sessions. Randomized
|
|
|
|
|
#: by default, so you'll logout everytime the process restarts.
|
2022-12-28 18:27:08 +00:00
|
|
|
|
SECRET_KEY: str = Field(default_factory=lambda: "autokey-" + secrets.token_hex(128))
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: 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.
|
2022-12-05 17:38:37 +00:00
|
|
|
|
ALLOWED_HOSTS: list[str] = Field(default_factory=lambda: ["*"])
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: If set, a list of hosts to accept for CORS.
|
2022-12-05 17:38:37 +00:00
|
|
|
|
CORS_HOSTS: list[str] = Field(default_factory=list)
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: If set, a list of hosts to accept for CSRF.
|
2022-12-05 17:38:37 +00:00
|
|
|
|
CSRF_HOSTS: list[str] = Field(default_factory=list)
|
2022-11-26 18:33:33 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
#: If enabled, trust the HTTP_X_FORWARDED_FOR header.
|
|
|
|
|
USE_PROXY_HEADERS: bool = False
|
|
|
|
|
|
|
|
|
|
#: An optional Sentry DSN for error reporting.
|
2022-12-05 17:38:37 +00:00
|
|
|
|
SENTRY_DSN: str | None = None
|
2022-12-05 01:08:23 +00:00
|
|
|
|
SENTRY_SAMPLE_RATE: float = 1.0
|
2022-12-19 00:42:08 +00:00
|
|
|
|
SENTRY_TRACES_SAMPLE_RATE: float = 0.01
|
2022-12-06 16:50:42 +00:00
|
|
|
|
SENTRY_CAPTURE_MESSAGES: bool = False
|
2023-01-08 00:21:41 +00:00
|
|
|
|
SENTRY_EXPERIMENTAL_PROFILES_TRACES_SAMPLE_RATE: float = 0.0
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
#: Fallback domain for links.
|
|
|
|
|
MAIN_DOMAIN: str = "example.com"
|
|
|
|
|
|
2022-11-26 18:33:33 +00:00
|
|
|
|
EMAIL_SERVER: AnyUrl = "console://localhost"
|
2022-11-26 17:04:04 +00:00
|
|
|
|
EMAIL_FROM: EmailStr = "test@example.com"
|
2022-12-05 17:38:37 +00:00
|
|
|
|
AUTO_ADMIN_EMAIL: EmailStr | None = None
|
|
|
|
|
ERROR_EMAILS: list[EmailStr] | None = None
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2023-01-29 19:27:07 +00:00
|
|
|
|
#: If set, a list of user agents to completely disallow in robots.txt
|
|
|
|
|
#: List formatting must be a valid JSON list, such as `["Agent1", "Agent2"]`
|
|
|
|
|
ROBOTS_TXT_DISALLOWED_USER_AGENTS: list[str] = Field(default_factory=list)
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
MEDIA_URL: str = "/media/"
|
2022-11-26 18:33:33 +00:00
|
|
|
|
MEDIA_ROOT: str = str(BASE_DIR / "media")
|
2022-12-05 17:38:37 +00:00
|
|
|
|
MEDIA_BACKEND: MediaBackendUrl | None = None
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-12-22 20:47:13 +00:00
|
|
|
|
#: S3 ACL to apply to all media objects when MEDIA_BACKEND is set to S3. If using a CDN
|
|
|
|
|
#: and/or have public access blocked to buckets this will likely need to be 'private'
|
|
|
|
|
MEDIA_BACKEND_S3_ACL: str = "public-read"
|
|
|
|
|
|
2022-12-05 01:20:50 +00:00
|
|
|
|
#: Maximum filesize when uploading images. Increasing this may increase memory utilization
|
|
|
|
|
#: because all images with a dimension greater than 2000px are resized to meet that limit, which
|
|
|
|
|
#: is necessary for compatibility with Mastodon’s image proxy.
|
|
|
|
|
MEDIA_MAX_IMAGE_FILESIZE_MB: int = 10
|
|
|
|
|
|
2022-12-17 19:53:13 +00:00
|
|
|
|
#: Maximum filesize for Avatars. Remote avatars larger than this size will
|
|
|
|
|
#: not be fetched and served from media, but served through the image proxy.
|
|
|
|
|
AVATAR_MAX_IMAGE_FILESIZE_KB: int = 1000
|
|
|
|
|
|
2022-12-15 07:50:54 +00:00
|
|
|
|
#: Maximum filesize for Emoji. Attempting to upload Local Emoji larger than this size will be
|
|
|
|
|
#: blocked. Remote Emoji larger than this size will not be fetched and served from media, but
|
|
|
|
|
#: served through the image proxy.
|
|
|
|
|
EMOJI_MAX_IMAGE_FILESIZE_KB: int = 200
|
|
|
|
|
|
2022-12-04 16:32:25 +00:00
|
|
|
|
#: Request timeouts to use when talking to other servers Either
|
|
|
|
|
#: float or tuple of floats for (connect, read, write, pool)
|
|
|
|
|
REMOTE_TIMEOUT: float | tuple[float, float, float, float] = 5.0
|
|
|
|
|
|
2022-12-01 16:53:45 +00:00
|
|
|
|
#: If search features like full text search should be enabled.
|
|
|
|
|
#: (placeholder setting, no effect)
|
|
|
|
|
SEARCH: bool = True
|
|
|
|
|
|
2022-12-05 17:55:30 +00:00
|
|
|
|
#: Default cache backend
|
|
|
|
|
CACHES_DEFAULT: CacheBackendUrl | None = None
|
|
|
|
|
|
2023-10-01 16:17:00 +00:00
|
|
|
|
# How long to wait, in days, until remote posts/profiles are pruned from
|
2023-11-13 01:01:01 +00:00
|
|
|
|
# our database if nobody local has interacted with them.
|
|
|
|
|
# Set to zero to disable.
|
|
|
|
|
REMOTE_PRUNE_HORIZON: int = 90
|
2023-10-01 16:17:00 +00:00
|
|
|
|
|
2022-12-20 08:02:35 +00:00
|
|
|
|
# Stator tuning
|
2023-11-13 17:39:21 +00:00
|
|
|
|
STATOR_CONCURRENCY: int = 20
|
|
|
|
|
STATOR_CONCURRENCY_PER_MODEL: int = 4
|
2022-12-20 08:02:35 +00:00
|
|
|
|
|
2023-11-09 18:58:40 +00:00
|
|
|
|
# If user migration is allowed (off by default until outbound is done)
|
|
|
|
|
ALLOW_USER_MIGRATION: bool = False
|
|
|
|
|
|
2023-07-15 18:37:34 +00:00
|
|
|
|
# Web Push keys
|
|
|
|
|
# Generate via https://web-push-codelab.glitch.me/
|
|
|
|
|
VAPID_PUBLIC_KEY: str | None = None
|
|
|
|
|
VAPID_PRIVATE_KEY: str | None = None
|
|
|
|
|
|
2022-12-05 17:38:37 +00:00
|
|
|
|
PGHOST: str | None = None
|
|
|
|
|
PGPORT: int | None = 5432
|
2022-11-26 17:04:04 +00:00
|
|
|
|
PGNAME: str = "takahe"
|
|
|
|
|
PGUSER: str = "postgres"
|
2022-12-05 17:38:37 +00:00
|
|
|
|
PGPASSWORD: str | None = None
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
@validator("PGHOST", always=True)
|
|
|
|
|
def validate_db(cls, PGHOST, values): # noqa
|
2022-11-26 18:33:33 +00:00
|
|
|
|
if not values.get("DATABASE_SERVER") and not PGHOST:
|
|
|
|
|
raise ValueError("Either DATABASE_SERVER or PGHOST are required.")
|
2022-11-26 17:04:04 +00:00
|
|
|
|
return PGHOST
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
env_prefix = "TAKAHE_"
|
2022-11-27 17:57:13 +00:00
|
|
|
|
env_file = str(BASE_DIR / TAKAHE_ENV_FILE)
|
2022-11-26 17:04:04 +00:00
|
|
|
|
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"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-11-27 17:57:13 +00:00
|
|
|
|
SETUP = Settings()
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-12-28 18:27:08 +00:00
|
|
|
|
# Don't allow automatic keys in production
|
2022-12-29 03:08:52 +00:00
|
|
|
|
if not SETUP.DEBUG and SETUP.SECRET_KEY.startswith("autokey-"):
|
2022-12-28 18:27:08 +00:00
|
|
|
|
print("You must set TAKAHE_SECRET_KEY in production")
|
|
|
|
|
sys.exit(1)
|
2022-11-26 17:04:04 +00:00
|
|
|
|
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",
|
2023-05-04 04:42:37 +00:00
|
|
|
|
"django.contrib.postgres",
|
2022-12-11 04:03:14 +00:00
|
|
|
|
"corsheaders",
|
2022-12-20 15:26:39 +00:00
|
|
|
|
"django_htmx",
|
2023-02-14 02:04:30 +00:00
|
|
|
|
"hatchway",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
"core",
|
|
|
|
|
"activities",
|
2022-12-11 04:03:14 +00:00
|
|
|
|
"api",
|
2022-12-10 19:16:08 +00:00
|
|
|
|
"mediaproxy",
|
2022-12-11 04:03:14 +00:00
|
|
|
|
"stator",
|
|
|
|
|
"users",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
MIDDLEWARE = [
|
2022-12-05 01:08:23 +00:00
|
|
|
|
"core.middleware.SentryTaggingMiddleware",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
"django.middleware.security.SecurityMiddleware",
|
2022-12-11 04:03:14 +00:00
|
|
|
|
"corsheaders.middleware.CorsMiddleware",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
"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",
|
2022-12-15 07:35:04 +00:00
|
|
|
|
"core.middleware.HeadersMiddleware",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
"core.middleware.ConfigLoadingMiddleware",
|
2022-12-11 07:25:48 +00:00
|
|
|
|
"api.middleware.ApiTokenMiddleware",
|
2023-05-04 04:42:37 +00:00
|
|
|
|
"users.middleware.DomainMiddleware",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
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",
|
2023-01-13 22:54:21 +00:00
|
|
|
|
"users.context.user_context",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
WSGI_APPLICATION = "takahe.wsgi.application"
|
|
|
|
|
|
2022-11-26 18:33:33 +00:00
|
|
|
|
if SETUP.DATABASE_SERVER:
|
|
|
|
|
DATABASES = {
|
|
|
|
|
"default": dj_database_url.parse(SETUP.DATABASE_SERVER, conn_max_age=600)
|
|
|
|
|
}
|
2022-11-26 17:04:04 +00:00
|
|
|
|
else:
|
|
|
|
|
DATABASES = {
|
|
|
|
|
"default": {
|
2022-12-05 21:44:50 +00:00
|
|
|
|
"ENGINE": "django.db.backends.postgresql",
|
2022-11-26 17:04:04 +00:00
|
|
|
|
"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"]
|
|
|
|
|
|
2023-05-08 05:08:33 +00:00
|
|
|
|
STORAGES = {
|
|
|
|
|
"staticfiles": {
|
|
|
|
|
"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
|
|
|
|
},
|
2023-05-08 16:40:33 +00:00
|
|
|
|
"default": {
|
|
|
|
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
|
|
|
|
},
|
2023-05-08 05:08:33 +00:00
|
|
|
|
}
|
2022-12-15 07:35:04 +00:00
|
|
|
|
|
2022-12-15 22:55:33 +00:00
|
|
|
|
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
|
|
|
|
|
|
2022-12-15 07:35:04 +00:00
|
|
|
|
WHITENOISE_MAX_AGE = 3600
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
STATIC_ROOT = BASE_DIR / "static-collected"
|
|
|
|
|
|
|
|
|
|
ALLOWED_HOSTS = SETUP.ALLOWED_HOSTS
|
|
|
|
|
|
|
|
|
|
AUTO_ADMIN_EMAIL = SETUP.AUTO_ADMIN_EMAIL
|
|
|
|
|
|
|
|
|
|
STATOR_TOKEN = SETUP.STATOR_TOKEN
|
2022-12-20 08:02:35 +00:00
|
|
|
|
STATOR_CONCURRENCY = SETUP.STATOR_CONCURRENCY
|
|
|
|
|
STATOR_CONCURRENCY_PER_MODEL = SETUP.STATOR_CONCURRENCY_PER_MODEL
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2023-01-29 19:27:07 +00:00
|
|
|
|
ROBOTS_TXT_DISALLOWED_USER_AGENTS = SETUP.ROBOTS_TXT_DISALLOWED_USER_AGENTS
|
|
|
|
|
|
2022-12-11 04:03:14 +00:00
|
|
|
|
CORS_ORIGIN_ALLOW_ALL = True # Temporary
|
2022-11-26 17:04:04 +00:00
|
|
|
|
CORS_ORIGIN_WHITELIST = SETUP.CORS_HOSTS
|
|
|
|
|
CORS_ALLOW_CREDENTIALS = True
|
|
|
|
|
CORS_PREFLIGHT_MAX_AGE = 604800
|
2023-05-02 15:57:12 +00:00
|
|
|
|
CORS_EXPOSE_HEADERS = ("link",)
|
2023-07-25 00:54:58 +00:00
|
|
|
|
CORS_ALLOW_HEADERS = (*default_headers, "Idempotency-Key")
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-12-28 03:01:00 +00:00
|
|
|
|
JSONLD_MAX_SIZE = 1024 * 50 # 50 KB
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
CSRF_TRUSTED_ORIGINS = SETUP.CSRF_HOSTS
|
|
|
|
|
|
|
|
|
|
MEDIA_URL = SETUP.MEDIA_URL
|
|
|
|
|
MEDIA_ROOT = SETUP.MEDIA_ROOT
|
|
|
|
|
MAIN_DOMAIN = SETUP.MAIN_DOMAIN
|
|
|
|
|
|
2023-01-14 19:18:35 +00:00
|
|
|
|
if not DEBUG and MAIN_DOMAIN == "example.com":
|
|
|
|
|
raise ValueError("You must set a TAKAHE_MAIN_DOMAIN!")
|
|
|
|
|
|
2022-12-21 22:14:41 +00:00
|
|
|
|
# Debug toolbar should only be loaded at all when debug is on
|
2022-12-23 08:59:31 +00:00
|
|
|
|
if DEBUG and SETUP.DEBUG_TOOLBAR:
|
2022-12-21 22:14:41 +00:00
|
|
|
|
INSTALLED_APPS.append("debug_toolbar")
|
2022-12-20 15:26:39 +00:00
|
|
|
|
DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": "core.middleware.show_toolbar"}
|
2022-12-21 22:14:41 +00:00
|
|
|
|
MIDDLEWARE.insert(8, "debug_toolbar.middleware.DebugToolbarMiddleware")
|
2022-12-11 04:03:14 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
if SETUP.USE_PROXY_HEADERS:
|
|
|
|
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if SETUP.SENTRY_DSN:
|
2023-10-23 16:33:55 +00:00
|
|
|
|
from sentry_sdk.integrations.django import DjangoIntegration
|
2023-01-04 23:41:27 +00:00
|
|
|
|
from sentry_sdk.integrations.httpx import HttpxIntegration
|
2023-10-23 16:33:55 +00:00
|
|
|
|
from sentry_sdk.integrations.logging import LoggingIntegration
|
2023-01-04 23:41:27 +00:00
|
|
|
|
|
2023-01-08 00:21:41 +00:00
|
|
|
|
sentry_experiments = {}
|
|
|
|
|
|
|
|
|
|
if SETUP.SENTRY_EXPERIMENTAL_PROFILES_TRACES_SAMPLE_RATE > 0:
|
|
|
|
|
sentry_experiments[
|
|
|
|
|
"profiles_sample_rate"
|
|
|
|
|
] = SETUP.SENTRY_EXPERIMENTAL_PROFILES_TRACES_SAMPLE_RATE
|
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
sentry_sdk.init(
|
|
|
|
|
dsn=SETUP.SENTRY_DSN,
|
|
|
|
|
integrations=[
|
|
|
|
|
DjangoIntegration(),
|
2023-01-04 23:41:27 +00:00
|
|
|
|
HttpxIntegration(),
|
2023-10-23 16:33:55 +00:00
|
|
|
|
LoggingIntegration(),
|
2022-11-26 17:04:04 +00:00
|
|
|
|
],
|
2022-12-05 01:08:23 +00:00
|
|
|
|
traces_sample_rate=SETUP.SENTRY_TRACES_SAMPLE_RATE,
|
|
|
|
|
sample_rate=SETUP.SENTRY_SAMPLE_RATE,
|
2022-11-26 17:04:04 +00:00
|
|
|
|
send_default_pii=True,
|
|
|
|
|
environment=SETUP.ENVIRONMENT,
|
2023-01-08 00:21:41 +00:00
|
|
|
|
_experiments=sentry_experiments,
|
2022-11-26 17:04:04 +00:00
|
|
|
|
)
|
2022-12-05 01:08:23 +00:00
|
|
|
|
sentry_sdk.set_tag("takahe.version", __version__)
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
SERVER_EMAIL = SETUP.EMAIL_FROM
|
2022-11-26 18:33:33 +00:00
|
|
|
|
if SETUP.EMAIL_SERVER:
|
|
|
|
|
parsed = urllib.parse.urlparse(SETUP.EMAIL_SERVER)
|
2022-11-26 17:04:04 +00:00
|
|
|
|
query = urllib.parse.parse_qs(parsed.query)
|
|
|
|
|
if parsed.scheme == "console":
|
|
|
|
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
2022-11-26 18:33:33 +00:00
|
|
|
|
elif parsed.scheme == "sendgrid":
|
|
|
|
|
EMAIL_HOST = "smtp.sendgrid.net"
|
|
|
|
|
EMAIL_PORT = 587
|
|
|
|
|
EMAIL_HOST_USER = "apikey"
|
2022-11-28 00:30:33 +00:00
|
|
|
|
# urlparse will lowercase it
|
|
|
|
|
EMAIL_HOST_PASSWORD = SETUP.EMAIL_SERVER.split("://")[1]
|
2022-11-26 18:33:33 +00:00
|
|
|
|
EMAIL_USE_TLS = True
|
2022-11-26 17:04:04 +00:00
|
|
|
|
elif parsed.scheme == "smtp":
|
|
|
|
|
EMAIL_HOST = parsed.hostname
|
|
|
|
|
EMAIL_PORT = parsed.port
|
2023-07-14 19:57:58 +00:00
|
|
|
|
if parsed.username is not None:
|
|
|
|
|
EMAIL_HOST_USER = urllib.parse.unquote(parsed.username)
|
|
|
|
|
if parsed.password is not None:
|
|
|
|
|
EMAIL_HOST_PASSWORD = urllib.parse.unquote(parsed.password)
|
2022-11-26 17:04:04 +00:00
|
|
|
|
EMAIL_USE_TLS = as_bool(query.get("tls"))
|
|
|
|
|
EMAIL_USE_SSL = as_bool(query.get("ssl"))
|
|
|
|
|
else:
|
2022-11-26 18:33:33 +00:00
|
|
|
|
raise ValueError("Unknown schema for EMAIL_SERVER.")
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if SETUP.MEDIA_BACKEND:
|
|
|
|
|
parsed = urllib.parse.urlparse(SETUP.MEDIA_BACKEND)
|
|
|
|
|
query = urllib.parse.parse_qs(parsed.query)
|
2022-12-15 04:21:18 +00:00
|
|
|
|
if parsed.scheme == "gs":
|
2023-05-08 16:40:33 +00:00
|
|
|
|
STORAGES["default"]["BACKEND"] = "core.uploads.TakaheGoogleCloudStorage"
|
2022-12-15 04:21:18 +00:00
|
|
|
|
GS_BUCKET_NAME = parsed.path.lstrip("/")
|
2022-11-26 17:04:04 +00:00
|
|
|
|
GS_QUERYSTRING_AUTH = False
|
2022-12-15 04:21:18 +00:00
|
|
|
|
if parsed.hostname is not None:
|
|
|
|
|
port = parsed.port or 443
|
|
|
|
|
GS_CUSTOM_ENDPOINT = f"https://{parsed.hostname}:{port}"
|
2023-11-18 04:49:06 +00:00
|
|
|
|
elif (parsed.scheme == "s3") or (parsed.scheme == "s3-insecure"):
|
2023-05-08 16:40:33 +00:00
|
|
|
|
STORAGES["default"]["BACKEND"] = "core.uploads.TakaheS3Storage"
|
2022-11-26 17:04:04 +00:00
|
|
|
|
AWS_STORAGE_BUCKET_NAME = parsed.path.lstrip("/")
|
2022-12-01 16:43:36 +00:00
|
|
|
|
AWS_QUERYSTRING_AUTH = False
|
2022-12-22 20:47:13 +00:00
|
|
|
|
AWS_DEFAULT_ACL = SETUP.MEDIA_BACKEND_S3_ACL
|
2022-11-28 17:22:39 +00:00
|
|
|
|
if parsed.username is not None:
|
|
|
|
|
AWS_ACCESS_KEY_ID = parsed.username
|
2022-11-29 16:32:38 +00:00
|
|
|
|
AWS_SECRET_ACCESS_KEY = urllib.parse.unquote(parsed.password)
|
2022-11-28 17:22:39 +00:00
|
|
|
|
if parsed.hostname is not None:
|
2023-11-18 04:49:06 +00:00
|
|
|
|
if parsed.scheme == "s3-insecure":
|
|
|
|
|
s3_default_port = 80
|
|
|
|
|
s3_scheme = "http"
|
|
|
|
|
else:
|
|
|
|
|
s3_default_port = 443
|
|
|
|
|
s3_scheme = "https"
|
|
|
|
|
port = parsed.port or s3_default_port
|
|
|
|
|
AWS_S3_ENDPOINT_URL = f"{s3_scheme}://{parsed.hostname}:{port}"
|
2022-12-18 21:04:46 +00:00
|
|
|
|
if SETUP.MEDIA_URL is not None:
|
|
|
|
|
media_url_parsed = urllib.parse.urlparse(SETUP.MEDIA_URL)
|
|
|
|
|
AWS_S3_CUSTOM_DOMAIN = media_url_parsed.hostname
|
2022-11-29 04:26:02 +00:00
|
|
|
|
elif parsed.scheme == "local":
|
|
|
|
|
if not (MEDIA_ROOT and MEDIA_URL):
|
|
|
|
|
raise ValueError(
|
|
|
|
|
"You must provide MEDIA_ROOT and MEDIA_URL for a local media backend"
|
|
|
|
|
)
|
2023-01-01 17:46:06 +00:00
|
|
|
|
if "://" not in MEDIA_URL and not DEBUG:
|
|
|
|
|
raise ValueError(
|
|
|
|
|
"The MEDIA_URL setting must start with https://your-domain"
|
|
|
|
|
)
|
2022-11-26 18:33:33 +00:00
|
|
|
|
else:
|
|
|
|
|
raise ValueError(f"Unsupported media backend {parsed.scheme}")
|
2022-11-26 17:04:04 +00:00
|
|
|
|
|
2022-12-10 19:16:08 +00:00
|
|
|
|
CACHES = {
|
|
|
|
|
"default": django_cache_url.parse(SETUP.CACHES_DEFAULT or "dummy://"),
|
|
|
|
|
}
|
2022-12-05 17:55:30 +00:00
|
|
|
|
|
2022-11-26 17:04:04 +00:00
|
|
|
|
if SETUP.ERROR_EMAILS:
|
|
|
|
|
ADMINS = [("Admin", e) for e in SETUP.ERROR_EMAILS]
|
2022-12-07 04:59:05 +00:00
|
|
|
|
|
|
|
|
|
TAKAHE_USER_AGENT = (
|
|
|
|
|
f"python-httpx/{httpx.__version__} "
|
|
|
|
|
f"(Takahe/{__version__}; +https://{SETUP.MAIN_DOMAIN}/)"
|
|
|
|
|
)
|
2022-12-27 23:53:49 +00:00
|
|
|
|
|
|
|
|
|
if SETUP.LOCAL_SETTINGS:
|
|
|
|
|
# Let any errors bubble up
|
|
|
|
|
from .local_settings import * # noqa
|