Make sentry errors more useful

This commit is contained in:
Ramon Wenger 2023-03-30 13:51:34 +02:00
parent d846e76245
commit 8bdf17685a
4 changed files with 298 additions and 248 deletions

View File

@ -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)),
)
]

View File

@ -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)

View File

@ -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"

View File

@ -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)