core/settings.py
"""Django settings for wf_website project.
Generated by 'django-admin startproject' using Django 2.1.3.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import logging
import os
import sys
import dj_database_url
from django.contrib.messages import constants as messages_constants
from django.core.management.utils import get_random_secret_key
from dotenv import load_dotenv
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
load_dotenv()
# Disable logging while running tests
if len(sys.argv) > 1 and sys.argv[1] == "test":
logging.disable(logging.CRITICAL)
default_allowed_hosts = "127.0.0.1,localhost,westernfriend.eu.ngrok.io"
ALLOWED_HOSTS = os.getenv("DJANGO_ALLOWED_HOSTS", default_allowed_hosts).split(",")
default_csrf_trusted_origins = "http://127.0.0.1,https://127.0.0.1,http://localhost,https://localhost,https://westernfriend.eu.ngrok.io"
CSRF_TRUSTED_ORIGINS = os.getenv(
"DJANGO_CSRF_TRUSTED_ORIGINS",
default_csrf_trusted_origins,
).split(",")
CORE_DIR = os.path.dirname(__file__)
BASE_DIR = os.path.dirname(CORE_DIR)
SECURE_REFERRER_POLICY = "strict-origin"
# Allow PayPal to open up in-context pop-ups
SECURE_CROSS_ORIGIN_OPENER_POLICY = "same-origin-allow-popups"
DEBUG = os.getenv("DJANGO_DEBUG", "false").lower() in ("true", "1")
if DEBUG:
SECRET_KEY = "not-so-secret-key"
else:
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key())
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
"file": {
"level": "DEBUG",
"class": "logging.handlers.RotatingFileHandler",
"filename": os.path.join(BASE_DIR, "debug.log"),
"maxBytes": 1024 * 1024 * 5, # 5 MB
"backupCount": 5,
},
},
"formatters": {
"verbose": {
"format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
},
"root": {
"handlers": ["console", "file"],
"level": "WARNING",
},
"loggers": {
"django": {
"handlers": ["console", "file"],
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING"),
},
},
}
# if SENTRY_DSN is set, then we are running in production
if os.getenv("SENTRY_DSN"):
sentry_sdk.init(
dsn=os.getenv("SENTRY_DSN"),
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
profiles_sample_rate=0.3,
)
# Settings related to DigitalOcean Spaces
# Note: for now, we are using the AWS naming-convention from Boto3
USE_SPACES = os.getenv("DJANGO_USE_SPACES", "False") == "True"
AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME", "sfo3")
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
AWS_LOCATION = os.getenv("AWS_LOCATION", "static")
PUBLIC_MEDIA_LOCATION = os.getenv("PUBLIC_MEDIA_LOCATION", "media")
AWS_DEFAULT_ACL = "public-read"
AWS_S3_ENDPOINT_URL = f"https://{AWS_S3_REGION_NAME}.digitaloceanspaces.com"
AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=86400"}
STATIC_ROOT = os.path.join(BASE_DIR, "static_root")
AUTH_USER_MODEL = "accounts.User"
CART_SESSION_ID = "cart"
# PayPal settings
PAYPAL_CLIENT_ENVIRONMENT = os.getenv("PAYPAL_CLIENT_ENVIRONMENT", "sandbox")
PAYPAL_API_URL = (
"https://api-m.paypal.com"
if PAYPAL_CLIENT_ENVIRONMENT.lower() == "production"
else "https://api-m.sandbox.paypal.com"
)
PAYPAL_CLIENT_ID = os.getenv("PAYPAL_CLIENT_ID")
PAYPAL_CLIENT_SECRET = os.getenv("PAYPAL_CLIENT_SECRET")
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# Application definition
INSTALLED_APPS = [
# First party (apps from this project)
# keep-sorted start
"accounts",
"addresses",
"blocks",
"cart",
"cli",
"common",
"community",
"contact",
"documents",
"events",
"facets",
"forms",
"home",
"library",
"magazine",
"memorials",
"navigation",
"news",
"orders",
"pagination",
"payment.apps.PaymentConfig",
"paypal",
"search",
"store",
"subscription",
"tags",
"wf_pages",
# keep-sorted end
# Third party (apps that have been installed)
# keep-sorted start
"crispy_bootstrap5",
"crispy_forms",
"django_extensions",
"django_flatpickr",
"django_recaptcha",
"honeypot",
"modelcluster",
"storages",
"taggit",
"wagtail",
"wagtail.admin",
"wagtail.contrib.forms",
"wagtail.contrib.redirects",
"wagtail.contrib.routable_page",
"wagtail.contrib.settings",
"wagtail.contrib.styleguide",
"wagtail.documents",
"wagtail.embeds",
"wagtail.images",
"wagtail.search",
"wagtail.sites",
"wagtail.snippets",
"wagtail.users",
"wagtail_color_panel",
"wagtailmedia",
# keep-sorted end
# Contrib (apps that are included in Django)
# keep-sorted start
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.messages",
"django.contrib.sessions",
"django.contrib.sitemaps",
"django.contrib.staticfiles",
# keep-sorted end
]
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
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",
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
]
X_FRAME_OPTIONS = "SAMEORIGIN"
ROOT_URLCONF = "core.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(CORE_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",
"wagtail.contrib.settings.context_processors.settings",
],
"debug": DEBUG,
},
},
]
WSGI_APPLICATION = "core.wsgi.application"
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASE_URL = os.getenv("DATABASE_URL")
NOT_COLLECTING_STATICFILES = len(sys.argv) > 1 and sys.argv[1] != "collectstatic"
if DATABASE_URL:
DATABASES = {"default": dj_database_url.parse(DATABASE_URL)}
else:
# Default to using local development environment
if NOT_COLLECTING_STATICFILES:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "wf_website",
"USER": "postgres",
"PASSWORD": "postgres",
"HOST": "localhost",
"PORT": "5432",
},
}
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
WAGTAILSEARCH_BACKENDS = {
"default": {
"BACKEND": "wagtail.search.backends.database",
},
}
WAGTAILEMBEDS_FINDERS = [
{
"class": "wagtail.embeds.finders.oembed",
},
]
# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa: E501
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
LOGIN_REDIRECT_URL = "/"
# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
WAGTAIL_I18N_ENABLED = True
USE_TZ = True
TIME_ZONE = "America/Los_Angeles"
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
STATICFILES_DIRS = [
os.path.join(CORE_DIR, "static"),
]
if USE_SPACES:
STATIC_URL = f"{AWS_S3_ENDPOINT_URL}/{ AWS_STORAGE_BUCKET_NAME}/{AWS_LOCATION}/"
STORAGES = {
"default": {
"BACKEND": "core.storage_backends.MediaStorage",
},
"staticfiles": {
"BACKEND": "core.storage_backends.StaticStorage",
},
}
MEDIA_URL = (
f"{AWS_S3_ENDPOINT_URL}/{ AWS_STORAGE_BUCKET_NAME}/{PUBLIC_MEDIA_LOCATION}/"
)
# Prevent setting URL querystring parameters
# which are causing 403 errors on DigitalOcean Spaces
AWS_QUERYSTRING_AUTH = False
else:
STATIC_URL = "/static/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
# Wagtail settings
WAGTAIL_SITE_NAME = "Western Friend"
# Base URL to use when referring to full URLs within the Wagtail admin backend -
# e.g. in notification emails. Don't include '/admin' or a trailing slash
BASE_URL = "https://westernfriend.org"
# Registration settings
ACCOUNT_ACTIVATION_DAYS = 7
REGISTRATION_OPEN = True
REGISTRATION_SALT = "registration"
# Email settings
EMAIL_HOST = os.getenv("EMAIL_HOST", None)
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "587"))
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", None)
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", None)
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "True") == "True"
EMAIL_USE_SSL = (
os.getenv("EMAIL_USE_SSL", "False") == "True"
) # SSL is less secure than TLS
DEFAULT_FROM_EMAIL = os.getenv(
"DEFAULT_FROM_EMAIL",
"tech@westernfriend.org",
)
# if the EMAIL authentication environment variables are set,
# then we can use the SMTP backend
if (
EMAIL_HOST is not None
and EMAIL_HOST_USER is not None
and EMAIL_HOST_PASSWORD is not None
):
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
else:
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
WAGTAILADMIN_BASE_URL = "/admin"
INTERNAL_IPS = [
"127.0.0.1",
]
# Recaptcha settings
RECAPTCHA_PUBLIC_KEY = os.environ.get("RECAPTCHA_PUBLIC_KEY", "")
RECAPTCHA_PRIVATE_KEY = os.environ.get("RECAPTCHA_PRIVATE_KEY", "")
NOCAPTCHA = True
# Honeypot settings
HONEYPOT_FIELD_NAME = "email2"
MESSAGE_TAGS = {
messages_constants.DEBUG: "alert alert-secondary",
messages_constants.INFO: "alert alert-info",
messages_constants.SUCCESS: "alert alert-success",
messages_constants.WARNING: "alert alert-warning",
messages_constants.ERROR: "alert alert-danger",
}