extensions-website/blender_extensions/settings.py
Dalai Felinto 4ef93583a2 API Tokens (#134)
This allows users to create tokens to be used with the API.

The goal is to use those for the API that will allow users to upload new versions of an extension.

The Tokens can be created/managed on the user profile.

Note: The API entries that to actually use these tokens is handled separately on !138.

Ref !134
Reviewed-by: Oleg-Komarov
2024-05-27 12:53:29 +02:00

339 lines
9.8 KiB
Python

"""Django settings for blender_extensions project.
Generated by 'django-admin startproject' using Django 4.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
import os
import sys
import dj_database_url
TESTING = sys.argv[1:2] == ['test']
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
ADMIN_SITE_HEADER = 'Blender Extensions Admin'
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get(
'SECRET_KEY',
'django-insecure-@!bx83z!nudfc3uvfmm+)n0a+ms1zz&z9jivwwj$&70&d48h2t',
)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(os.environ.get('DEBUG', True))
APPEND_SLASH = True
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'extensions.local').split(',')
AUTH_USER_MODEL = 'users.User'
# Application definition
INSTALLED_APPS = [
'users',
'teams',
'emails',
'releases',
'abuse',
'extensions',
'background_task',
'blender_id_oauth_client',
'common',
'files',
'loginas',
'notifications',
'pipeline',
'ratings',
'rangefilter',
'reviewers',
'stats',
'apitokens',
'taggit',
'drf_spectacular',
'drf_spectacular_sidecar',
'rest_framework',
'waffle',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.flatpages',
'django.contrib.humanize',
'actstream',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'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',
'common.middleware.threadlocal.ThreadLocalMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
]
ROOT_URLCONF = 'blender_extensions.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / 'assets_shared' / 'src' / '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',
'loginas.context_processors.impersonated_session_status',
'common.context_processors.extra_context',
],
},
},
]
WSGI_APPLICATION = 'blender_extensions.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': dj_database_url.config(default='sqlite:///{}'.format(BASE_DIR / 'db.sqlite3')),
}
DATABASES['default']['CONN_MAX_AGE'] = None
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Amsterdam'
USE_I18N = True
USE_TZ = True
SITE_ID = 1
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
MEDIA_URL = 'media/'
STATIC_ROOT = os.environ.get('STATIC_ROOT', BASE_DIR / 'public/static')
MEDIA_ROOT = os.environ.get('MEDIA_ROOT', BASE_DIR / 'public/media')
STATICFILES_DIRS = [BASE_DIR / 'assets_shared' / 'src', BASE_DIR / 'assets_shared' / 'assets']
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'pipeline.finders.PipelineFinder',
]
STATICFILES_STORAGE = 'pipeline.storage.PipelineManifestStorage'
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {'format': '%(asctime)-15s %(levelname)8s %(name)s %(message)s'},
'verbose': {
'format': (
'%(asctime)s %(levelname)8s [%(filename)s:%(lineno)d '
'%(funcName)s] %(name)s %(message)s '
),
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {'level': 'INFO'},
},
'root': {'level': 'INFO', 'handlers': ['console']},
}
PIPELINE = {
'JS_COMPRESSOR': 'pipeline.compressors.jsmin.JSMinCompressor',
'CSS_COMPRESSOR': 'pipeline.compressors.NoopCompressor',
'JAVASCRIPT': {
'common': {
'source_filenames': (
'common/scripts/*.js',
'scripts/tutti/*.js',
),
'output_filename': 'js/common.js',
},
'extensions': {
'source_filenames': ('extensions/scripts/*.js',),
'output_filename': 'js/extensions.js',
},
},
'STYLESHEETS': {
'common': {
'source_filenames': (
'common/styles/main.sass',
'common/styles/*.scss',
),
'output_filename': 'css/common.css',
'extra_context': {'media': 'screen,projection'},
},
},
'COMPILERS': ('libsasscompiler.LibSassCompiler',),
'DISABLE_WRAPPER': True,
}
# Blender ID login and logout URLs
LOGIN_URL = '/oauth/login'
LOGOUT_URL = '/oauth/logout'
SENTRY_DSN = os.environ.get('SENTRY_DSN')
if SENTRY_DSN:
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[
DjangoIntegration(),
],
# Set traces_sample_rate to 1.0 to capture 100%
# of transactions for performance monitoring.
# We recommend adjusting this value in production.
traces_sample_rate=1.0,
# If you wish to associate users to errors (assuming you are using
# django.contrib.auth) you may enable sending PII data.
send_default_pii=False,
)
BLENDER_ID = {
# MUST end in a slash:
'BASE_URL': os.environ.get('BID_BASE_URL', 'http://id.local:8000/'),
'OAUTH_CLIENT': os.environ.get('BID_OAUTH_CLIENT', 'BLENDER-EXTENSIONS-DEV'),
'OAUTH_SECRET': os.environ.get(
'BID_OAUTH_SECRET', 'DEVELOPMENT-ONLY NON SECRET NEVER USE IN PRODUCTION'
),
'WEBHOOK_USER_MODIFIED_SECRET': os.environ.get(
'BID_WEBHOOK_USER_MODIFIED_SECRET', 'DEVELOPMENT-ONLY NON SECRET NEVER USE IN PRODUCTION'
),
}
TAGGIT_CASE_INSENSITIVE = True
ACTSTREAM_SETTINGS = {
'MANAGER': 'users.managers.CustomStreamManager',
'FETCH_RELATIONS': True,
}
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': ('apitokens.authentication.UserTokenAuthentication',),
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
}
SPECTACULAR_SETTINGS = {
'TITLE': 'Blender Extensions Platform API',
'DESCRIPTION': 'API for the Blender Extensions Platform website',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
# We use DRF sidecar so we don't rely on CDNs
'SWAGGER_UI_DIST': 'SIDECAR',
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
'REDOC_DIST': 'SIDECAR',
}
# Fallback user for logging
SYSTEM_USER_ID = os.environ.get('SYSTEM_USER_ID', 1)
if TESTING:
# Avoid "ValueError: Missing staticfiles manifest entry for"
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
# Disable logging output when running tests
LOGGING = {
'version': 1,
'loggers': {
'': {
'level': 'CRITICAL',
},
},
}
if DEBUG:
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
INSTALLED_APPS.append('debug_toolbar')
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
INTERNAL_IPS = [
'127.0.0.1',
]
# Email configuration, by default uses console output
EMAIL_BACKEND = os.getenv('EMAIL_BACKEND', 'django.core.mail.backends.console.EmailBackend')
DEFAULT_REPLY_TO_EMAIL = os.getenv(
'DEFAULT_REPLY_TO_EMAIL', 'Blender Extensions Platform <extensions@blender.org>'
)
DEFAULT_FROM_EMAIL = os.getenv(
'DEFAULT_FROM_EMAIL', 'Blender Extensions Platform <extensions@blender.org>'
)
EMAIL_HOST = os.getenv('EMAIL_HOST')
EMAIL_PORT = os.getenv('EMAIL_PORT', '587')
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')
ACTSTREAM_SETTINGS = {
'MANAGER': 'actstream.managers.ActionManager',
}
# Require file validation for other file processing (e.g. thumbnails).
# Should be set for staging/production.
REQUIRE_FILE_VALIDATION = os.getenv('REQUIRE_FILE_VALIDATION', False)
# Maximum number of attempts for failing background tasks
MAX_ATTEMPTS = 5