8 from psycopg2cffi
import compat
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':
30 DEBUG
= get_bool('DEBUG', False)
32 ADMINS
= re
.findall(r
'\s*([^<]+) <([^>]+)>\s*', os
.getenv('ADMINS', ''))
37 'default': dj_database_url
.config(default
='postgres://mygpo:mygpo@localhost/mygpo')
41 _cache_used
= bool(os
.getenv('CACHE_BACKEND', False))
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
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'
66 # If you set this to False, Django will make some optimizations so as not
67 # to load the internationalization machinery.
73 STATIC_ROOT
= 'staticfiles'
74 STATIC_URL
= '/static/'
76 STATICFILES_DIRS
= (os
.path
.abspath(os
.path
.join(BASE_DIR
, '..', 'static')),)
81 MEDIA_ROOT
= os
.getenv(
82 'MEDIA_ROOT', os
.path
.abspath(os
.path
.join(BASE_DIR
, '..', 'media'))
90 'BACKEND': 'django.template.backends.django.DjangoTemplates',
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
110 'django.template.context_processors.request',
112 'libraries': {'staticfiles': 'django.templatetags.static'},
115 'django.template.loaders.cached.Loader',
116 ['django.template.loaders.app_directories.Loader'],
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'
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',
155 'mygpo.subscriptions',
158 'mygpo.usersettings',
164 'mygpo.episodestates',
167 'mygpo.administration',
169 'mygpo.podcastlists',
177 INSTALLED_APPS
+= ['debug_toolbar']
178 MIDDLEWARE
+= ['debug_toolbar.middleware.DebugToolbarMiddleware']
186 import django_extensions
188 INSTALLED_APPS
+= ['django_extensions']
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]:
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
= ['*']
241 'disable_existing_loggers': False,
243 'verbose': {'format': '%(asctime)s %(name)s %(levelname)s %(message)s'}
245 'filters': {'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}},
248 'level': os
.getenv('LOGGING_CONSOLE_LEVEL', 'DEBUG'),
249 'class': 'logging.StreamHandler',
250 'formatter': 'verbose',
254 'filters': ['require_debug_false'],
255 'class': 'django.utils.log.AdminEmailHandler',
260 'handlers': os
.getenv('LOGGING_DJANGO_HANDLERS', 'console').split(),
262 'level': os
.getenv('LOGGING_DJANGO_LEVEL', 'WARN'),
265 'handlers': os
.getenv('LOGGING_MYGPO_HANDLERS', 'console').split(),
266 'level': os
.getenv('LOGGING_MYGPO_LEVEL', 'INFO'),
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))
278 LOGGING
['handlers']['file'] = {
280 'class': 'logging.handlers.RotatingFileHandler',
281 'filename': os
.getenv('LOGGING_FILENAME'),
282 'maxBytes': 10_000_000,
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', '')
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']
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
348 ACTIVATION_VALID_DAYS
= int(os
.getenv('ACTIVATION_VALID_DAYS', 10))
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))
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', '')
383 raise ValueError('Could not set up sentry because ' 'SENTRY_DSN is not set')
386 dsn
=sentry_dsn
, integrations
=[DjangoIntegration(), CeleryIntegration()]
389 except (ImportError, ValueError):