Add Celery integration to Sentry
[mygpo.git] / mygpo / settings.py
blob00ae5779e4bf4466d8ebe93d69aa6294082b4b5b
1 import re
2 import sys
3 import os.path
4 import dj_database_url
7 try:
8 from psycopg2cffi import compat
10 compat.register()
11 except ImportError:
12 pass
15 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18 def get_bool(name, default):
19 return os.getenv(name, str(default)).lower() == 'true'
22 def get_intOrNone(name, default):
23 """ Parses the env variable, accepts ints and literal None"""
24 value = os.getenv(name, str(default))
25 if value.lower() == 'none':
26 return None
27 return int(value)
30 DEBUG = get_bool('DEBUG', False)
32 ADMINS = re.findall(r'\s*([^<]+) <([^>]+)>\s*', os.getenv('ADMINS', ''))
34 MANAGERS = ADMINS
36 DATABASES = {
37 'default': dj_database_url.config(default='postgres://mygpo:mygpo@localhost/mygpo')
41 _cache_used = bool(os.getenv('CACHE_BACKEND', False))
43 if _cache_used:
44 CACHES = {}
45 CACHES['default'] = {
46 'BACKEND': os.getenv(
47 'CACHE_BACKEND', 'django.core.cache.backends.memcached.MemcachedCache'
49 'LOCATION': os.getenv('CACHE_LOCATION'),
53 # Local time zone for this installation. Choices can be found here:
54 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
55 # although not all choices may be available on all operating systems.
56 # If running in a Windows environment this must be set to the same as your
57 # system time zone.
58 TIME_ZONE = 'UTC'
60 # Language code for this installation. All choices can be found here:
61 # http://www.i18nguy.com/unicode/language-identifiers.html
62 LANGUAGE_CODE = 'en-us'
64 SITE_ID = 1
66 # If you set this to False, Django will make some optimizations so as not
67 # to load the internationalization machinery.
68 USE_I18N = True
71 # Static Files
73 STATIC_ROOT = 'staticfiles'
74 STATIC_URL = '/static/'
76 STATICFILES_DIRS = (os.path.abspath(os.path.join(BASE_DIR, '..', 'static')),)
79 # Media Files
81 MEDIA_ROOT = os.getenv(
82 'MEDIA_ROOT', os.path.abspath(os.path.join(BASE_DIR, '..', 'media'))
85 MEDIA_URL = '/media/'
88 TEMPLATES = [
90 'BACKEND': 'django.template.backends.django.DjangoTemplates',
91 'DIRS': [],
92 'OPTIONS': {
93 'debug': DEBUG,
94 'context_processors': [
95 'django.contrib.auth.context_processors.auth',
96 'django.template.context_processors.debug',
97 'django.template.context_processors.i18n',
98 'django.template.context_processors.media',
99 'django.template.context_processors.static',
100 'django.template.context_processors.tz',
101 'django.contrib.messages.context_processors.messages',
102 'mygpo.web.google.analytics',
103 'mygpo.web.google.adsense',
104 # make the debug variable available in templates
105 # https://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-debug
106 'django.template.context_processors.debug',
107 # required so that the request obj can be accessed from
108 # templates. this is used to direct users to previous
109 # page after login
110 'django.template.context_processors.request',
112 'libraries': {'staticfiles': 'django.templatetags.static'},
113 'loaders': [
115 'django.template.loaders.cached.Loader',
116 ['django.template.loaders.app_directories.Loader'],
124 MIDDLEWARE = [
125 'django.middleware.common.CommonMiddleware',
126 'django.middleware.csrf.CsrfViewMiddleware',
127 'django.contrib.sessions.middleware.SessionMiddleware',
128 'django.contrib.auth.middleware.AuthenticationMiddleware',
129 'django.middleware.locale.LocaleMiddleware',
130 'django.contrib.messages.middleware.MessageMiddleware',
133 ROOT_URLCONF = 'mygpo.urls'
135 INSTALLED_APPS = [
136 'django.contrib.contenttypes',
137 'django.contrib.messages',
138 'django.contrib.admin',
139 'django.contrib.humanize',
140 'django.contrib.auth',
141 'django.contrib.sessions',
142 'django.contrib.staticfiles',
143 'django.contrib.sites',
144 'django.contrib.postgres',
145 'django_celery_results',
146 'django_celery_beat',
147 'mygpo.core',
148 'mygpo.podcasts',
149 'mygpo.chapters',
150 'mygpo.search',
151 'mygpo.users',
152 'mygpo.api',
153 'mygpo.web',
154 'mygpo.publisher',
155 'mygpo.subscriptions',
156 'mygpo.history',
157 'mygpo.favorites',
158 'mygpo.usersettings',
159 'mygpo.data',
160 'mygpo.userfeeds',
161 'mygpo.suggestions',
162 'mygpo.directory',
163 'mygpo.categories',
164 'mygpo.episodestates',
165 'mygpo.maintenance',
166 'mygpo.share',
167 'mygpo.administration',
168 'mygpo.pubsub',
169 'mygpo.podcastlists',
170 'mygpo.votes',
173 try:
174 if DEBUG:
175 import debug_toolbar
177 INSTALLED_APPS += ['debug_toolbar']
178 MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
180 except ImportError:
181 pass
184 try:
185 if DEBUG:
186 import django_extensions
188 INSTALLED_APPS += ['django_extensions']
190 except ImportError:
191 pass
194 ACCOUNT_ACTIVATION_DAYS = int(os.getenv('ACCOUNT_ACTIVATION_DAYS', 7))
196 AUTHENTICATION_BACKENDS = (
197 'mygpo.users.backend.CaseInsensitiveModelBackend',
198 'mygpo.web.auth.EmailAuthenticationBackend',
201 SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
203 # TODO: use (default) JSON serializer for security
204 # this would currently fail as we're (de)serializing datetime objects
205 # https://docs.djangoproject.com/en/1.5/topics/http/sessions/#session-serialization
206 SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
209 MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
211 USER_CLASS = 'mygpo.users.models.User'
213 LOGIN_URL = '/login/'
215 CSRF_FAILURE_VIEW = 'mygpo.web.views.csrf_failure'
218 DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', '')
220 SECRET_KEY = os.getenv('SECRET_KEY', '')
222 if 'pytest' in sys.argv[0]:
223 SECRET_KEY = 'test'
225 GOOGLE_ANALYTICS_PROPERTY_ID = os.getenv('GOOGLE_ANALYTICS_PROPERTY_ID', '')
227 DIRECTORY_EXCLUDED_TAGS = os.getenv('DIRECTORY_EXCLUDED_TAGS', '').split()
229 FLICKR_API_KEY = os.getenv('FLICKR_API_KEY', '')
231 SOUNDCLOUD_CONSUMER_KEY = os.getenv('SOUNDCLOUD_CONSUMER_KEY', '')
233 MAINTENANCE = get_bool('MAINTENANCE', False)
236 ALLOWED_HOSTS = ['*']
239 LOGGING = {
240 'version': 1,
241 'disable_existing_loggers': False,
242 'formatters': {
243 'verbose': {'format': '%(asctime)s %(name)s %(levelname)s %(message)s'}
245 'filters': {'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}},
246 'handlers': {
247 'console': {
248 'level': os.getenv('LOGGING_CONSOLE_LEVEL', 'DEBUG'),
249 'class': 'logging.StreamHandler',
250 'formatter': 'verbose',
252 'mail_admins': {
253 'level': 'ERROR',
254 'filters': ['require_debug_false'],
255 'class': 'django.utils.log.AdminEmailHandler',
258 'loggers': {
259 'django': {
260 'handlers': os.getenv('LOGGING_DJANGO_HANDLERS', 'console').split(),
261 'propagate': True,
262 'level': os.getenv('LOGGING_DJANGO_LEVEL', 'WARN'),
264 'mygpo': {
265 'handlers': os.getenv('LOGGING_MYGPO_HANDLERS', 'console').split(),
266 'level': os.getenv('LOGGING_MYGPO_LEVEL', 'INFO'),
268 'celery': {
269 'handlers': os.getenv('LOGGING_CELERY_HANDLERS', 'console').split(),
270 'level': os.getenv('LOGGING_CELERY_LEVEL', 'DEBUG'),
275 _use_log_file = bool(os.getenv('LOGGING_FILENAME', False))
277 if _use_log_file:
278 LOGGING['handlers']['file'] = {
279 'level': 'INFO',
280 'class': 'logging.handlers.RotatingFileHandler',
281 'filename': os.getenv('LOGGING_FILENAME'),
282 'maxBytes': 10_000_000,
283 'backupCount': 10,
284 'formatter': 'verbose',
288 # minimum number of subscribers a podcast must have to be assigned a slug
289 PODCAST_SLUG_SUBSCRIBER_LIMIT = int(os.getenv('PODCAST_SLUG_SUBSCRIBER_LIMIT', 10))
291 # minimum number of subscribers that a podcast needs to "push" one of its
292 # categories to the top
293 MIN_SUBSCRIBERS_CATEGORY = int(os.getenv('MIN_SUBSCRIBERS_CATEGORY', 10))
295 # maximum number of episode actions that the API processes immediatelly before
296 # returning the response. Larger requests will be handled in background.
297 # Handler can be set to None to disable
298 API_ACTIONS_MAX_NONBG = int(os.getenv('API_ACTIONS_MAX_NONBG', 100))
299 API_ACTIONS_BG_HANDLER = 'mygpo.api.tasks.episode_actions_celery_handler'
302 ADSENSE_CLIENT = os.getenv('ADSENSE_CLIENT', '')
304 ADSENSE_SLOT_BOTTOM = os.getenv('ADSENSE_SLOT_BOTTOM', '')
306 # we're running behind a proxy that sets the X-Forwarded-Proto header correctly
307 # see https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
308 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
311 # enabled access to staff-only areas with ?staff=<STAFF_TOKEN>
312 STAFF_TOKEN = os.getenv('STAFF_TOKEN', None)
314 # The User-Agent string used for outgoing HTTP requests
315 USER_AGENT = 'gpodder.net (+https://github.com/gpodder/mygpo)'
317 # Base URL of the website that is used if the actually used parameters is not
318 # available. Request handlers, for example, can access the requested domain.
319 # Code that runs in background can not do this, and therefore requires a
320 # default value. This should be set to something like 'http://example.com'
321 DEFAULT_BASE_URL = os.getenv('DEFAULT_BASE_URL', '')
324 ### Celery
326 CELERY_BROKER_URL = os.getenv('BROKER_URL', 'redis://localhost')
327 CELERY_RESULT_BACKEND = 'django-db'
329 CELERY_RESULT_EXPIRES = 60 * 60 # 1h expiry time in seconds
331 CELERY_ACCEPT_CONTENT = ['json']
334 ### Google API
336 GOOGLE_CLIENT_ID = os.getenv('GOOGLE_CLIENT_ID', '')
337 GOOGLE_CLIENT_SECRET = os.getenv('GOOGLE_CLIENT_SECRET', '')
339 # URL where users of the site can get support
340 SUPPORT_URL = os.getenv('SUPPORT_URL', '')
343 FEEDSERVICE_URL = os.getenv('FEEDSERVICE_URL', 'http://feeds.gpodder.net/')
346 # time for how long an activation is valid; after that, an unactivated user
347 # will be deleted
348 ACTIVATION_VALID_DAYS = int(os.getenv('ACTIVATION_VALID_DAYS', 10))
351 OPBEAT = {
352 "ORGANIZATION_ID": os.getenv('OPBEAT_ORGANIZATION_ID', ''),
353 "APP_ID": os.getenv('OPBEAT_APP_ID', ''),
354 "SECRET_TOKEN": os.getenv('OPBEAT_SECRET_TOKEN', ''),
357 LOCALE_PATHS = [os.path.abspath(os.path.join(BASE_DIR, 'locale'))]
359 INTERNAL_IPS = os.getenv('INTERNAL_IPS', '').split()
361 EMAIL_BACKEND = os.getenv(
362 'EMAIL_BACKEND', 'django.core.mail.backends.smtp.EmailBackend'
365 PODCAST_AD_ID = os.getenv('PODCAST_AD_ID')
368 MAX_EPISODE_ACTIONS = int(os.getenv('MAX_EPISODE_ACTIONS', 1000))
370 SEARCH_CUTOFF = float(os.getenv('SEARCH_CUTOFF', 0.3))
373 ### Sentry
375 try:
376 import sentry_sdk
377 from sentry_sdk.integrations.django import DjangoIntegration
378 from sentry_sdk.integrations.celery import CeleryIntegration
380 # Sentry Data Source Name (DSN)
381 sentry_dsn = os.getenv('SENTRY_DSN', '')
382 if not sentry_dsn:
383 raise ValueError('Could not set up sentry because ' 'SENTRY_DSN is not set')
385 sentry_sdk.init(
386 dsn=sentry_dsn, integrations=[DjangoIntegration(), CeleryIntegration()]
389 except (ImportError, ValueError):
390 pass