423 lines
12 KiB
Python
423 lines
12 KiB
Python
import os
|
|
import sys
|
|
|
|
import dj_database_url
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from dotenv import find_dotenv, load_dotenv
|
|
|
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
|
from core.env_utils import bool_value
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
load_dotenv(find_dotenv())
|
|
|
|
# Quick-start development settings - unsuitable for production
|
|
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
|
|
|
# SECURITY WARNING: keep the secret key used in production secret!
|
|
SECRET_KEY = os.environ.get("SECRET_KEY")
|
|
SIGNING_SECRET = os.environ.get("SIGNING_SECRET")
|
|
|
|
# SECURITY WARNING: don't run with debug turned on in production!
|
|
DEBUG = bool_value(os.environ.get("DEBUG", ""))
|
|
TEST = "test" in sys.argv
|
|
ENABLE_SILKY = bool_value(os.environ.get("ENABLE_SILKY", ""))
|
|
SERVE_VIA_WEBPACK = bool_value(os.environ.get("SERVE_VIA_WEBPACK", DEBUG))
|
|
ENABLE_SENTRY = not DEBUG or bool_value(os.environ.get("ENABLE_SENTRY_DEBUG", ""))
|
|
|
|
ALLOWED_HOSTS = ["*"]
|
|
|
|
if not DEBUG:
|
|
SECURE_SSL_REDIRECT = True
|
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
|
|
# Application definition
|
|
|
|
|
|
INSTALLED_APPS = [
|
|
"core",
|
|
"api",
|
|
"users",
|
|
"books",
|
|
"objectives",
|
|
"rooms",
|
|
"assignments",
|
|
"basicknowledge",
|
|
"portfolio",
|
|
"statistics",
|
|
"surveys",
|
|
"notes",
|
|
"news",
|
|
"oauth",
|
|
"wagtail.contrib.redirects",
|
|
"wagtail.contrib.modeladmin",
|
|
"wagtail.embeds",
|
|
"wagtail.sites",
|
|
"wagtail.users",
|
|
"wagtail.snippets",
|
|
"wagtail.documents",
|
|
"wagtail.images",
|
|
"wagtail.search",
|
|
"wagtail.admin",
|
|
"wagtail",
|
|
"wagtail.api.v2",
|
|
"wagtailautocomplete",
|
|
"taggit",
|
|
"django.contrib.admin",
|
|
"django.contrib.auth",
|
|
"django.contrib.contenttypes",
|
|
"django.contrib.sessions",
|
|
"django.contrib.messages",
|
|
# 'raven.contrib.django.raven_compat',
|
|
"whitenoise.runserver_nostatic",
|
|
"django.contrib.staticfiles",
|
|
"django_filters",
|
|
"graphene_django",
|
|
"django_extensions",
|
|
"compressor",
|
|
]
|
|
|
|
if DEBUG:
|
|
INSTALLED_APPS += ["wagtail.contrib.styleguide"]
|
|
|
|
MIDDLEWARE = [
|
|
"django.middleware.security.SecurityMiddleware",
|
|
"whitenoise.middleware.WhiteNoiseMiddleware",
|
|
"django.middleware.gzip.GZipMiddleware",
|
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
|
"django.middleware.locale.LocaleMiddleware",
|
|
]
|
|
|
|
# Enable CORS for local development
|
|
if DEBUG:
|
|
INSTALLED_APPS += ["corsheaders"]
|
|
MIDDLEWARE += ["corsheaders.middleware.CorsMiddleware"]
|
|
CORS_ORIGIN_WHITELIST = ("http://localhost:8080",)
|
|
CORS_ALLOW_CREDENTIALS = True
|
|
|
|
# enable silk for performance measuring
|
|
if ENABLE_SILKY:
|
|
INSTALLED_APPS += ["silk"]
|
|
MIDDLEWARE += [
|
|
"silk.middleware.SilkyMiddleware",
|
|
]
|
|
|
|
MIDDLEWARE += [
|
|
"django.middleware.common.CommonMiddleware",
|
|
"django.middleware.csrf.CsrfViewMiddleware",
|
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
|
"django.contrib.messages.middleware.MessageMiddleware",
|
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
|
"core.middleware.ThreadLocalMiddleware",
|
|
"core.middleware.CommonRedirectMiddleware",
|
|
"core.middleware.UserLoggedInCookieMiddleWare",
|
|
"oauth.middleware.user_has_license_middleware",
|
|
]
|
|
|
|
ROOT_URLCONF = "core.urls"
|
|
|
|
TEMPLATES = [
|
|
{
|
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
"DIRS": [
|
|
os.path.join(BASE_DIR, "..", "client/dist"),
|
|
os.path.join(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_processors.settings_context",
|
|
],
|
|
},
|
|
},
|
|
]
|
|
|
|
WSGI_APPLICATION = "core.wsgi.application"
|
|
|
|
# Database
|
|
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
|
|
|
# Database
|
|
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}
|
|
|
|
# Django custom user
|
|
AUTH_USER_MODEL = "users.User"
|
|
|
|
# Password validation
|
|
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
|
|
|
WEAK_PASSWORDS = DEBUG
|
|
if WEAK_PASSWORDS:
|
|
AUTH_PASSWORD_VALIDATORS = []
|
|
else:
|
|
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",
|
|
},
|
|
]
|
|
|
|
LOGOUT_REDIRECT_URL = "/login"
|
|
LOGIN_REDIRECT_URL = "/login"
|
|
|
|
LOGIN_URL = LOGIN_REDIRECT_URL
|
|
|
|
# Internationalization
|
|
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
|
|
|
LANGUAGE_CODE = "de"
|
|
|
|
TIME_ZONE = "UTC"
|
|
|
|
USE_I18N = True
|
|
|
|
USE_L10N = True
|
|
|
|
USE_TZ = True
|
|
|
|
LANGUAGES = [
|
|
("de", _("German")),
|
|
("en", _("English")),
|
|
]
|
|
|
|
LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]
|
|
|
|
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
|
|
# Static files (CSS, JavaScript, Images)
|
|
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
|
|
|
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
|
STATIC_URL = "/static/"
|
|
|
|
STATICFILES_DIRS = (
|
|
os.path.join(BASE_DIR, "..", "client/dist"),
|
|
os.path.join(BASE_DIR, "..", "client/src/assets"),
|
|
)
|
|
|
|
if not TEST:
|
|
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
|
|
|
COMPRESS_CSS_FILTERS = [
|
|
# 'django_compressor_autoprefixer.AutoprefixerFilter',
|
|
"compressor.filters.cssmin.CSSMinFilter",
|
|
]
|
|
|
|
STATICFILES_FINDERS = (
|
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
|
"compressor.finders.CompressorFinder",
|
|
)
|
|
|
|
COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),)
|
|
|
|
COMPRESS_ENABLED = True
|
|
|
|
if not DEBUG:
|
|
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
|
COMPRESS_OFFLINE = True
|
|
|
|
# AWS S3
|
|
# http://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html
|
|
|
|
USE_AWS = bool_value(os.environ.get("USE_AWS"))
|
|
AWS_QUERYSTRING_AUTH = False
|
|
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
|
|
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
|
|
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
|
|
AWS_S3_FILE_OVERWRITE = False
|
|
|
|
# use with cloudfront
|
|
AWS_S3_CUSTOM_DOMAIN = "{}.s3-{}.amazonaws.com".format(
|
|
AWS_STORAGE_BUCKET_NAME, os.environ.get("AWS_REGION", "eu-west-1")
|
|
)
|
|
if USE_AWS:
|
|
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
|
# use with cloudfront
|
|
MEDIA_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN
|
|
else:
|
|
MEDIA_URL = "/media/"
|
|
MEDIA_ROOT = os.environ.get("DJANGO_MEDIAFILES", os.path.join(BASE_DIR, "media"))
|
|
|
|
AWS_S3_OBJECT_PARAMETERS = {
|
|
"CacheControl": "max-age=86400",
|
|
}
|
|
|
|
# Media Files
|
|
USE_404_FALLBACK_IMAGE = bool_value(os.environ.get("USE_404_FALLBACK_IMAGE", "True"))
|
|
|
|
# Logging Conf
|
|
|
|
LOGGING = {
|
|
"version": 1,
|
|
"formatters": {
|
|
"verbose_format": {
|
|
"format": "%(levelname)s %(asctime)s %(module)s %(name)s (%(process)d): %(message)s"
|
|
},
|
|
"simple_format": {"format": "%(levelname)s %(name)s: %(message)s"},
|
|
},
|
|
"disable_existing_loggers": not DEBUG,
|
|
"handlers": {
|
|
"mail_admins": {
|
|
"level": "CRITICAL",
|
|
"class": "django.utils.log.AdminEmailHandler",
|
|
},
|
|
"console": {
|
|
"level": "DEBUG",
|
|
"class": "logging.StreamHandler",
|
|
"stream": sys.stdout,
|
|
"formatter": "simple_format",
|
|
},
|
|
# for automatic papertrail logging
|
|
"SysLog": {
|
|
"level": "INFO",
|
|
"class": "logging.handlers.SysLogHandler",
|
|
"formatter": "simple_format",
|
|
},
|
|
},
|
|
"loggers": {
|
|
"": {"handlers": ["console"], "level": "WARNING"},
|
|
"skillbox": {
|
|
"handlers": ["console", "SysLog"],
|
|
"level": os.environ.get("DJANGO_LOG_LEVEL", "INFO"),
|
|
"propagate": False,
|
|
},
|
|
"graphql": {"handlers": ["console"], "level": "WARNING", "propagate": False},
|
|
"django": {
|
|
"handlers": ["console"],
|
|
"level": "INFO",
|
|
"propagate": False,
|
|
},
|
|
"django.server": {
|
|
"handlers": ["console"],
|
|
"level": "WARNING",
|
|
"propagate": False,
|
|
},
|
|
},
|
|
}
|
|
|
|
if ENABLE_SENTRY and os.environ.get("SENTRY_DSN"):
|
|
import sentry_sdk
|
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
from sentry_sdk.integrations.logging import ignore_logger
|
|
|
|
def before_send(event, hint):
|
|
user = event["user"]
|
|
id = user["id"]
|
|
event["user"] = {"id": id}
|
|
return event
|
|
|
|
environment = os.environ.get("SENTRY_ENV", "localhost")
|
|
sample_rate = os.environ.get("SENTRY_SAMPLE_RATE", 0.01)
|
|
|
|
sentry_sdk.init(
|
|
dsn=os.environ.get("SENTRY_DSN"),
|
|
integrations=[DjangoIntegration()],
|
|
send_default_pii=True,
|
|
before_send=before_send,
|
|
before_send_transaction=before_send,
|
|
environment=environment,
|
|
traces_sample_rate=sample_rate,
|
|
)
|
|
|
|
# ignore 'Traceback' error messages, they don't give enough information
|
|
# from https://jerrynsh.com/how-to-monitor-python-graphql-api-with-sentry/
|
|
ignore_logger("graphql.execution.utils")
|
|
|
|
RAVEN_DSN_JS = os.environ.get("RAVEN_DSN_JS", "")
|
|
|
|
GRAPHENE = {
|
|
"SCHEMA": "api.schema.schema",
|
|
"SCHEMA_OUTPUT": "schema.graphql",
|
|
"MIDDLEWARE": ["core.middleware.SentryMiddleware"],
|
|
}
|
|
|
|
# if DEBUG:
|
|
# GRAPHENE['MIDDLEWARE'] = [
|
|
# 'graphene_django.debug.DjangoDebugMiddleware',
|
|
# ]
|
|
|
|
# http://docs.wagtail.io/en/v2.1/advanced_topics/settings.html?highlight=urls
|
|
WAGTAIL_SITE_NAME = "skillbox"
|
|
WAGTAILSEARCH_BACKENDS = {
|
|
"default": {
|
|
"BACKEND": "wagtail.search.backends.database",
|
|
}
|
|
}
|
|
WAGTAILDOCS_DOCUMENT_MODEL = "books.CustomDocument"
|
|
|
|
|
|
GRAPHQL_QUERIES_DIR = os.path.join(
|
|
BASE_DIR, "..", "client", "src", "graphql", "gql", "queries"
|
|
)
|
|
GRAPHQL_MUTATIONS_DIR = os.path.join(GRAPHQL_QUERIES_DIR, "../mutations")
|
|
|
|
DEFAULT_FROM_EMAIL = "myskillbox <noreply@myskillbox.ch>"
|
|
|
|
# Metanet Config
|
|
if DEBUG:
|
|
EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
|
else:
|
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
|
|
|
ALLOW_BETA_LOGIN = True
|
|
|
|
# HEP
|
|
HEP_URL = os.environ.get("HEP_URL")
|
|
|
|
# HEP Oauth
|
|
AUTHLIB_OAUTH_CLIENTS = {
|
|
"hep": {
|
|
"client_id": os.environ.get("OAUTH_CLIENT_ID"),
|
|
"client_secret": os.environ.get("OAUTH_CLIENT_SECRET"),
|
|
"request_token_url": None,
|
|
"request_token_params": None,
|
|
"access_token_url": os.environ.get("OAUTH_ACCESS_TOKEN_URL"),
|
|
"access_token_params": None,
|
|
"refresh_token_url": None,
|
|
"authorize_url": os.environ.get("OAUTH_AUTHORIZE_URL"),
|
|
"api_base_url": os.environ.get("OAUTH_API_BASE_URL"),
|
|
"client_kwargs": {
|
|
"scope": "orders",
|
|
"token_endpoint_auth_method": "client_secret_post",
|
|
"token_placement": "header",
|
|
},
|
|
}
|
|
}
|
|
|
|
PLATFORM = os.environ.get("APP_FLAVOR", "myskillbox")
|
|
|
|
OAUTH_LOCAL_REDIRECT_URI = os.environ.get("OAUTH_LOCAL_REDIRECT_URI")
|
|
|
|
TASKBASE_USER = os.environ.get("TASKBASE_USER")
|
|
TASKBASE_PASSWORD = os.environ.get("TASKBASE_PASSWORD")
|
|
TASKBASE_SUPERUSER = os.environ.get("TASKBASE_SUPERUSER")
|
|
TASKBASE_SUPERPASSWORD = os.environ.get("TASKBASE_SUPERPASSWORD")
|
|
TASKBASE_BASEURL = os.environ.get("TASKBASE_BASEURL")
|
|
ENABLE_SPELLCHECK = True if TASKBASE_BASEURL else False
|
|
|
|
TEST_RUNNER = "xmlrunner.extra.djangotestrunner.XMLTestRunner"
|
|
TEST_OUTPUT_DIR = "./test-reports/"
|
|
TEST_OUTPUT_VERBOSE = 1
|
|
|
|
# new default in Django 3.0, making it explicit to facilitate bug hunting
|
|
X_FRAME_OPTIONS = "DENY"
|
|
SECURE_CONTENT_TYPE_NOSNIFF = True
|
|
# Django 3.2 uses BitAutoField by default, we keep things the old way
|
|
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|