Make sentry errors more useful
This commit is contained in:
parent
d846e76245
commit
8bdf17685a
|
|
@ -2,24 +2,31 @@ from django.conf import settings
|
|||
from django.conf.urls import url
|
||||
from django.urls import include
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from graphene_django.views import GraphQLView
|
||||
|
||||
from api.schema_public import schema
|
||||
|
||||
from core.views import PrivateGraphQLView
|
||||
from core.views import SentryGraphQLView, PrivateGraphQLView
|
||||
|
||||
app_name = 'api'
|
||||
app_name = "api"
|
||||
urlpatterns = [
|
||||
url(r'^graphql-public', csrf_exempt(GraphQLView.as_view(schema=schema))),
|
||||
url(r'^graphql', csrf_exempt(PrivateGraphQLView.as_view())),
|
||||
|
||||
url(r"^graphql-public", csrf_exempt(SentryGraphQLView.as_view(schema=schema))),
|
||||
url(r"^graphql", csrf_exempt(PrivateGraphQLView.as_view())),
|
||||
# oauth
|
||||
url(r'^oauth/', include('oauth.urls', namespace="oauth")),
|
||||
url(r"^oauth/", include("oauth.urls", namespace="oauth")),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [url(r'^graphiql-public', csrf_exempt(GraphQLView.as_view(schema=schema, graphiql=True,
|
||||
pretty=True)))]
|
||||
urlpatterns += [url(r'^graphiql', csrf_exempt(PrivateGraphQLView.as_view(graphiql=True, pretty=True)))]
|
||||
|
||||
|
||||
urlpatterns += [
|
||||
url(
|
||||
r"^graphiql-public",
|
||||
csrf_exempt(
|
||||
SentryGraphQLView.as_view(schema=schema, graphiql=True, pretty=True)
|
||||
),
|
||||
)
|
||||
]
|
||||
urlpatterns += [
|
||||
url(
|
||||
r"^graphiql",
|
||||
csrf_exempt(PrivateGraphQLView.as_view(graphiql=True, pretty=True)),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ from django.conf import settings
|
|||
from django.http import Http404, HttpResponsePermanentRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from graphene import ResolveInfo
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
|
||||
try:
|
||||
|
|
@ -15,25 +17,25 @@ _thread_locals = local()
|
|||
|
||||
|
||||
def get_current_request():
|
||||
""" returns the request object for this thread """
|
||||
"""returns the request object for this thread"""
|
||||
return getattr(_thread_locals, "request", None)
|
||||
|
||||
|
||||
def get_current_user():
|
||||
""" returns the current user, if exist, otherwise returns None """
|
||||
"""returns the current user, if exist, otherwise returns None"""
|
||||
request = get_current_request()
|
||||
if request:
|
||||
return getattr(request, "user", None)
|
||||
|
||||
|
||||
class ThreadLocalMiddleware(MiddlewareMixin):
|
||||
""" Simple middleware that adds the request object in thread local storage."""
|
||||
"""Simple middleware that adds the request object in thread local storage."""
|
||||
|
||||
def process_request(self, request):
|
||||
_thread_locals.request = request
|
||||
|
||||
def process_response(self, request, response):
|
||||
if hasattr(_thread_locals, 'request'):
|
||||
if hasattr(_thread_locals, "request"):
|
||||
del _thread_locals.request
|
||||
return response
|
||||
|
||||
|
|
@ -42,9 +44,14 @@ class CommonRedirectMiddleware(MiddlewareMixin):
|
|||
"""
|
||||
redirects common bad requests or missing images
|
||||
"""
|
||||
|
||||
DEFAULT_REDIRECTS = [
|
||||
(re.compile("(?i)(.+\.php|.+wp-admin.+|.+\.htm|\/wordpress\/|\/wp\/|\/mm5\/|\/wp-content\/)"),
|
||||
'http://example.org/'),
|
||||
(
|
||||
re.compile(
|
||||
"(?i)(.+\.php|.+wp-admin.+|.+\.htm|\/wordpress\/|\/wp\/|\/mm5\/|\/wp-content\/)"
|
||||
),
|
||||
"http://example.org/",
|
||||
),
|
||||
]
|
||||
|
||||
def process_exception(self, request, exception):
|
||||
|
|
@ -72,10 +79,17 @@ class CommonRedirectMiddleware(MiddlewareMixin):
|
|||
# some static image is missing show a placeholder (use full for local dev)
|
||||
m = re.match(r".*(max|fill)-(?P<dimensions>\d+x\d+)\.(jpg|png|svg)", path)
|
||||
if m:
|
||||
return 'https://picsum.photos/{}'.format(m.group('dimensions').replace('x', '/'))
|
||||
return "https://picsum.photos/{}".format(
|
||||
m.group("dimensions").replace("x", "/")
|
||||
)
|
||||
# or dummy image: return 'http://via.placeholder.com/{}'.format(m.group('dimensions'))
|
||||
if '.png' in path or '.jpg' in path or '.svg' in path or 'not-found' in path:
|
||||
return 'https://picsum.photos/400/400'
|
||||
if (
|
||||
".png" in path
|
||||
or ".jpg" in path
|
||||
or ".svg" in path
|
||||
or "not-found" in path
|
||||
):
|
||||
return "https://picsum.photos/400/400"
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/4898408/how-to-set-a-login-cookie-in-django
|
||||
|
|
@ -86,14 +100,24 @@ class UserLoggedInCookieMiddleWare(MiddlewareMixin):
|
|||
If the user is not authenticated and the cookie remains, delete it
|
||||
"""
|
||||
|
||||
cookie_name = 'loginStatus'
|
||||
cookie_name = "loginStatus"
|
||||
|
||||
def process_response(self, request, response):
|
||||
#if user and no cookie, set cookie
|
||||
# if user and no cookie, set cookie
|
||||
if request.user.is_authenticated and not request.COOKIES.get(self.cookie_name):
|
||||
response.set_cookie(self.cookie_name, 'true')
|
||||
elif not request.user.is_authenticated and request.COOKIES.get(self.cookie_name):
|
||||
#else if if no user and cookie remove user cookie, logout
|
||||
response.set_cookie(self.cookie_name, "true")
|
||||
elif not request.user.is_authenticated and request.COOKIES.get(
|
||||
self.cookie_name
|
||||
):
|
||||
# else if if no user and cookie remove user cookie, logout
|
||||
response.delete_cookie(self.cookie_name)
|
||||
return response
|
||||
|
||||
|
||||
class SentryMiddleware(object):
|
||||
def on_error(self, error):
|
||||
capture_exception(error)
|
||||
raise error
|
||||
|
||||
def resolve(self, next, root, info: ResolveInfo, **args):
|
||||
return next(root, info, **args).catch(self.on_error)
|
||||
|
|
|
|||
|
|
@ -16,142 +16,138 @@ load_dotenv(find_dotenv())
|
|||
# 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')
|
||||
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', ''))
|
||||
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 = ['*']
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
if not DEBUG:
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
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',
|
||||
"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',
|
||||
"whitenoise.runserver_nostatic",
|
||||
"django.contrib.staticfiles",
|
||||
"django_filters",
|
||||
"graphene_django",
|
||||
"django_extensions",
|
||||
"compressor",
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
INSTALLED_APPS += ['wagtail.contrib.styleguide']
|
||||
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'
|
||||
"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',
|
||||
)
|
||||
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', ]
|
||||
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',
|
||||
"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'
|
||||
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',
|
||||
"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'
|
||||
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)
|
||||
}
|
||||
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}
|
||||
|
||||
# Django custom user
|
||||
AUTH_USER_MODEL = 'users.User'
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
|
@ -162,30 +158,30 @@ if WEAK_PASSWORDS:
|
|||
else:
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
LOGOUT_REDIRECT_URL = '/login'
|
||||
LOGIN_REDIRECT_URL = '/login'
|
||||
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'
|
||||
LANGUAGE_CODE = "de"
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
|
@ -194,167 +190,161 @@ USE_L10N = True
|
|||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
('de', _('German')),
|
||||
('en', _('English')),
|
||||
("de", _("German")),
|
||||
("en", _("English")),
|
||||
]
|
||||
|
||||
LOCALE_PATHS = [
|
||||
os.path.join(BASE_DIR, 'locale')
|
||||
]
|
||||
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')
|
||||
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/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
STATICFILES_DIRS = (
|
||||
os.path.join(BASE_DIR, '..', 'client/dist/static'),
|
||||
os.path.join(BASE_DIR, '..', 'client/src/assets'),
|
||||
os.path.join(BASE_DIR, "..", "client/dist/static"),
|
||||
os.path.join(BASE_DIR, "..", "client/src/assets"),
|
||||
)
|
||||
|
||||
if not TEST:
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
|
||||
COMPRESS_CSS_FILTERS = [
|
||||
# 'django_compressor_autoprefixer.AutoprefixerFilter',
|
||||
'compressor.filters.cssmin.CSSMinFilter',
|
||||
"compressor.filters.cssmin.CSSMinFilter",
|
||||
]
|
||||
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||
"compressor.finders.CompressorFinder",
|
||||
)
|
||||
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/x-scss', 'django_libsass.SassCompiler'),
|
||||
)
|
||||
COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),)
|
||||
|
||||
COMPRESS_ENABLED = True
|
||||
|
||||
if not DEBUG:
|
||||
COMPRESS_STORAGE = 'compressor.storage.GzipCompressorFileStorage'
|
||||
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'))
|
||||
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_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'))
|
||||
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'))
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.environ.get("DJANGO_MEDIAFILES", os.path.join(BASE_DIR, "media"))
|
||||
|
||||
AWS_S3_OBJECT_PARAMETERS = {
|
||||
'CacheControl': 'max-age=86400',
|
||||
"CacheControl": "max-age=86400",
|
||||
}
|
||||
|
||||
# Media Files
|
||||
USE_404_FALLBACK_IMAGE = bool_value(os.environ.get('USE_404_FALLBACK_IMAGE', 'True'))
|
||||
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'
|
||||
"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'
|
||||
"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'
|
||||
"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',
|
||||
|
||||
"SysLog": {
|
||||
"level": "INFO",
|
||||
"class": "logging.handlers.SysLogHandler",
|
||||
"formatter": "simple_format",
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING'
|
||||
"loggers": {
|
||||
"": {"handlers": ["console"], "level": "WARNING"},
|
||||
"skillbox": {
|
||||
"handlers": ["console", "SysLog"],
|
||||
"level": os.environ.get("DJANGO_LOG_LEVEL", "INFO"),
|
||||
"propagate": False,
|
||||
},
|
||||
'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,
|
||||
},
|
||||
'graphql': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING',
|
||||
'propagate': False
|
||||
"django.server": {
|
||||
"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'):
|
||||
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}
|
||||
user = event["user"]
|
||||
id = user["id"]
|
||||
event["user"] = {"id": id}
|
||||
return event
|
||||
|
||||
|
||||
environment = os.environ.get('SENTRY_ENV', 'localhost')
|
||||
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'),
|
||||
dsn=os.environ.get("SENTRY_DSN"),
|
||||
integrations=[DjangoIntegration()],
|
||||
send_default_pii=True,
|
||||
before_send=before_send,
|
||||
environment=environment
|
||||
before_send_transaction=before_send,
|
||||
environment=environment,
|
||||
traces_sample_rate=sample_rate,
|
||||
)
|
||||
|
||||
RAVEN_DSN_JS = os.environ.get('RAVEN_DSN_JS', '')
|
||||
# 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'
|
||||
"SCHEMA": "api.schema.schema",
|
||||
"SCHEMA_OUTPUT": "schema.graphql",
|
||||
"MIDDLEWARE": ["core.middleware.SentryMiddleware"],
|
||||
}
|
||||
|
||||
# if DEBUG:
|
||||
|
|
@ -363,25 +353,27 @@ GRAPHENE = {
|
|||
# ]
|
||||
|
||||
# http://docs.wagtail.io/en/v2.1/advanced_topics/settings.html?highlight=urls
|
||||
WAGTAIL_SITE_NAME = 'skillbox'
|
||||
WAGTAIL_SITE_NAME = "skillbox"
|
||||
WAGTAILSEARCH_BACKENDS = {
|
||||
'default': {
|
||||
'BACKEND': 'wagtail.search.backends.database',
|
||||
"default": {
|
||||
"BACKEND": "wagtail.search.backends.database",
|
||||
}
|
||||
}
|
||||
WAGTAILDOCS_DOCUMENT_MODEL = 'books.CustomDocument'
|
||||
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')
|
||||
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>'
|
||||
DEFAULT_FROM_EMAIL = "myskillbox <noreply@myskillbox.ch>"
|
||||
|
||||
# Metanet Config
|
||||
if DEBUG:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
||||
else:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
|
||||
ALLOW_BETA_LOGIN = True
|
||||
|
||||
|
|
@ -390,25 +382,25 @@ 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',
|
||||
}
|
||||
"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')
|
||||
PLATFORM = os.environ.get("APP_FLAVOR", "myskillbox")
|
||||
|
||||
OAUTH_LOCAL_REDIRECT_URI = os.environ.get("OAUTH_LOCAL_REDIRECT_URI")
|
||||
|
||||
|
|
@ -419,12 +411,12 @@ 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_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'
|
||||
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'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from django.http.request import HttpRequest
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
|
@ -5,10 +6,34 @@ from django.http.response import HttpResponse, HttpResponseRedirect
|
|||
from django.shortcuts import render
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from graphene_django.views import GraphQLView
|
||||
from sentry_sdk.api import start_transaction
|
||||
from wagtail.admin.views.pages.listing import index as wagtailadmin_explore
|
||||
|
||||
|
||||
class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
|
||||
# For sentry perfomance monitoring
|
||||
# taken from https://jerrynsh.com/how-to-monitor-python-graphql-api-with-sentry/
|
||||
class SentryGraphQLView(GraphQLView):
|
||||
def execute_graphql_request(
|
||||
self,
|
||||
request: HttpRequest,
|
||||
data,
|
||||
query,
|
||||
variables,
|
||||
operation_name,
|
||||
show_graphiql,
|
||||
):
|
||||
operation_type = (
|
||||
self.get_backend(request)
|
||||
.document_from_string(self.schema, query)
|
||||
.get_operation_type(operation_name)
|
||||
)
|
||||
with start_transaction(op=operation_type, name=operation_name):
|
||||
return super().execute_graphql_request(
|
||||
request, data, query, variables, operation_name, show_graphiql
|
||||
)
|
||||
|
||||
|
||||
class PrivateGraphQLView(LoginRequiredMixin, SentryGraphQLView):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -16,22 +41,24 @@ class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
|
|||
def home(request):
|
||||
if settings.SERVE_VIA_WEBPACK:
|
||||
try:
|
||||
res = requests.get('http://localhost:8080{}'.format(request.get_full_path()))
|
||||
res = requests.get(
|
||||
"http://localhost:8080{}".format(request.get_full_path())
|
||||
)
|
||||
headers = res.headers
|
||||
content_type = headers.get('content-type', 'text/html')
|
||||
content_type = headers.get("content-type", "text/html")
|
||||
return HttpResponse(res.text, content_type=content_type)
|
||||
except Exception as e:
|
||||
print('Can not connect to dev server at http://localhost:8080:', e)
|
||||
print("Can not connect to dev server at http://localhost:8080:", e)
|
||||
|
||||
return render(request, 'index.html', {})
|
||||
return render(request, "index.html", {})
|
||||
|
||||
|
||||
def override_wagtailadmin_explore_default_ordering(request, parent_page_id):
|
||||
"""
|
||||
Wrap Wagtail's explore view to change the default ordering
|
||||
"""
|
||||
if request.method == 'GET' and 'ordering' not in request.GET:
|
||||
if request.method == "GET" and "ordering" not in request.GET:
|
||||
# Display reordering handles by default for children of all Page types.
|
||||
return HttpResponseRedirect(request.path_info + '?ordering=ord')
|
||||
return HttpResponseRedirect(request.path_info + "?ordering=ord")
|
||||
|
||||
return wagtailadmin_explore(request, parent_page_id=parent_page_id)
|
||||
|
|
|
|||
Loading…
Reference in New Issue