Ejemplo n.º 1
0
class Development(databases.Databases, common.Common):
    """Settings for development."""

    CACHES = values.DictValue({
        'default': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
        }
    })

    MIDDLEWARE = common.Common.MIDDLEWARE + [
        'debug_toolbar.middleware.DebugToolbarMiddleware'
    ]
    INSTALLED_APPS = (common.Common.INSTALLED_APPS + ('debug_toolbar', ))

    EMAIL_BACKEND = values.Value(
        'django.core.mail.backends.console.EmailBackend')

    @property
    def INTERNAL_IPS(self):  # noqa
        """Return a tuple of IP addresses, as strings.

        Detect a Vagrant box by looking at the hostname. Return the gateway IP
        address on a Vagrant box, because this is the IP address the request
        will originate from.
        """
        if 'vagrant' in socket.gethostname():
            addr = [
                line.split()[1] for line in subprocess.check_output(
                    ['netstat', '-rn']).splitlines()
                if line.startswith('0.0.0.0')
            ][0]  # noqa
        else:
            addr = '127.0.0.1'
        return (addr, )
Ejemplo n.º 2
0
class Prod(Base):
    """Production settings (override default values with environment vars"""
    SECRET_KEY = values.SecretValue()

    DEBUG = False

    SASS_OUTPUT_STYLE = 'compressed'

    # Set like this: DJANGO_ADMINS=Foo,[email protected];Bar,[email protected]
    ADMINS = values.SingleNestedTupleValue()

    # Set like this: DJANGO_ALLOWED_HOSTS=foo.com,bar.net
    ALLOWED_HOSTS = values.ListValue([
        '127.0.0.1',
        'localhost',
        'oldp.local',
        'de.oldp.local'
    ])

    # Set like this: DJANGO_LANGUAGES_DOMAINS="{'de.foo.com':'de','fr.foo.com':'fr'}"
    LANGUAGES_DOMAINS = values.DictValue({
        'localhost:8000': 'en',
        'oldp.local:8000': 'en',
        'de.oldp.local:8000': 'de',
        '127.0.0.1:8000': 'de',
    })
Ejemplo n.º 3
0
class HerokuPostmark(Heroku):
    SECRET_URLS = values.DictValue({
        "admin": "admin",
        "postmark_inbound": "postmark_inbound",
        "postmark_bounce": "postmark_bounce"
    })

    FOI_EMAIL_TEMPLATE = values.Value('request+{secret}@{domain}')
    FOI_EMAIL_DOMAIN = values.Value('inbound.postmarkapp.com')

    SERVER_EMAIL = values.Value(os_env('POSTMARK_INBOUND_ADDRESS'))
    DEFAULT_FROM_EMAIL = values.Value(os_env('POSTMARK_INBOUND_ADDRESS'))

    # Official Notification Mail goes through
    # the normal Django SMTP Backend
    EMAIL_HOST = os_env('POSTMARK_SMTP_SERVER')
    EMAIL_PORT = values.IntegerValue(2525)
    EMAIL_HOST_USER = os_env('POSTMARK_API_KEY')
    EMAIL_HOST_PASSWORD = os_env('POSTMARK_API_KEY')
    EMAIL_USE_TLS = values.BooleanValue(True)

    # SMTP settings for sending FoI mail
    FOI_EMAIL_FIXED_FROM_ADDRESS = values.BooleanValue(False)
    FOI_EMAIL_HOST_FROM = os_env('POSTMARK_INBOUND_ADDRESS')
    FOI_EMAIL_HOST_USER = os_env('POSTMARK_API_KEY')
    FOI_EMAIL_HOST_PASSWORD = os_env('POSTMARK_API_KEY')
    FOI_EMAIL_HOST = os_env('POSTMARK_SMTP_SERVER')
    FOI_EMAIL_PORT = values.IntegerValue(2525)
    FOI_EMAIL_USE_TLS = values.BooleanValue(True)
Ejemplo n.º 4
0
class Dev(Base):
    u"""Configuração para Desenvolvimento."""

    DEBUG = True
    DATABASES = values.DatabaseURLValue(
        'postgres://postgres@localhost/postgres')
    SECRET_KEY = values.Value(
        '(ec65w1as3rno#!g#e*4wji!m*6#$=6v5d-bs--%jax(7o_y6$')
    JWT_AUTH = values.DictValue({
        'JWT_EXPIRATION_DELTA':
        datetime.timedelta(hours=1),
        'JWT_REFRESH_EXPIRATION_DELTA':
        datetime.timedelta(hours=1),
        'JWT_ALLOW_REFRESH':
        True,
        'JWT_AUTH_HEADER_PREFIX':
        'Bearer',
    })

    @classmethod
    def pre_setup(cls):
        u"""Executado antes da Configuração."""
        super(Base, cls).pre_setup()

    @classmethod
    def setup(cls):
        u"""Executado depois da Configuração."""
        super(Base, cls).setup()
        logging.info('Configurações de desenvolvimento carregadas: %s', cls)

    @classmethod
    def post_setup(cls):
        u"""Executado depois da Configuração."""
        super(Base, cls).post_setup()
Ejemplo n.º 5
0
class Development(Base):
    """Development environment settings.

    We set ``DEBUG`` to ``True`` by default, configure the server to respond to all hosts,
    and use a local sqlite database by default.
    """

    ALLOWED_HOSTS = ["*"]
    AWS_SOURCE_BUCKET_NAME = values.Value("development-marsha-source")
    DEBUG = values.BooleanValue(True)
    CLOUDFRONT_SIGNED_URLS_ACTIVE = values.BooleanValue(False)
    CACHES = {
        "default": {
            "BACKEND": "django.core.cache.backends.dummy.DummyCache"
        }
    }

    LOGGING = values.DictValue({
        "version": 1,
        "disable_existing_loggers": False,
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
            }
        },
        "loggers": {
            "marsha": {
                "handlers": ["console"],
                "level": "DEBUG",
                "propagate": True
            }
        },
    })
Ejemplo n.º 6
0
class Development(Base):
    """Development environment settings.

    We set ``DEBUG`` to ``True`` by default, configure the server to respond to all hosts.
    """

    ALLOWED_HOSTS = ["*"]
    AWS_BASE_NAME = values.Value("development")
    DEBUG = values.BooleanValue(True)
    CLOUDFRONT_SIGNED_URLS_ACTIVE = values.BooleanValue(False)
    CACHES = {
        "default": {
            "BACKEND": "django.core.cache.backends.dummy.DummyCache"
        }
    }

    # Mail
    EMAIL_HOST = values.Value("mailcatcher")
    EMAIL_PORT = values.PositiveIntegerValue(1025)

    # Logging
    LOGGING = values.DictValue({
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "gelf": {
                "()": "logging_gelf.formatters.GELFFormatter",
                "null_character": True,
            },
        },
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
            },
            "gelf": {
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
                "formatter": "gelf",
            },
        },
        "loggers": {
            "marsha": {
                "handlers": ["console"],
                "level": "DEBUG",
                "propagate": True,
            },
            # This formatter is here as an example to what is possible to do
            # with xapi loogers.
            "xapi": {
                "handlers": ["gelf"],
                "level": "INFO",
                "propagate": True
            },
        },
    })
Ejemplo n.º 7
0
class Base(Configuration):
    ACTIONNETWORK_API_KEYS = values.DictValue({"main": ""},
                                              environ_prefix=None)
    # stl_dsa/config/settings.py - 2 = stl_dsa/
    ROOT_DIR = environ.Path(__file__) - 2
    APPS_DIR = ROOT_DIR.path("stl_dsa")
    BASE_DIR = ROOT_DIR
    if READ_DOT_ENV_FILE := env.bool("DJANGO_READ_DOT_ENV_FILE",
                                     default=False):
        env.read_env(str(ROOT_DIR.path(".env")))
Ejemplo n.º 8
0
class EmptyDatabases(object):
    """Empty databases settings, used to force to overwrite them."""
    DATABASES = values.DictValue({
        'default': {
            'ENGINE': '',
            'NAME': '',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
        },
    })
Ejemplo n.º 9
0
class Dev(Base):
    """Base settings for development."""

    DEBUG = True

    # Required overrides
    SITE_URL = values.URLValue('http://*****:*****@example.com',
        'password': '******'
    })

    # Storage
    AWS_S3_REGION_NAME = ''
    AWS_STORAGE_BUCKET_NAME = values.Value('django')
    AWS_S3_ENDPOINT_URL = values.Value('http://minio:9000')
    AWS_ACCESS_KEY_ID = values.Value('djangos3')
    AWS_SECRET_ACCESS_KEY = values.Value('djangos3')
    AWS_S3_SECURE_URLS = values.BooleanValue(True)

    @property
    def AWS_S3_CUSTOM_DOMAIN(self):
        return values.Value(self.URL.netloc)

    # Core
    @property
    def FRONTEND_URL(self):
        return values.URLValue(self.SITE_URL)

    @property
    def INSTALLED_APPS(self):
        return super().INSTALLED_APPS + [
            'debug_toolbar',
        ]

    # Security
    CORS_ORIGIN_ALLOW_ALL = True
    SESSION_COOKIE_SECURE = False
    CSRF_COOKIE_SECURE = False
    AWS_AUTO_CREATE_BUCKET = True

    # Email
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

    # Services
    CELERY_BROKER_URL = values.Value('redis://redis',
                                     environ_name='CELERY_BROKER_URL')
    DATABASES = values.DatabaseURLValue(
        'postgis://*****:*****@db:5432/django')
Ejemplo n.º 10
0
class PostgreSQLDatabases(object):
    """Settings for local PostgreSQL databases."""
    DATABASES = values.DictValue({
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'hopper',
            'USER': '******',
            'PASSWORD': '******',
            'HOST': 'localhost',
            'CONN_MAX_AGE': None,
        },
    })
Ejemplo n.º 11
0
class Production(Base):
    """Production environment settings

    You must define the DJANGO_ALLOWED_HOSTS environment variable in Production
    configuration (and derived configurations):

    DJANGO_ALLOWED_HOSTS="foo.com,foo.fr"
    """

    # Security
    ALLOWED_HOSTS = values.ListValue(None)
    CSRF_COOKIE_SECURE = True
    SECURE_BROWSER_XSS_FILTER = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SESSION_COOKIE_SECURE = True
    # System check reference:
    # https://docs.djangoproject.com/en/2.2/ref/checks/#security
    SILENCED_SYSTEM_CHECKS = values.ListValue([
        # Allow the X_FRAME_OPTIONS to be set to "SAMEORIGIN"
        "security.W019"
    ])
    # The X_FRAME_OPTIONS value should be set to "SAMEORIGIN" to display
    # DjangoCMS frontend admin frames. Dockerflow raises a system check security
    # warning with this setting, one should add "security.W019" to the
    # SILENCED_SYSTEM_CHECKS setting (see above).
    X_FRAME_OPTIONS = "SAMEORIGIN"

    # For static files in production, we want to use a backend that includes a hash in
    # the filename, that is calculated from the file content, so that browsers always
    # get the updated version of each file.
    STATICFILES_STORAGE = (
        "django.contrib.staticfiles.storage.ManifestStaticFilesStorage")

    # For more details about CMS_CACHE_DURATION, see :
    # http://docs.django-cms.org/en/latest/reference/configuration.html#cms-cache-durations
    CMS_CACHE_DURATIONS = values.DictValue({
        "menus": 3600,
        "content": 86400,
        "permissions": 86400
    })

    # By default, Django CMS sends cached responses with a
    # Cache-control: max-age value that reflects the server cache TTL
    # (CMS_CACHE_DURATIONS["content"])
    #
    # The thing is : we can invalidate a server side cache entry, but we cannot
    # invalidate our client browser cache entries. That's why we want to set a
    # long TTL on the server side, but a much lower TTL on the browser cache.
    #
    # This setting allows to define a maximum value for the max-age header
    # returned by Django CMS views.
    MAX_BROWSER_CACHE_TTL = 600
Ejemplo n.º 12
0
class Development(databases.Databases, common.Common):
    """Settings for development."""

    CACHES = values.DictValue({
        'default': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
        }
    })

    DEVSERVER_ARGS = values.ListValue([])

    @property
    def DEVSERVER_DEFAULT_ADDR(self):
        """Return the default address to bind devserver to."""
        if 'vagrant' in socket.gethostname():
            addr = '0.0.0.0'
        else:
            addr = '127.0.0.1'
        return addr

    DEVSERVER_MODULES = values.ListValue([
        'devserver.modules.sql.SQLRealTimeModule',
        'devserver.modules.sql.SQLSummaryModule',
        'devserver.modules.profile.ProfileSummaryModule',
    ])

    DEVSERVER_TRUNCATE_SQL = values.BooleanValue(True)

    EMAIL_BACKEND = values.Value(
        'django.core.mail.backends.console.EmailBackend')

    # devserver must be ahead of django.contrib.staticfiles
    INSTALLED_APPS = ('devserver', ) + common.Common.INSTALLED_APPS + (
        'debug_toolbar', )

    @property
    def INTERNAL_IPS(self):
        """Return a tuple of IP addresses, as strings.

        Detect a Vagrant box by looking at the hostname. Return the gateway IP
        address on a Vagrant box, because this is the IP address the request
        will originate from.
        """
        if 'vagrant' in socket.gethostname():
            addr = [
                line.split()[1] for line in subprocess.check_output(
                    ['netstat', '-rn']).splitlines()
                if line.startswith('0.0.0.0')
            ][0]  # noqa
        else:
            addr = '127.0.0.1'
        return (addr, )
Ejemplo n.º 13
0
class DevMixin:
    DEBUG = values.BooleanValue(True)
    CACHES = values.DictValue(
        environ_prefix='',
        default={
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
            }
        })
    EMAIL_BACKEND = 'eml_email_backend.EmailBackend'

    @property
    def EMAIL_FILE_PATH(self):
        return join(super().BASE_DIR, 'tmp')

    THUMBNAIL_DEBUG = True
Ejemplo n.º 14
0
class Production(Base):
    """Production environment settings

    You must define the DJANGO_ALLOWED_HOSTS and DJANGO_SECRET_KEY environment
    variables in Production configuration (and derived configurations):

    DJANGO_ALLOWED_HOSTS="foo.com,foo.fr"
    DJANGO_SECRET_KEY="your-secret-key"
    """

    # Security
    SECRET_KEY = values.SecretValue()
    ALLOWED_HOSTS = values.ListValue(None)
    CSRF_COOKIE_SECURE = True
    SECURE_BROWSER_XSS_FILTER = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SESSION_COOKIE_SECURE = True

    # For static files in production, we want to use a backend that includes a hash in
    # the filename, that is calculated from the file content, so that browsers always
    # get the updated version of each file.
    STATICFILES_STORAGE = (
        "django.contrib.staticfiles.storage.ManifestStaticFilesStorage")

    # For more details about CMS_CACHE_DURATION, see :
    # http://docs.django-cms.org/en/latest/reference/configuration.html#cms-cache-durations
    CMS_CACHE_DURATIONS = values.DictValue({
        "menus": 3600,
        "content": 86400,
        "permissions": 86400
    })

    # By default, Django CMS sends cached responses with a
    # Cache-control: max-age value that reflects the server cache TTL
    # (CMS_CACHE_DURATIONS["content"])
    #
    # The thing is : we can invalidate a server side cache entry, but we cannot
    # invalidate our client browser cache entries. That's why we want to set a
    # long TTL on the server side, but a much lower TTL on the browser cache.
    #
    # This setting allows to define a maximum value for the max-age header
    # returned by Django CMS views.
    MAX_BROWSER_CACHE_TTL = 600
Ejemplo n.º 15
0
class Production(Common):

    # This ensures that Django will be able to detect a secure connection
    # properly on Heroku.
#    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

    # INSTALLED_APPS
    INSTALLED_APPS = Common.INSTALLED_APPS
    # END INSTALLED_APPS

    # SECRET KEY
    SECRET_KEY = values.SecretValue()
    # END SECRET KEY

    # sentry
    RAVEN_CONFIG = values.DictValue()

    INSTALLED_APPS += ('raven.contrib.django.raven_compat', )
    # end sentry


    # django-secure
#    INSTALLED_APPS += ("djangosecure", )

    # set this to 60 seconds and then to 518400 when you can prove it works
#    SECURE_HSTS_SECONDS = 60
#    SECURE_HSTS_INCLUDE_SUBDOMAINS = values.BooleanValue(True)
#    SECURE_FRAME_DENY = values.BooleanValue(True)
#    SECURE_CONTENT_TYPE_NOSNIFF = values.BooleanValue(True)
#    SECURE_BROWSER_XSS_FILTER = values.BooleanValue(True)
#    SESSION_COOKIE_SECURE = values.BooleanValue(False)
#    SESSION_COOKIE_HTTPONLY = values.BooleanValue(True)
#    SECURE_SSL_REDIRECT = values.BooleanValue(True)
    # end django-secure

    # SITE CONFIGURATION
    # Hosts/domain names that are valid for this site
    # See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
    ALLOWED_HOSTS = ["*"]
    # END SITE CONFIGURATION

    INSTALLED_APPS += ("gunicorn", )
Ejemplo n.º 16
0
class Test(Base):
    DEBUG = False
    TEMPLATE_DEBUG = True

    def _fake_convert_pdf(self, infile, outpath):
        _, filename = os.path.split(infile)
        name, ext = filename.rsplit('.', 1)
        output = os.path.join(outpath, '%s.pdf' % name)
        args = ['cp', infile, output]
        return args, output

    @property
    def FROIDE_CONFIG(self):
        config = dict(super(Test, self).FROIDE_CONFIG)
        config.update(
            dict(doc_conversion_call_func=self._fake_convert_pdf,
                 default_law=10000,
                 greetings=[
                     rec(u"Dear ((?:Mr\.?|Ms\.?) .*),?"),
                     rec(u'Sehr geehrter? ((Herr|Frau) .*),?')
                 ],
                 closings=[
                     rec(u"Sincerely yours,?"),
                     rec(u'Mit freundlichen Grüßen')
                 ],
                 public_body_officials_public=False))
        return config

    @property
    def MEDIA_ROOT(self):
        return os.path.abspath(
            os.path.join(super(Test, self).PROJECT_ROOT, "tests", "testdata"))

    MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
    CACHES = values.CacheURLValue('locmem://')

    TEST_SELENIUM_DRIVER = values.Value('phantomjs')

    USE_X_ACCEL_REDIRECT = True

    SECRET_URLS = values.DictValue({
        "admin": "admin",
        "postmark_inbound": "postmark_inbound",
        "postmark_bounce": "postmark_bounce"
    })

    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    DEFAULT_FROM_EMAIL = '*****@*****.**'

    FOI_EMAIL_DOMAIN = 'fragdenstaat.de'

    @property
    def HAYSTACK_CONNECTIONS(self):
        return {
            'default': {
                'ENGINE':
                'haystack.backends.whoosh_backend.WhooshEngine',
                'PATH':
                os.path.join(
                    super(Test, self).PROJECT_ROOT,
                    'tests/froide_test_whoosh_db'),
            },
        }

    CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'
    CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
    CELERY_ALWAYS_EAGER = True
    CELERY_EAGER_PROPAGATES_EXCEPTIONS = True

    MIDDLEWARE_CLASSES = [
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
    ]
Ejemplo n.º 17
0
class Base(Configuration):
    DEBUG = values.BooleanValue(True)
    TEMPLATE_DEBUG = values.BooleanValue(DEBUG)

    DATABASES = values.DatabaseURLValue('sqlite:///dev.db')
    CONN_MAX_AGE = None

    INSTALLED_APPS = values.ListValue([
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'django.contrib.admin',
        'django_comments',
        'django.contrib.flatpages',
        'django.contrib.sitemaps',

        # external
        'haystack',
        'djcelery',
        'taggit',
        'floppyforms',
        'overextends',
        'tastypie',
        'tastypie_swagger',
        'storages',
        'compressor',

        # local
        'froide.foirequest',
        'froide.foirequestfollower',
        'froide.frontpage',
        'froide.publicbody',
        'froide.account',
        'froide.redaction',
        'froide.foisite',
        'froide.helper',
    ])

    CACHES = values.CacheURLValue('dummy://')

    # ############# Site Configuration #########

    # Make this unique, and don't share it with anybody.
    SECRET_KEY = 'make_me_unique!!'

    SITE_NAME = values.Value('Froide')
    SITE_EMAIL = values.Value('*****@*****.**')
    SITE_URL = values.Value('http://*****:*****@example.com'),
    )

    MANAGERS = ADMINS

    INTERNAL_IPS = values.TupleValue(('127.0.0.1', ))

    # ############## PATHS ###############

    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

    LOCALE_PATHS = values.TupleValue(
        (os.path.abspath(os.path.join(PROJECT_ROOT, '..', "locale")), ))

    GEOIP_PATH = None

    # Absolute filesystem path to the directory that will hold user-uploaded files.
    # Example: "/home/media/media.lawrence.com/media/"
    MEDIA_ROOT = os.path.abspath(os.path.join(PROJECT_ROOT, "..", "files"))

    # Sub path in MEDIA_ROOT that will hold FOI attachments
    FOI_MEDIA_PATH = values.Value('foi')

    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/home/media/media.lawrence.com/static/"
    STATIC_ROOT = os.path.abspath(os.path.join(PROJECT_ROOT, "..", "public"))

    # Additional locations of static files
    STATICFILES_DIRS = (os.path.join(PROJECT_ROOT, "static"), )
    COMPRESS_ENABLED = values.BooleanValue(False)
    COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']
    COMPRESS_CSS_FILTERS = [
        'compressor.filters.css_default.CssAbsoluteFilter',
        'compressor.filters.cssmin.CSSMinFilter'
    ]
    COMPRESS_PARSER = 'compressor.parser.HtmlParser'

    # Additional locations of template files
    TEMPLATE_DIRS = (os.path.join(PROJECT_ROOT, "templates"), )

    # ########## URLs #################

    ROOT_URLCONF = values.Value('froide.urls')

    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
    MEDIA_URL = values.Value('/files/')

    # URL prefix for static files.
    # Example: "http://media.lawrence.com/static/"

    # URL that handles the static files like app media.
    # Example: "http://media.lawrence.com"
    STATIC_URL = values.Value('/static/')

    USE_X_ACCEL_REDIRECT = values.BooleanValue(False)
    X_ACCEL_REDIRECT_PREFIX = values.Value('/protected')

    # ## URLs that can be translated to a secret value

    SECRET_URLS = values.DictValue({"admin": "admin"})

    # ######## Backends, Finders, Processors, Classes ####

    AUTH_USER_MODEL = values.Value('account.User')
    CUSTOM_AUTH_USER_MODEL_DB = values.Value('')

    # List of finder classes that know how to find static files in
    # various locations.
    STATICFILES_FINDERS = (
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
        'django.contrib.staticfiles.finders.FileSystemFinder',
        'compressor.finders.CompressorFinder',
    )

    AUTHENTICATION_BACKENDS = [
        "froide.helper.auth.EmailBackend",
        "django.contrib.auth.backends.ModelBackend",
    ]

    TEMPLATE_CONTEXT_PROCESSORS = (
        'django.core.context_processors.debug',
        'django.core.context_processors.i18n',
        'django.core.context_processors.media',
        'django.core.context_processors.static',
        'django.core.context_processors.request',
        'django.contrib.auth.context_processors.auth',
        'django.contrib.messages.context_processors.messages',
        'froide.helper.context_processors.froide',
        'froide.helper.context_processors.site_settings')

    # List of callables that know how to import templates from various sources.
    TEMPLATE_LOADERS = [
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
    ]

    MIDDLEWARE_CLASSES = [
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.locale.LocaleMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
    ]

    # ######### I18N and L10N ##################

    # Local time zone for this installation. Choices can be found here:
    # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
    # although not all choices may be available on all operating systems.
    # On Unix systems, a value of None will cause Django to use the same
    # timezone as the operating system.
    # If running in a Windows environment this must be set to the same as your
    # system time zone.
    TIME_ZONE = values.Value('Europe/Berlin')
    USE_TZ = values.BooleanValue(True)

    # Language code for this installation. All choices can be found here:
    # http://www.i18nguy.com/unicode/language-identifiers.html
    LANGUAGE_CODE = values.Value('en-us')
    LANGUAGES = (
        ('en', gettext('English')),
        ('es', gettext('Spanish')),
        ('fi-fi', gettext('Finnish (Finland)')),
        ('de', gettext('German')),
        ('da-dk', gettext('Danish (Denmark)')),
        ('it', gettext('Italian')),
        ('pt', gettext('Portuguese')),
        ('sv-se', gettext('Swedish (Sweden)')),
        ('sv-fi', gettext('Swedish (Finland)')),
        ('zh-cn', gettext('Chinese (Simplified)')),
        ('zh-hk', gettext('Chinese (Traditional, Hong Kong)')),
    )

    # If you set this to False, Django will make some optimizations so as not
    # to load the internationalization machinery.
    USE_I18N = values.BooleanValue(True)

    # If you set this to False, Django will not format dates, numbers and
    # calendars according to the current locale
    USE_L10N = values.BooleanValue(True)

    DATE_FORMAT = values.Value("d. F Y")
    SHORT_DATE_FORMAT = values.Value("d.m.Y")
    DATE_INPUT_FORMATS = values.TupleValue(("%d.%m.%Y", ))
    SHORT_DATETIME_FORMAT = values.Value("d.m.Y H:i")
    DATETIME_INPUT_FORMATS = values.TupleValue(("%d.%m.%Y %H:%M", ))
    TIME_FORMAT = values.Value("H:i")
    TIME_INPUT_FORMATS = values.TupleValue(("%H:%M", ))

    HOLIDAYS = [
        (1, 1),  # New Year's Day
        (12, 25),  # Christmas
        (12, 26)  # Second day of Christmas
    ]

    # Weekends are non-working days
    HOLIDAYS_WEEKENDS = True

    # Calculates other holidays based on easter sunday
    HOLIDAYS_FOR_EASTER = (0, -2, 1, 39, 50, 60)

    # ######## Logging ##########

    # A sample logging configuration.
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': True,
        'root': {
            'level': 'WARNING',
            'handlers': [],
        },
        'filters': {
            'require_debug_false': {
                '()': 'django.utils.log.RequireDebugFalse'
            }
        },
        'formatters': {
            'verbose': {
                'format':
                '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
            },
        },
        'handlers': {
            'mail_admins': {
                'level': 'ERROR',
                'filters': ['require_debug_false'],
                'class': 'django.utils.log.AdminEmailHandler'
            },
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            }
        },
        'loggers': {
            'froide': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'DEBUG',
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': True,
            },
            'django.db.backends': {
                'level': 'ERROR',
                'handlers': ['console'],
                'propagate': False,
            }
        }
    }

    # ######## Security ###########

    CSRF_COOKIE_SECURE = False
    CSRF_COOKIE_HTTPONLY = True
    CSRF_FAILURE_VIEW = values.Value('froide.account.views.csrf_failure')

    # Change this
    # ALLOWED_HOSTS = ()

    SESSION_COOKIE_AGE = values.IntegerValue(3628800)  # six weeks
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False

    # ######## Celery #############

    CELERY_RESULT_BACKEND = values.Value(
        'djcelery.backends.database:DatabaseBackend')
    CELERYBEAT_SCHEDULER = values.Value(
        "djcelery.schedulers.DatabaseScheduler")
    CELERY_ALWAYS_EAGER = values.BooleanValue(True)

    CELERY_ROUTES = {
        'froide.foirequest.tasks.fetch_mail': {
            "queue": "emailfetch"
        },
    }
    CELERY_TIMEZONE = TIME_ZONE

    # ######## Haystack ###########

    HAYSTACK_CONNECTIONS = {
        'default': {
            'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
        }
    }

    # ######### Tastypie #########

    TASTYPIE_SWAGGER_API_MODULE = values.Value('froide.urls.v1_api')

    # ######### Froide settings ########

    FROIDE_THEME = None

    FROIDE_CONFIG = dict(
        create_new_publicbody=True,
        publicbody_empty=True,
        user_can_hide_web=True,
        public_body_officials_public=True,
        public_body_officials_email_public=False,
        request_public_after_due_days=14,
        payment_possible=True,
        currency="Euro",
        default_law=1,
        search_engine_query=
        "http://www.google.de/search?as_q=%(query)s&as_epq=&as_oq=&as_eq=&hl=en&lr=&cr=&as_ft=i&as_filetype=&as_qdr=all&as_occt=any&as_dt=i&as_sitesearch=%(domain)s&as_rights=&safe=images",
        greetings=[rec(u"Dear (?:Mr\.?|Ms\.? .*?)")],
        closings=[rec(u"Sincerely yours,?")],
        public_body_boosts={},
        dryrun=False,
        request_throttle=
        None,  # Set to [(15, 7 * 24 * 60 * 60),] for 15 requests in 7 days
        dryrun_domain="testmail.example.com",
        allow_pseudonym=False,
        doc_conversion_binary=None,  # replace with libreoffice instance
        doc_conversion_call_func=None,  # see settings_test for use
    )

    # ###### Email ##############

    # Django settings

    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    EMAIL_SUBJECT_PREFIX = values.Value('[Froide] ')
    SERVER_EMAIL = values.Value('*****@*****.**')
    DEFAULT_FROM_EMAIL = values.Value('*****@*****.**')

    # Official Notification Mail goes through
    # the normal Django SMTP Backend
    EMAIL_HOST = values.Value("")
    EMAIL_PORT = values.IntegerValue(587)
    EMAIL_HOST_USER = values.Value("")
    EMAIL_HOST_PASSWORD = values.Value("")
    EMAIL_USE_TLS = values.BooleanValue(True)

    # Froide special case settings
    # IMAP settings for fetching mail
    FOI_EMAIL_PORT_IMAP = values.IntegerValue(993)
    FOI_EMAIL_HOST_IMAP = values.Value("imap.example.com")
    FOI_EMAIL_ACCOUNT_NAME = values.Value("*****@*****.**")
    FOI_EMAIL_ACCOUNT_PASSWORD = values.Value("")
    FOI_EMAIL_USE_SSL = values.BooleanValue(True)

    # SMTP settings for sending FoI mail
    FOI_EMAIL_HOST_USER = values.Value(FOI_EMAIL_ACCOUNT_NAME)
    FOI_EMAIL_HOST_FROM = values.Value(FOI_EMAIL_HOST_USER)
    FOI_EMAIL_HOST_PASSWORD = values.Value(FOI_EMAIL_ACCOUNT_PASSWORD)
    FOI_EMAIL_HOST = values.Value("smtp.example.com")
    FOI_EMAIL_PORT = values.IntegerValue(537)
    FOI_EMAIL_USE_TLS = values.BooleanValue(True)

    # The FoI Mail can use a different account
    FOI_EMAIL_DOMAIN = values.Value("example.com")

    FOI_EMAIL_TEMPLATE = None
    # Example:
    # FOI_EMAIL_TEMPLATE = lambda user_name, secret: "{username}.{secret}@{domain}" % (user_name, secret, FOI_EMAIL_DOMAIN)

    # Is the message you can send from fixed
    # or can you send from any address you like?
    FOI_EMAIL_FIXED_FROM_ADDRESS = values.BooleanValue(True)
Ejemplo n.º 18
0
class BaseSettings(Configuration):
    """
    Django settings for qcat project.

    For more information on this file, see
    https://docs.djangoproject.com/en/dev/topics/settings/

    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/dev/ref/settings/
    """

    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = join(dirname(dirname(dirname(dirname(__file__)))))

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = values.BooleanValue(default=False)

    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

    # Application definition
    INSTALLED_APPS = (
        'django.contrib.contenttypes',
        'grappelli.dashboard',
        'grappelli',
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.sitemaps',
        'django.contrib.staticfiles',
        'django.contrib.humanize',
        'compressor',
        'cookielaw',
        'corsheaders',
        'django_extensions',
        'django_filters',
        'easy_thumbnails',
        'easy_thumbnails.optimize',
        'floppyforms',
        'imagekit',
        'maintenancemode',
        'rest_framework',
        'rest_framework_swagger',
        'sekizai',
        'wkhtmltopdf',
        # Custom apps
        'accounts',
        'api',
        'approaches',
        'configuration',
        'qcat',
        'questionnaire',
        'notifications',
        'sample',
        'samplemulti',
        'samplemodule',
        'search',
        'summary',
        'technologies',
        'unccd',
        'watershed',
        'wocat',
        'cca',
        'cbp',
    )

    MIDDLEWARE_CLASSES = (
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.security.SecurityMiddleware',
        'django.middleware.locale.LocaleMiddleware',
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'maintenancemode.middleware.MaintenanceModeMiddleware',
        'qcat.middleware.ProfilerMiddleware',
    )

    ROOT_URLCONF = 'qcat.urls'

    WSGI_APPLICATION = 'qcat.wsgi.application'

    # Internationalization
    # https://docs.djangoproject.com/en/dev/topics/i18n/
    LANGUAGE_CODE = 'en'

    LOCALE_PATHS = (
        join(BASE_DIR, 'locale'),
    )

    # The first language is the default language.
    # Important: If you add languages here, make sure to add a placeholder of
    # the infographic in src/assets/img/infographics (make a copy of the English
    # version)
    LANGUAGES = (
        ('en', _('English')),
        ('fr', _('French')),
        ('es', _('Spanish')),
        ('ru', _('Russian')),
        ('zh', _('Chinese')),
        ('km', _('Khmer')),
        ('lo', _('Lao')),
        ('ar', _('Arabic')),
        ('pt', _('Portuguese')),
        ('af', _('Afrikaans')),
        ('th', _('Thai')),
        ('mn', _('Mongolian')),
    )
    # languages with extraordinarily long words that need 'forced' line breaks
    # to remain consistent in the box-layout.
    WORD_WRAP_LANGUAGES = [
        'km',
        'lo',
        'th',
    ]

    TIME_ZONE = 'Europe/Zurich'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True
    BASE_URL = values.Value(environ_prefix='', default='https://qcat.wocat.net')

    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/dev/howto/static-files/
    STATIC_URL = '/static/'
    STATIC_ROOT = join(BASE_DIR, '..', 'static')
    STATICFILES_DIRS = (
        join(BASE_DIR, 'static'),
    )
    STATICFILES_FINDERS = (
        'django.contrib.staticfiles.finders.FileSystemFinder',
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
        'compressor.finders.CompressorFinder',
    )

    MEDIA_URL = '/upload/'
    MEDIA_ROOT = join(BASE_DIR, '..', 'upload')

    UPLOAD_VALID_FILES = {
        'image': (
            ('image/jpeg', 'jpg'),
            ('image/png', 'png'),
            ('image/gif', 'gif'),
        ),
        'document': (
            ('application/pdf', 'pdf'),
        )
    }
    UPLOAD_MAX_FILE_SIZE = 3145728  # 3 MB
    UPLOAD_IMAGE_THUMBNAIL_FORMATS = (
        ('default', (640, 480)),
        ('small', (1024, 768)),
        ('medium', (1440, 1080)),
        # 'large' is the original uploaded image.
    )
    THUMBNAIL_ALIASES = {
        'summary': {
            'screen': {
                'header_image': {
                    'size': (1542, 767),
                    'upscale': True,
                    'crop': True,
                    'target': (50, 50),
                },
                'half_height': {
                    'size': (640, 640),
                    'upscale': True,
                    'crop': True,
                },
                'map': {
                    'size': (560, 0)
                },
                'flow_chart': {
                    'size': (900, 0),
                    'upscale': False
                },
                'flow_chart_half_height': {
                    'size': (640, 640),
                    'upscale': True,
                }
            },
            'print': {
                'header_image': {
                    'size': (6168, 3068),
                    'crop': True,
                    'upscale': True,
                },
                'half_height': {
                    'size': (2560, 2560),
                    'upscale': True,
                    'crop': True,
                },
                'map': {
                    'size': (2240, 0)
                },
                'flow_chart': {
                    'size': (3600, 0),
                    'upscale': False
                },
                'flow_chart_half_height': {
                    'size': (2560, 2560),
                    'upscale': True,
                }
            }
        }
    }

    SUMMARY_PDF_PATH = join(MEDIA_ROOT, 'summary-pdf')

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [
                join(BASE_DIR, 'templates'),
            ],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.contrib.auth.context_processors.auth',
                    'django.template.context_processors.debug',
                    'django.template.context_processors.i18n',
                    'django.template.context_processors.media',
                    'django.template.context_processors.static',
                    'django.template.context_processors.tz',
                    'django.contrib.messages.context_processors.messages',
                    'django.template.context_processors.request',
                    'sekizai.context_processors.sekizai',
                    'qcat.context_processors.template_settings'
                ],
            }
        }
    ]



    AUTH_USER_MODEL = 'accounts.User'
    AUTHENTICATION_BACKENDS = (
        'accounts.authentication.WocatCMSAuthenticationBackend',
    )
    REACTIVATE_WOCAT_ACCOUNT_URL = values.URLValue(
        environ_prefix='', default='https://wocat.net/accounts/reactivate/'
    )
    LOGIN_URL = 'login'

    GRAPPELLI_ADMIN_TITLE = 'QCAT Administration'
    GRAPPELLI_INDEX_DASHBOARD = 'qcat.dashboard.CustomIndexDashboard'

    # Elasticsearch settings
    ES_HOST = values.Value(default='localhost', environ_prefix='')
    ES_PORT = values.IntegerValue(default=9200, environ_prefix='')
    ES_INDEX_PREFIX = values.Value(default='qcat_', environ_prefix='')
    # For Elasticsearch >= 2.3: https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-2.3.html  # noqa
    ES_NESTED_FIELDS_LIMIT = values.IntegerValue(default=250, environ_prefix='')
    # For each language (as set in the setting ``LANGUAGES``), a language
    # analyzer can be specified. This helps to analyze the text in the
    # corresponding language for better search results.
    # https://www.elastic.co/guide/en/elasticsearch/reference/1.6/analysis-lang-analyzer.html  # noqa
    ES_ANALYZERS = (
        ('en', 'english'),
        ('es', 'spanish'),
    )
    # https://www.elastic.co/guide/en/elasticsearch/reference/2.0/query-dsl-query-string-query.html#_reserved_characters
    ES_QUERY_RESERVED_CHARS = ['\\', '+', '-', '=', '&&', '||', '>', '<', '!', '(', ')', '{', '}', '[', ']', '^', '"',
                               '~', '*', '?', ':', '/']

    MESSAGE_TAGS = {
        messages.INFO: 'secondary',
    }

    # Allow various formats to communicate with the API.
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework.parsers.JSONParser',
            'rest_framework_xml.parsers.XMLParser',
        ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework.renderers.JSONRenderer',
            'rest_framework_xml.renderers.XMLRenderer',
            'rest_framework_csv.renderers.CSVRenderer',
        ),
        'DEFAULT_THROTTLE_RATES': {
            'anon': '10/day',
            'user': '******',
        },
        'DEFAULT_VERSIONING_CLASS':
            'rest_framework.versioning.NamespaceVersioning',
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 25,
    }
    SWAGGER_SETTINGS = {
        'DOC_EXPANSION': 'list',
        'JSON_EDITOR': True,
        'VALIDATOR_URL': None,
    }
    API_PAGE_SIZE = values.IntegerValue(default=25, environ_prefix='')

    CORS_ORIGIN_WHITELIST = values.ListValue(environ_prefix='', default=[])

    DATABASES = values.DatabaseURLValue(environ_required=True)

    ALLOWED_HOSTS = values.ListValue(default=['localhost', '127.0.0.1'])

    SECRET_KEY = values.SecretValue(environ_required=True)

    # The base URL of the REST API used for authentication
    AUTH_API_URL = values.Value(environ_prefix='', default='https://www.wocat.net/api/v1/')

    # The username used for API login
    AUTH_API_USER = values.Value(environ_prefix='')

    # The key used for API login
    AUTH_API_KEY = values.Value(environ_prefix='')
    AUTH_API_TOKEN = values.Value(environ_prefix='')

    # The URL of the WOCAT authentication form. Used to handle both login
    # and logout
    AUTH_LOGIN_FORM = values.Value(
        environ_prefix='',
        default='https://dev.wocat.net/en/sitefunctions/login.html'
    )
    AUTH_COOKIE_NAME = values.Value(default='fe_typo_user', environ_prefix='')

    # Specify specific editions to be used in the filter. If not specified,
    # always the latest edition of a configuration is used. Specify specific
    # editions as a dict in the env.
    # Example to use edition 2015 to filter Technologies:
    # {"technologies": "2015"}
    FILTER_EDITIONS = values.DictValue(default={}, environ_prefix='')

    # https://raw.githubusercontent.com/SeleniumHQ/selenium/master/py/CHANGES
    # for the latest supported firefox version.
    TESTING_FIREFOX_PATH = values.Value(environ_prefix='')
    TESTING_CHROMEDRIVER_PATH = values.Value(
        environ_prefix='', default='/usr/local/bin/chromedriver')
    TESTING_POP_BROWSER = values.BooleanValue(environ_prefix='', default=False)

    # Flag for caching of the whole configuration object. Sections are always cached.
    USE_CACHING = values.BooleanValue(default=True)
    # django-cache-url doesn't support the redis package of our choice, set the redis location as
    # common environment (dict)value.
    CACHES = values.DictValue(environ_prefix='')
    KEY_PREFIX = values.Value(environ_prefix='', default='')

    # If set to true, the template 503.html is displayed.
    MAINTENANCE_MODE = values.BooleanValue(environ_prefix='', default=False)
    MAINTENANCE_LOCKFILE_PATH = join(BASE_DIR, 'maintenance.lock')

    # "Feature toggles"
    IS_ACTIVE_FEATURE_MODULE = values.BooleanValue(
        environ_prefix='', default=True
    )
    IS_ACTIVE_FEATURE_WATERSHED = values.BooleanValue(
        environ_prefix='', default=False
    )
    IS_ACTIVE_FEATURE_MEMORY_PROFILER = values.BooleanValue(
        environ_prefix='', default=False
    )

    HOST_STRING_DEV = values.Value(environ_prefix='')
    HOST_STRING_DEMO = values.Value(environ_prefix='')
    HOST_STRING_LIVE = values.Value(environ_prefix='')

    # touch file to reload uwsgi
    TOUCH_FILE_DEV = values.Value(environ_prefix='')
    TOUCH_FILE_DEMO = values.Value(environ_prefix='')
    TOUCH_FILE_LIVE = values.Value(environ_prefix='')

    SENTRY_DSN = values.Value(environ_prefix='')
    SLACK_TOKEN = values.Value(environ_prefix='')

    WARN_HEADER = values.Value(environ_prefix='')
    NEXT_MAINTENANCE = join(BASE_DIR, 'envs/NEXT_MAINTENANCE')
    DEPLOY_TIMEOUT = values.Value(environ_prefix='', default=900)

    # Settings for piwik integration. Tracking happens in the frontend
    # (base template) and backend (API)
    PIWIK_SITE_ID = values.IntegerValue(environ_prefix='', default=None)
    PIWIK_URL = values.Value(environ_prefix='', default='https://webstats.wocat.net/')
    PIWIK_AUTH_TOKEN = values.Value(environ_prefix='')
    PIWIK_API_VERSION = values.IntegerValue(environ_prefix='', default=1)

    # google webdeveloper verification
    GOOGLE_WEBMASTER_TOOLS_KEY = values.Value(environ_prefix='')

    # Google Maps Javascript API key
    GOOGLE_MAPS_JAVASCRIPT_API_KEY = values.Value(environ_prefix='')

    # Mail settings (notification mails)
    DEFAULT_FROM_EMAIL = '*****@*****.**'
    DO_SEND_EMAILS = values.BooleanValue(environ_prefix='', default=True)
    DO_SEND_STAFF_ONLY = values.BooleanValue(environ_prefix='', default=False)

    WOCAT_IMPORT_DATABASE_URL = values.Value(environ_prefix='')
    WOCAT_IMPORT_DATABASE_URL_LOCAL = values.Value(environ_prefix='')
    WOCAT_CONTACT_PAGE = values.Value(
        environ_prefix='',
        default='https://www.wocat.net/about/wocat-secretariat'
    )
    WOCAT_MAILBOX_USER_ID = values.IntegerValue(environ_prefix='')

    # TODO: Temporary test of UNCCD flagging.
    TEMP_UNCCD_TEST = values.ListValue(environ_prefix='')

    CDE_SUBNET_ADDR = values.Value(environ_prefix='', default='0.0.0.')

    # Prevent error when submitting very large forms. Default is 1000.
    # (https://docs.djangoproject.com/en/2.0/ref/settings/#data-upload-max-number-fields)
    DATA_UPLOAD_MAX_NUMBER_FIELDS = 2000
Ejemplo n.º 19
0
class Common(Configuration):
    """Common configuration base class."""

    SECRET_KEY = '(_j4e0=pbe(b+b1$^ch_48be0=gszglcgfzz^dy=(gnx=@m*b7'

    DEBUG = values.BooleanValue(False)

    MAIL_ADMINS = values.BooleanValue(False)

    ADMINS = AdminsValue((('Max Brauer', '*****@*****.**'), ))
    MANAGERS = ADMINS

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'filters': {
            'require_debug_false': {
                '()': 'django.utils.log.RequireDebugFalse',
            },
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            },
        },
        'handlers': {
            'console': {
                'level': 'INFO',
                'filters': ['require_debug_true'],
                'class': 'logging.StreamHandler',
            },
            'null': {
                'class': 'logging.NullHandler',
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler'
            }
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': False,
            },
            'django.security': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': False,
            },
            'django.security.DisallowedHost': {
                'handlers': ['null'],
                'propagate': False,
            },
            'py.warnings': {
                'handlers': ['console'],
            },
        }
    }

    ALLOWED_HOSTS = values.ListValue(['www.example.com'])

    SITE_ID = values.IntegerValue(1)

    # Internationalization
    # https://docs.djangoproject.com/en/dev/topics/i18n/
    LANGUAGE_CODE = values.Value('en-us')

    TIME_ZONE = values.Value('Europe/Berlin')

    USE_I18N = True

    USE_L10N = True

    USE_TZ = True

    # Absolute filesystem path to the directory that will hold user-uploaded files.
    # Example: "/var/www/example.com/media/"
    MEDIA_ROOT = values.PathValue(os.path.join(BaseDir.BASE_DIR, 'media'))

    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://example.com/media/", "http://media.example.com/"
    MEDIA_URL = values.Value('/media/')

    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/var/www/example.com/static/"
    STATIC_ROOT = values.PathValue(
        os.path.join(BaseDir.BASE_DIR, 'static_root'))

    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/dev/howto/static-files/
    STATIC_URL = values.Value('/static/')

    # Additional locations of static files
    STATICFILES_DIRS = (
        # Put strings here, like "/home/html/static" or "C:/www/django/static".
        # Always use forward slashes, even on Windows.
        # Don't forget to use absolute paths, not relative paths.
        os.path.join(BaseDir.BASE_DIR, 'static'),
        os.path.join(os.path.dirname(BaseDir.BASE_DIR), 'node_modules',
                     'normalize.css'),
    )

    STATICFILES_FINDERS = values.ListValue([
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
        'django.contrib.staticfiles.finders.FileSystemFinder',
        'sass_processor.finders.CssFinder',
        #    'django.contrib.staticfiles.finders.DefaultStorageFinder',
    ])

    MIDDLEWARE_CLASSES = values.ListValue([
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'django.middleware.security.SecurityMiddleware',
    ])

    ROOT_URLCONF = 'bureau.config.urls'

    WSGI_APPLICATION = 'bureau.config.wsgi.application'

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [
                os.path.join(BaseDir.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',
                    'bureau.context_processors.django_version',
                ],
                'debug':
                values.BooleanValue(
                    False, environ_name='DJANGO_TEMPLATES_TEMPLATE_DEBUG'),
                'string_if_invalid':
                values.Value(
                    '', environ_name='DJANGO_TEMPLATES_STRING_IF_INVALID'),
            },
        },
    ]

    # the following line is only necessary because django-template-debug uses it
    TEMPLATE_DEBUG = TEMPLATES[0]['OPTIONS'].get('debug', False)

    FIXTURE_DIRS = (os.path.join(BaseDir.BASE_DIR, 'fixtures'), )

    INSTALLED_APPS = (
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'django.contrib.admin',
        'django.contrib.admindocs',
        'sass_processor',
        'bureau.apps.core.apps.CoreConfig',
    )

    CACHES = values.DictValue({
        'default': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        }
    })

    EMAIL_SUBJECT_PREFIX = '[bureau]'

    DEFAULT_FROM_EMAIL = values.EmailValue('*****@*****.**')

    SERVER_EMAIL = DEFAULT_FROM_EMAIL
class Base(Core):
    """Settings that may change per-environment, some with defaults."""
    @classmethod
    def setup(cls):
        super(Base, cls).setup()

        # For the sake of convenience we want to make UPLOAD_TRY_SYMBOLS_URL
        # optional as an environment variable. If it's not set, set it
        # by taking the UPLOAD_DEFAULT_URL and adding the prefix "/try"
        # right after the bucket name.
        if not cls.UPLOAD_TRY_SYMBOLS_URL:
            default_url = urlparse(cls.UPLOAD_DEFAULT_URL)
            path = default_url.path.split("/")
            # Since it always start with '/', the point after the bucket
            # name is the 3rd one.
            path.insert(2, "try")
            # Note `._replace` is actually not a private method.
            try_url = default_url._replace(path="/".join(path))
            cls.UPLOAD_TRY_SYMBOLS_URL = try_url.geturl()

    SECRET_KEY = values.SecretValue()

    DEBUG = values.BooleanValue(default=False)
    DEBUG_PROPAGATE_EXCEPTIONS = values.BooleanValue(default=False)

    ALLOWED_HOSTS = values.ListValue([])

    DATABASES = values.DatabaseURLValue("postgres://postgres@db/postgres")
    CONN_MAX_AGE = values.IntegerValue(60)

    REDIS_URL = values.Value("redis://redis-cache:6379/0")
    REDIS_STORE_URL = values.Value("redis://redis-store:6379/0")

    REDIS_SOCKET_CONNECT_TIMEOUT = values.IntegerValue(1)
    REDIS_SOCKET_TIMEOUT = values.IntegerValue(2)
    REDIS_STORE_SOCKET_CONNECT_TIMEOUT = values.IntegerValue(1)
    REDIS_STORE_SOCKET_TIMEOUT = values.IntegerValue(2)

    # Use redis as the Celery broker.
    @property
    def CELERY_BROKER_URL(self):
        return self.REDIS_URL

    # This name is hardcoded inside django-redis. It it's set to true in `settings`
    # it means that django-redis will attempt WARNING log any exceptions that
    # happen with the connection when it swallows the error(s).
    DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = values.BooleanValue(True)

    REDIS_IGNORE_EXCEPTIONS = values.BooleanValue(True)

    @property
    def CACHES(self):
        return {
            "default": {
                "BACKEND": "django_redis.cache.RedisCache",
                "LOCATION": self.REDIS_URL,
                "OPTIONS": {
                    "COMPRESSOR":
                    "django_redis.compressors.zlib.ZlibCompressor",  # noqa
                    # "SERIALIZER": "django_redis.serializers.msgpack.MSGPackSerializer",  # noqa
                    "SERIALIZER":
                    "tecken.cache_extra.MSGPackSerializer",  # noqa
                    "SOCKET_CONNECT_TIMEOUT":
                    self.REDIS_SOCKET_CONNECT_TIMEOUT,
                    "SOCKET_TIMEOUT": self.REDIS_SOCKET_TIMEOUT,
                    "IGNORE_EXCEPTIONS": self.REDIS_IGNORE_EXCEPTIONS,
                },
            },
            "store": {
                "BACKEND": "django_redis.cache.RedisCache",
                "LOCATION": self.REDIS_STORE_URL,
                "OPTIONS": {
                    "COMPRESSOR":
                    "django_redis.compressors.zlib.ZlibCompressor",  # noqa
                    "SERIALIZER":
                    "tecken.cache_extra.MSGPackSerializer",  # noqa
                    "SOCKET_CONNECT_TIMEOUT":
                    self.REDIS_STORE_SOCKET_CONNECT_TIMEOUT,
                    "SOCKET_TIMEOUT": self.REDIS_STORE_SOCKET_TIMEOUT,
                },
            },
        }

    LOGGING_USE_JSON = values.BooleanValue(False)

    LOGGING_DEFAULT_LEVEL = values.Value("INFO")

    def LOGGING(self):
        config = {
            "version": 1,
            "disable_existing_loggers": False,
            "formatters": {
                "json": {
                    "()": "dockerflow.logging.JsonLogFormatter",
                    "logger_name": "tecken",
                },
                "verbose": {
                    "format": "%(levelname)s %(asctime)s %(name)s %(message)s"
                },
            },
            "handlers": {
                "console": {
                    "level": self.LOGGING_DEFAULT_LEVEL,
                    "class": "logging.StreamHandler",
                    "formatter":
                    ("json" if self.LOGGING_USE_JSON else "verbose"),
                },
                "sentry": {
                    "level":
                    "ERROR",
                    "class":
                    ("raven.contrib.django.raven_compat.handlers.SentryHandler"
                     ),
                },
                "null": {
                    "class": "logging.NullHandler"
                },
            },
            "root": {
                "level": "INFO",
                "handlers": ["sentry", "console"]
            },
            "loggers": {
                "django": {
                    "level": "INFO",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "django.db.backends": {
                    "level": "ERROR",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "django.request": {
                    "level": "INFO",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "raven": {
                    "level": "DEBUG",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "sentry.errors": {
                    "level": "DEBUG",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "tecken": {
                    "level": "DEBUG",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "mozilla_django_oidc": {
                    "level": "DEBUG",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "celery.task": {
                    "level": "DEBUG",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "markus": {
                    "level": "INFO",
                    "handlers": ["console"],
                    "propagate": False,
                },
                "request.summary": {
                    "handlers": ["console"],
                    "level": "INFO",
                    "propagate": False,
                },
                "django.security.DisallowedHost": {
                    "handlers": ["null"],
                    "propagate": False,
                },
                "django_redis.cache": {
                    "level": "INFO",
                    "handlers": ["console"],
                    "propagate": False,
                },
            },
        }
        if not self.LOGGING_USE_JSON:
            # If you're not using JSON logging, there's no point using the
            # 'request.summary' logger that python-dockerflow uses.
            config["loggers"]["request.summary"]["handlers"] = []
        return config

    CSRF_FAILURE_VIEW = "tecken.views.csrf_failure"
    CSRF_USE_SESSIONS = values.BooleanValue(True)

    # The order here matters. Symbol download goes through these one at a time.
    # Ideally you want the one most commonly hit first unless there's a
    # cascading reason you want other buckets first.
    # By default, each URL is assumed to be private!
    # If there's a bucket you want to include that should be accessed
    # by HTTP only, add '?access=public' to the URL.
    # Note that it's empty by default which is actually not OK.
    # For production-like environments this must be something or else
    # Django won't start. (See tecken.apps.TeckenAppConfig)
    #
    SYMBOL_URLS = values.ListValue([])

    # Same as with SYMBOL_URLS, this has to be set to something
    # or else Django won't start.
    UPLOAD_DEFAULT_URL = values.Value()

    # When an upload comes in with symbols from a Try build, these symbols
    # mustn't be uploaded with the "regular symbols".
    # This value can be very similar to UPLOAD_DEFAULT_URL in that
    # it can use the exact same S3 bucket but have a different prefix.
    #
    # Note! By default the value for 'UPLOAD_TRY_SYMBOLS_URL' becomes
    # the value of 'UPLOAD_DEFAULT_URL' but with a '/try' suffix added.
    UPLOAD_TRY_SYMBOLS_URL = values.Value()
    # # The reason for this is to simplify things in local dev and non-Prod
    # # environments where the location isn't as important.
    # # Basically, if don't set this, the value
    # # becomes `settings.UPLOAD_DEFAULT_URL + '/try'` (but carefully so)
    # @property
    # def UPLOAD_TRY_SYMBOLS_URL(self):
    #     print(Configuration.LANGUAGES)
    #     print(Configuration.UPLOAD_TRY_SYMBOLS_URL)
    #     # # super()
    #     # print(dir(self))
    #     # print(self.UPLOAD_TRY_SYMBOLS_URL.value.copy())
    #     return '/TRY'
    #     value = super().value
    #     return value + '/TRY'

    # The config is a list of tuples like this:
    # 'email:url' where the email part can be a glob like regex
    # For example '*@example.com:https://s3-us-west-2.amazonaws.com/mybucket'
    # will upload all symbols to a bucket called 'mybucket' for anybody
    # with a @example.com email.

    # This is a config that, typed as a Python dictionary, specifies
    # specific email addresses or patterns to custom URLs.
    # For example '{"*****@*****.**": "https://s3.amazonaws.com/mybucket"}'
    # or '{"*@example.com": "https://s3.amazonaws.com/otherbucket"}' for
    # anybody uploading with an @example.com email address.
    UPLOAD_URL_EXCEPTIONS = values.DictValue({})

    # XXX Can this be deleted?
    # When an upload comes in, we need to store it somewhere that it
    # can be shared between the webapp and the Celery worker.
    # In production-like environments this can't be a local filesystem
    # path but needs to one that is shared across servers. E.g. EFS.
    # UPLOAD_INBOX_DIRECTORY = values.Value("./upload-inbox")

    # The default prefix for locating all symbols
    SYMBOL_FILE_PREFIX = values.Value("v1")

    # During upload, for each file in the archive, if the extension
    # matches this list, the file gets gzip compressed before uploading.
    COMPRESS_EXTENSIONS = values.ListValue(["sym"])

    # For specific file uploads, override the mimetype.
    # For .sym files, for example, if S3 knows them as 'text/plain'
    # they become really handy to open in a browser and view directly.
    MIME_OVERRIDES = values.DictValue({"sym": "text/plain"})

    # Number of seconds to wait for a symbol download. If this
    # trips, no error will be raised and we'll just skip using it
    # as a known symbol file.
    # The value gets cached as an empty dict for one hour.
    SYMBOLS_GET_TIMEOUT = values.Value(5)

    # Individual strings that can't be allowed in any of the lines in the
    # content of a symbols archive file.
    DISALLOWED_SYMBOLS_SNIPPETS = values.ListValue([
        # https://bugzilla.mozilla.org/show_bug.cgi?id=1012672
        "qcom/proprietary"
    ])

    DOCKERFLOW_CHECKS = [
        "dockerflow.django.checks.check_database_connected",
        "dockerflow.django.checks.check_migrations_applied",
        "dockerflow.django.checks.check_redis_connected",
        "tecken.dockerflow_extra.check_redis_store_connected",
        "tecken.dockerflow_extra.check_storage_urls",
    ]

    # We can cache quite aggressively here because the SymbolDownloader
    # has chance to invalidate certain keys.
    # Also, any time a symbol archive file is upload, for each file within
    # that we end up uploading to S3 we also cache invalidate.
    SYMBOLDOWNLOAD_EXISTS_TTL_SECONDS = values.IntegerValue(60 * 60 * 6)

    # Whether to start a background task to search for symbols
    # on Microsoft's server is protected by an in-memory cache.
    # This is quite important. Don't make it too long or else clients
    # won't be able retry to see if a Microsoft symbol has been successfully
    # downloaded by the background job.
    # We can tweak this when we later learn more about the amount
    # attempted symbol downloads for .pdb files we get that 404.
    MICROSOFT_DOWNLOAD_CACHE_TTL_SECONDS = values.IntegerValue(60)

    # cabextract is installed by Docker and used to unpack .pd_ files to .pdb
    # It's assumed to be installed on $PATH.
    CABEXTRACT_PATH = values.Value("cabextract")

    # dump_syms is downloaded and installed by docker/build_dump_syms.sh
    # and by default gets to put this specific location.
    # If you change this, please make sure it works with
    # how docker/build_dump_syms.sh works.
    DUMP_SYMS_PATH = values.Value("/dump_syms/dump_syms")

    # How many uploads to display per page when paginating through
    # past uploads.
    API_UPLOADS_BATCH_SIZE = 20
    API_UPLOADS_CREATED_BATCH_SIZE = 20
    API_FILES_BATCH_SIZE = 40
    API_DOWNLOADS_MISSING_BATCH_SIZE = 20
    API_DOWNLOADS_MICROSOFT_BATCH_SIZE = 20

    # Every time we do a symbol upload, we also take a look to see if there
    # are incomplete uploads that could have failed due to some unlucky
    # temporary glitch.
    # When we do the reattempt, we need to wait sufficiently long because
    # the upload might just be incomplete because it's in the queue, not
    # because it failed.
    # Note also, if the job is put back into a celery job, we also log
    # this in the cache so that it doesn't add it more than once. That
    # caching uses this same timeout.
    UPLOAD_REATTEMPT_LIMIT_SECONDS = values.IntegerValue(60 * 60 * 12)

    # When you "upload by download", the URL's domain needs to be in this
    # whitelist. This is to double-check that we don't allow downloads from
    # domains we don't fully trust.
    ALLOW_UPLOAD_BY_DOWNLOAD_DOMAINS = values.ListValue(
        ["queue.taskcluster.net"])

    # A list of file extensions that if a file is NOT one of these extensions
    # we can immediately return 404 and not bother to process for anything
    # else.
    # It's case sensitive and has to be lower case.
    # As a way to get marginal optimization of this, make sure '.sym' is
    # first in the list since it's the most common.
    DOWNLOAD_FILE_EXTENSIONS_WHITELIST = values.ListValue(
        [".sym", ".dl_", ".ex_", ".pd_", ".dbg.gz", ".tar.bz2"])
Ejemplo n.º 21
0
class Base(Configuration):
    """
    The are correct settings that are primarily targeted at the production
    system but allow (where appriate) easy overrides either via subclassing
    or environment variables.
    """

    ###########################################################################
    #
    # General settings
    #
    PROJECT_NAME = 'pyconde'

    BASE_DIR = os.path.dirname(os.path.dirname(__file__))

    ADMINS = values.ListValue([], converter=parseaddr)

    ALLOWED_HOSTS = values.ListValue(['localhost', '127.0.0.1'])

    @property
    def MANAGERS(self):
        return self.ADMINS

    EMAIL_HOST = values.Value()

    DEFAULT_FROM_EMAIL = values.EmailValue('*****@*****.**')

    SERVER_EMAIL = values.EmailValue('*****@*****.**')

    TIME_ZONE = 'Europe/Berlin'

    LANGUAGE_CODE = 'en'

    SECRET_KEY = values.SecretValue()

    EMAIL_SUBJECT_PREFIX = values.Value('[EuroPython 2014] ')

    USE_I18N = True

    USE_L10N = True

    SITE_ID = values.IntegerValue(1)

    CONFERENCE_ID = values.IntegerValue(1)

    LANGUAGES = (
        ('de', ugettext('German')),
        ('en', ugettext('English')),
    )
    INTERNAL_IPS = ('127.0.0.1', )

    ROOT_URLCONF = '%s.urls' % PROJECT_NAME

    TEMPLATE_DIRS = (
        os.path.join(BASE_DIR, 'skins', 'default'),
        os.path.join(BASE_DIR, 'skins', 'ep14'),
    )

    INSTALLED_APPS = [
        # Skins
        'pyconde.skins.ep14',
        'pyconde.skins.default',
        'djangocms_admin_style',
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.messages',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.staticfiles',
        'django.contrib.markup',
        'crispy_forms',
        'south',
        'easy_thumbnails',
        'filer',
        'compressor',
        'djangocms_text_ckeditor',  # must be before 'cms'!
        'cms',
        'cms.stacks',
        'mptt',
        'menus',
        'sekizai',
        'userprofiles',
        'userprofiles.contrib.accountverification',
        'userprofiles.contrib.emailverification',
        'userprofiles.contrib.profiles',
        'taggit',
        'haystack',
        #'tinymce', # If you want tinymce, add it in the settings.py file.
        'django_gravatar',
        'social_auth',
        'gunicorn',
        'statici18n',
        'cms.plugins.inherit',
        'cms.plugins.googlemap',
        'cms.plugins.link',
        'cms.plugins.snippet',
        #'cms.plugins.twitter',
        #'cms.plugins.text',
        'cmsplugin_filer_file',
        'cmsplugin_filer_image',
        'djangocms_style',
        #'cmsplugin_news',
        'pyconde.testimonials',

        # Symposion apps
        'pyconde.conference',
        'pyconde.speakers',
        'pyconde.proposals',
        'pyconde.sponsorship',

        # Custom apps
        'pyconde.core',
        'pyconde.accounts',
        'pyconde.attendees',
        'pyconde.events',
        'pyconde.reviews',
        'pyconde.schedule',
        'pyconde.search',
        'pyconde.helpers',
    ]

    MIDDLEWARE_CLASSES = [
        'django.middleware.common.CommonMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.locale.LocaleMiddleware',
        'cms.middleware.page.CurrentPageMiddleware',
        'cms.middleware.user.CurrentUserMiddleware',
        'cms.middleware.toolbar.ToolbarMiddleware',
        'cms.middleware.language.LanguageCookieMiddleware',
        'social_auth.middleware.SocialAuthExceptionMiddleware',
    ]

    TEMPLATE_CONTEXT_PROCESSORS = Configuration.TEMPLATE_CONTEXT_PROCESSORS + (
        'django.core.context_processors.debug',
        'django.core.context_processors.request',
        'sekizai.context_processors.sekizai',
        'pyconde.conference.context_processors.current_conference',
        'pyconde.reviews.context_processors.review_roles',
        'pyconde.context_processors.less_settings',
        'social_auth.context_processors.social_auth_backends',
    )

    DATABASES = values.DatabaseURLValue(
        'sqlite:///{0}/djep.db'.format(BASE_DIR), environ_prefix='DJANGO')

    # Disable south migrations during unittests
    SOUTH_TESTS_MIGRATE = False

    FIXTURE_DIRS = (os.path.join(BASE_DIR, 'fixtures'), )

    # TODO: As soon as we move to foundation use
    # https://pypi.python.org/pypi/crispy-forms-foundation
    CRISPY_TEMPLATE_PACK = 'bootstrap3'

    # If the project uses Less.js, use the inline-JavaScript renderer in
    # debug mode.
    LESS_USE_DYNAMIC_IN_DEBUG = True

    LOGGING = {'version': 1, 'disable_existing_loggers': True}

    ###########################################################################
    #
    # Debug settings
    #
    DEBUG = values.BooleanValue(False)

    DEBUG_TOOLBAR_CONFIG = {'INTERCEPT_REDIRECTS': False}

    @property
    def TEMPLATE_DEBUG(self):
        return self.DEBUG

    @property
    def THUMBNAIL_DEBUG(self):
        return self.DEBUG

    ###########################################################################
    #
    # File settings
    #
    MEDIA_ROOT = values.Value()

    STATIC_ROOT = values.Value()

    MEDIA_URL = values.Value('/site_media/')

    MEDIA_OPTIPNG_PATH = values.Value('optipng')

    MEDIA_JPEGOPTIM_PATH = values.Value('jpegoptim')

    STATIC_URL = values.Value('/static_media/')

    STATICFILES_FINDERS = Configuration.STATICFILES_FINDERS + (
        'pyconde.helpers.static.AppMediaDirectoriesFinder',
        'compressor.finders.CompressorFinder',
    )

    STATICFILES_DIRS = values.ListValue()

    STATICI18N_ROOT = os.path.join(BASE_DIR, PROJECT_NAME, "core", "static")

    COMPRESS_CSS_FILTERS = (
        'compressor.filters.css_default.CssAbsoluteFilter',
        'compressor.filters.cssmin.CSSMinFilter',
    )

    THUMBNAIL_PROCESSORS = (
        'easy_thumbnails.processors.colorspace',
        'easy_thumbnails.processors.autocrop',
        'filer.thumbnail_processors.scale_and_crop_with_subject_location',
        'easy_thumbnails.processors.filters',
    )
    THUMBNAIL_SIZE = 100

    ###########################################################################
    #
    # Profile settings
    #    Here we configure what profile module is used and other aspects of a
    #    registered user's profile.
    #
    USERPROFILES_CHECK_UNIQUE_EMAIL = True

    USERPROFILES_DOUBLE_CHECK_EMAIL = False

    USERPROFILES_DOUBLE_CHECK_PASSWORD = True

    USERPROFILES_REGISTRATION_FULLNAME = True

    USERPROFILES_USE_ACCOUNT_VERIFICATION = True

    USERPROFILES_USE_EMAIL_VERIFICATION = True

    USERPROFILES_USE_PROFILE = True

    USERPROFILES_INLINE_PROFILE_ADMIN = True

    USERPROFILES_USE_PROFILE_VIEW = False

    USERPROFILES_REGISTRATION_FORM = 'pyconde.accounts.forms.ProfileRegistrationForm'

    USERPROFILES_PROFILE_FORM = 'pyconde.accounts.forms.ProfileForm'

    USERPROFILES_EMAIL_VERIFICATION_DONE_URL = 'userprofiles_profile_change'

    AUTH_PROFILE_MODULE = 'accounts.Profile'

    ACCOUNTS_FALLBACK_TO_GRAVATAR = False

    CHILDREN_DATA_DISABLED = True

    ###########################################################################
    #
    # CMS Settings
    #
    CMS_TEMPLATES = (
        ('cms/default.html', ugettext('Default template')),
        ('cms/start.html', ugettext('Start page template')),
        ('cms/page_templates/fullpage.html',
         ugettext('Full page width (schedule, ...)')),
    )

    # Docs at https://django-cms.readthedocs.org/en/develop/getting_started/configuration.html#cms-languages
    CMS_LANGUAGES = {
        1: [
            {
                'code': 'en',
                'name': ugettext('English'),
                'public': True,
            },
            {
                'code': 'de',
                'name': ugettext('German'),
                'public': True,
            },
        ],
        'default': {
            'fallbacks': ['en', 'de'],
            'hide_untranslated': False,
        }
    }

    WYM_TOOLS = ",\n".join([
        "{'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'}",
        "{'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'}",
        "{'name': 'Superscript', 'title': 'Superscript', 'css': 'wym_tools_superscript'}",
        "{'name': 'Subscript', 'title': 'Subscript', 'css': 'wym_tools_subscript'}",
        "{'name': 'InsertOrderedList', 'title': 'Ordered_List', 'css': 'wym_tools_ordered_list'}",
        "{'name': 'InsertUnorderedList', 'title': 'Unordered_List', 'css': 'wym_tools_unordered_list'}",
        "{'name': 'Indent', 'title': 'Indent', 'css': 'wym_tools_indent'}",
        "{'name': 'Outdent', 'title': 'Outdent', 'css': 'wym_tools_outdent'}",
        "{'name': 'Undo', 'title': 'Undo', 'css': 'wym_tools_undo'}",
        "{'name': 'Redo', 'title': 'Redo', 'css': 'wym_tools_redo'}",
        "{'name': 'Paste', 'title': 'Paste_From_Word', 'css': 'wym_tools_paste'}",
        "{'name': 'ToggleHtml', 'title': 'HTML', 'css': 'wym_tools_html'}",
        "{'name': 'CreateLink', 'title': 'Link', 'css': 'wym_tools_link'}",
        "{'name': 'Unlink', 'title': 'Unlink', 'css': 'wym_tools_unlink'}",
        "{'name': 'InsertImage', 'title': 'Image', 'css': 'wym_tools_image'}",
        "{'name': 'InsertTable', 'title': 'Table', 'css': 'wym_tools_table'}",
        "{'name': 'Preview', 'title': 'Preview', 'css': 'wym_tools_preview'}",
    ])

    TINYMCE_DEFAULT_CONFIG = {
        'theme':
        'advanced',
        'relative_urls':
        False,
        'theme_advanced_resizing':
        True,
        'theme_advanced_buttons1_add':
        'forecolor,backcolor',
        'style_formats': [
            {
                'title': u'Heading 2 (alternative)',
                'block': 'h2',
                'classes': 'alt'
            },
            {
                'title': u'Heading 3 (alternative)',
                'block': 'h3',
                'classes': 'alt'
            },
        ]
    }

    CMSPLUGIN_NEWS_FEED_TITLE = u'EuroPython 2014 News'

    CMSPLUGIN_NEWS_FEED_DESCRIPTION = u'News from EuroPython 2014'

    SCHEDULE_CACHE_SCHEDULE = values.BooleanValue(True)

    ###########################################################################
    #
    # Account and profile settings
    #
    AVATAR_MIN_DIMENSION = values.TupleValue(converter=int)
    AVATAR_MAX_DIMENSION = values.TupleValue(converter=int)

    ###########################################################################
    #
    # Proposal and schedule settings
    #
    ATTENDEES_PRODUCT_NUMBER_START = 1000

    PROPOSALS_SUPPORT_ADDITIONAL_SPEAKERS = True

    MAX_CHECKOUT_DURATION = 1800  # 30 minutes

    # This configures the form that is used for each proposal type identified
    # by their respective slug.
    PROPOSALS_TYPED_SUBMISSION_FORMS = {
        'training': 'pyconde.proposals.forms.TrainingSubmissionForm',
        'talk': 'pyconde.proposals.forms.TalkSubmissionForm',
        'poster': 'pyconde.proposals.forms.PosterSubmissionForm',
    }

    # These languages should be available when making a session proposal.
    PROPOSAL_LANGUAGES = (
        ('de', ugettext('German')),
        ('en', ugettext('English')),
    )

    # This setting defines the language that should be pre-selected in the
    # proposal submission form.
    PROPOSAL_DEFAULT_LANGUAGE = 'en'

    ###########################################################################
    #
    # Review settings
    #
    REVIEWER_APPLICATION_OPEN = values.BooleanValue(False)

    ###########################################################################
    #
    # Search configuration
    #    If no other search backend is specified, Whoosh is used to make the setup
    #    as simple as possible. In production we will be using a Lucene-based
    #    backend like SOLR or ElasticSearch.

    HAYSTACK_CONNECTIONS = {
        'default': {
            'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
            'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
            'STORAGE': 'file',
            'INCLUDE_SPELLING': True,
            'BATCH_SIZE': 100,
        }
    }

    ###########################################################################
    #
    # Auth settings
    #
    LOGIN_ERROR_URL = '/accounts/login/'

    LOGIN_REDIRECT_URL = '/accounts/welcome/'

    LOGOUT_REDIRECT_URL = '/'

    SOCIAL_AUTH_PIPELINE = (
        'social_auth.backends.pipeline.social.social_auth_user',
        'social_auth.backends.pipeline.user.get_username',
        'social_auth.backends.pipeline.user.create_user',
        'social_auth.backends.pipeline.social.associate_user',
        'social_auth.backends.pipeline.social.load_extra_data',
        'social_auth.backends.pipeline.user.update_user_details',
        'social_auth.backends.pipeline.misc.save_status_to_session',
        'pyconde.accounts.pipeline.show_request_email_form',
        'pyconde.accounts.pipeline.create_profile',
    )

    GITHUB_APP_ID = values.Value()

    GITHUB_API_SECRET = values.Value()

    GITHUB_EXTENDED_PERMISSIONS = ['user:email']

    TWITTER_CONSUMER_KEY = values.Value()

    TWITTER_CONSUMER_SECRET = values.Value()

    GOOGLE_OAUTH2_CLIENT_ID = values.Value()

    GOOGLE_OAUTH2_CLIENT_SECRET = values.Value()

    FACEBOOK_APP_ID = values.Value()

    FACEBOOK_API_SECRET = values.Value()

    @property
    def AUTHENTICATION_BACKENDS(self):
        backends = ['django.contrib.auth.backends.ModelBackend']
        if self.GITHUB_APP_ID and self.GITHUB_API_SECRET:
            backends.insert(
                -1, 'social_auth.backends.contrib.github.GithubBackend')
        if self.TWITTER_CONSUMER_KEY and self.WITTER_CONSUMER_SECRET:
            backends.insert(-1, 'social_auth.backends.twitter.TwitterBackend')
        if self.FACEBOOK_API_SECRET and self.FACEBOOK_APP_ID:
            backends.insert(-1,
                            'social_auth.backends.facebook.FacebookBackend')
        if self.GOOGLE_OAUTH2_CLIENT_SECRET and self.GOOGLE_OAUTH2_CLIENT_ID:
            backends.insert(-1,
                            'social_auth.backends.google.GoogleOAuth2Backend')
        return backends

    ###########################################################################
    #
    # Payment settings
    #
    PAYMILL_PRIVATE_KEY = values.Value()

    PAYMILL_PUBLIC_KEY = values.Value()

    PAYMILL_TRANSACTION_DESCRIPTION = 'EuroPython 2014: Purchase ID {purchase_pk}'

    PAYMENT_METHODS = values.ListValue(['invoice', 'creditcard'])

    PURCHASE_TERMS_OF_USE_URL = values.Value(
        "https://ep2014.europython.eu/en/registration/terms-conditions/")

    PURCHASE_INVOICE_DISABLE_RENDERING = values.BooleanValue(True)
    # List of emails to be notified when a purchase has been made. PDF is send
    # to these addresses, too.
    PURCHASE_INVOICE_EXPORT_RECIPIENTS = values.ListValue([])

    PURCHASE_INVOICE_FONT_CONFIG = values.DictValue({'de': {}, 'en': {}})

    PURCHASE_INVOICE_FONT_ROOT = values.Value(
    )  # absolute path on the filesystem

    PURCHASE_INVOICE_NUMBER_FORMAT = values.Value('INVOICE-{0:d}')

    PURCHASE_INVOICE_ROOT = values.Value()  # absolute path on the filesystem

    PURCHASE_INVOICE_TEMPLATE_PATH = values.Value(
    )  # absolute path to invoice template

    CACHES = values.DictValue({
        'default': {
            'BACKEND': 'redis_cache.cache.RedisCache',
            'LOCATION': 'localhost:6379:0',
            'OPTIONS': {
                'PARSER_CLASS': 'redis.connection.HiredisParser'
            },
        },
    })

    BROKER_URL = values.Value('redis://localhost:6379/0')

    LOCALE_PATHS = (os.path.join(BASE_DIR, PROJECT_NAME, 'locale'), )

    # Default settings for statici18n
    STATICI18N_OUTPUT_DIR = 'jsi18n'
    STATICI18N_DOMAIN = 'djangojs'
    STATICI18N_FILENAME_FUNCTION = 'statici18n.utils.default_filename'
Ejemplo n.º 22
0
class TestBase(Base):
    DEBUG = False

    @property
    def TEMPLATES(self):
        TEMP = super().TEMPLATES
        TEMP[0]['OPTIONS']['debug'] = True
        return TEMP

    def _fake_convert_pdf(self, infile, outpath):
        _, filename = os.path.split(infile)
        name, ext = filename.rsplit('.', 1)
        output = os.path.join(outpath, '%s.pdf' % name)
        args = ['cp', infile, output]
        return args, output

    @property
    def FROIDE_CONFIG(self):
        config = dict(super().FROIDE_CONFIG)
        config.update(
            dict(doc_conversion_call_func=self._fake_convert_pdf,
                 default_law=10000,
                 greetings=[
                     rec(r"Dear ((?:Mr\.?|Ms\.?) .*),?"),
                     rec(r'Sehr geehrter? ((Herr|Frau) .*),?')
                 ],
                 closings=[
                     rec(r"Sincerely yours,?"),
                     rec(r'Mit freundlichen Grüßen')
                 ],
                 public_body_officials_public=False))
        return config

    @property
    def MEDIA_ROOT(self):
        return os.path.abspath(
            os.path.join(super().PROJECT_ROOT, "tests", "testdata"))

    ALLOWED_HOSTS = ('localhost', 'testserver')

    ELASTICSEARCH_INDEX_PREFIX = 'froide_test'

    MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
    CACHES = values.CacheURLValue('locmem://')

    TEST_SELENIUM_DRIVER = values.Value('chrome_headless')

    SECRET_URLS = values.DictValue({
        "admin": "admin",
        "postmark_inbound": "postmark_inbound",
        "postmark_bounce": "postmark_bounce"
    })

    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    DEFAULT_FROM_EMAIL = '*****@*****.**'

    FOI_EMAIL_DOMAIN = 'fragdenstaat.de'

    CELERY_TASK_ALWAYS_EAGER = True
    CELERY_TASK_EAGER_PROPAGATES = True

    MIDDLEWARE = [
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
    ]
    FROIDE_CSRF_MIDDLEWARE = 'django.middleware.csrf.CsrfViewMiddleware'
Ejemplo n.º 23
0
class Base(Configuration):
    DEBUG = values.BooleanValue(True)

    DATABASES = values.DatabaseURLValue('spatialite:///dev.db')
    SPATIALITE_LIBRARY_PATH = '/usr/local/lib/mod_spatialite.dylib'
    CONN_MAX_AGE = None

    INSTALLED_APPS = values.ListValue([
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'django.contrib.admin',
        'django_comments',
        'django.contrib.flatpages',
        'django.contrib.sitemaps',
        'django.contrib.humanize',
        'django.contrib.gis',

        # overwrite management command in
        # django_elasticsearch_dsl
        'froide.helper',

        # external
        'django_elasticsearch_dsl',
        'taggit',
        'storages',
        'treebeard',
        'django_filters',
        'leaflet',

        # Semi-external
        'filingcabinet',

        # local
        'froide.foirequest',
        'froide.foirequestfollower',
        'froide.frontpage',
        'froide.georegion',
        'froide.publicbody',
        'froide.document',
        'froide.account',
        'froide.bounce',
        'froide.team',
        'froide.foisite',
        'froide.problem',
        'froide.accesstoken',
        'froide.guide',
        'froide.comments',
        'froide.campaign',

        # API
        'oauth2_provider',
        'rest_framework',
    ])

    CACHES = values.CacheURLValue('dummy://')

    # ############# Site Configuration #########

    # Make this unique, and don't share it with anybody.
    SECRET_KEY = 'make_me_unique!!'

    SITE_NAME = values.Value('Froide')
    SITE_EMAIL = values.Value('*****@*****.**')
    SITE_URL = values.Value('http://*****:*****@example.com'),
    )

    MANAGERS = ADMINS

    INTERNAL_IPS = values.TupleValue(('127.0.0.1', ))

    # ############## PATHS ###############

    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

    LOCALE_PATHS = values.TupleValue(
        (os.path.abspath(os.path.join(PROJECT_ROOT, '..', "locale")), ))

    GEOIP_PATH = None

    # Absolute filesystem path to the directory that will hold user-uploaded files.
    # Example: "/home/media/media.lawrence.com/media/"
    MEDIA_ROOT = values.Value(
        os.path.abspath(os.path.join(PROJECT_ROOT, "..", "files")))

    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
    MEDIA_URL = values.Value('/files/')

    # Sub path in MEDIA_ROOT that will hold FOI attachments
    FOI_MEDIA_PATH = values.Value('foi')
    FOI_MEDIA_URL = values.Value('/files/')
    FOI_MEDIA_DOMAIN = values.Value('')
    FOI_MEDIA_TOKENS = False
    FOI_MEDIA_TOKEN_EXPIRY = 2 * 60

    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/home/media/media.lawrence.com/static/"
    STATIC_ROOT = values.Value(
        os.path.abspath(os.path.join(PROJECT_ROOT, "..", "public")))

    # Additional locations of static files
    STATICFILES_DIRS = (os.path.join(PROJECT_ROOT, "static"), )
    # ########## URLs #################

    ROOT_URLCONF = values.Value('froide.urls')

    # URL prefix for static files.
    # Example: "http://media.lawrence.com/static/"

    # URL that handles the static files like app media.
    # Example: "http://media.lawrence.com"
    STATIC_URL = values.Value('/static/')

    USE_X_ACCEL_REDIRECT = values.BooleanValue(False)
    X_ACCEL_REDIRECT_PREFIX = values.Value('/protected')

    # ## URLs that can be translated to a secret value

    SECRET_URLS = values.DictValue({"admin": "admin"})

    # ######## Backends, Finders, Processors, Classes ####

    AUTH_USER_MODEL = values.Value('account.User')
    PASSWORD_HASHERS = [
        'django.contrib.auth.hashers.PBKDF2PasswordHasher',
        'froide.account.hashers.PBKDF2WrappedSHA1PasswordHasher',
    ]

    # List of finder classes that know how to find static files in
    # various locations.
    STATICFILES_FINDERS = (
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
        'django.contrib.staticfiles.finders.FileSystemFinder',
    )

    TEMPLATES = [{
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(PROJECT_ROOT, "templates"),
        ],
        'OPTIONS': {
            'debug':
            values.BooleanValue(DEBUG),
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ],
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.i18n',
                'django.template.context_processors.media',
                'django.template.context_processors.static',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'froide.helper.context_processors.froide',
                'froide.helper.context_processors.site_settings',
                'froide.helper.context_processors.block_helper'
            ]
        }
    }]

    MIDDLEWARE = [
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.locale.LocaleMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'oauth2_provider.middleware.OAuth2TokenMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    COMMENTS_APP = 'froide.comments'

    # ######### I18N and L10N ##################

    # Local time zone for this installation. Choices can be found here:
    # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
    # although not all choices may be available on all operating systems.
    # On Unix systems, a value of None will cause Django to use the same
    # timezone as the operating system.
    # If running in a Windows environment this must be set to the same as your
    # system time zone.
    TIME_ZONE = values.Value('Europe/Berlin')
    USE_TZ = values.BooleanValue(True)

    # Language code for this installation. All choices can be found here:
    # http://www.i18nguy.com/unicode/language-identifiers.html
    LANGUAGE_CODE = values.Value('en')
    LANGUAGES = (
        ('en', _('English')),
        ('es', _('Spanish')),
        ('fi-fi', _('Finnish (Finland)')),
        ('de', _('German')),
        ('da-dk', _('Danish (Denmark)')),
        ('it', _('Italian')),
        ('pt', _('Portuguese')),
        ('sv-se', _('Swedish (Sweden)')),
        ('sv-fi', _('Swedish (Finland)')),
        ('zh-cn', _('Chinese (Simplified)')),
        ('zh-hk', _('Chinese (Traditional, Hong Kong)')),
    )

    # If you set this to False, Django will make some optimizations so as not
    # to load the internationalization machinery.
    USE_I18N = values.BooleanValue(True)

    # If you set this to False, Django will not format dates, numbers and
    # calendars according to the current locale
    USE_L10N = values.BooleanValue(True)

    DATE_FORMAT = values.Value("d. F Y")
    SHORT_DATE_FORMAT = values.Value("d.m.Y")
    DATE_INPUT_FORMATS = values.TupleValue(("%d.%m.%Y", ))
    SHORT_DATETIME_FORMAT = values.Value("d.m.Y H:i")
    DATETIME_INPUT_FORMATS = values.TupleValue(("%d.%m.%Y %H:%M", ))
    TIME_FORMAT = values.Value("H:i")
    TIME_INPUT_FORMATS = values.TupleValue(("%H:%M", ))

    HOLIDAYS = [
        (1, 1),  # New Year's Day
        (12, 25),  # Christmas
        (12, 26)  # Second day of Christmas
    ]

    # Weekends are non-working days
    HOLIDAYS_WEEKENDS = True

    # Calculates other holidays based on easter sunday
    HOLIDAYS_FOR_EASTER = (0, -2, 1, 39, 50, 60)

    # ######## Logging ##########

    # A sample logging configuration.
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': True,
        'root': {
            'level': 'WARNING',
            'handlers': [],
        },
        'filters': {
            'require_debug_false': {
                '()': 'django.utils.log.RequireDebugFalse'
            }
        },
        'formatters': {
            'verbose': {
                'format':
                '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
            },
        },
        'handlers': {
            'mail_admins': {
                'level': 'ERROR',
                'filters': ['require_debug_false'],
                'class': 'django.utils.log.AdminEmailHandler'
            },
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            }
        },
        'loggers': {
            'froide': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'DEBUG',
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': True,
            },
            'django.db.backends': {
                'level': 'ERROR',
                'handlers': ['console'],
                'propagate': False,
            }
        }
    }

    # ######## Security ###########

    CSRF_COOKIE_SECURE = False
    CSRF_FAILURE_VIEW = values.Value('froide.account.views.csrf_failure')

    # Change this
    # ALLOWED_HOSTS = ()
    ALLOWED_REDIRECT_HOSTS = ()

    SESSION_COOKIE_AGE = values.IntegerValue(3628800)  # six weeks
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False

    # ######## FilingCabinet Document ####

    # FILINGCABINET_DOCUMENT_MODEL = 'document.Document'
    # FILINGCABINET_DOCUMENTCOLLECTION_MODEL = 'document.DocumentCollection'

    FILINGCABINET_DOCUMENT_MODEL = 'document.Document'
    FILINGCABINET_DOCUMENTCOLLECTION_MODEL = 'document.DocumentCollection'

    # ######## Celery #############

    CELERY_BEAT_SCHEDULE = {
        'fetch-mail': {
            'task': 'froide.foirequest.tasks.fetch_mail',
            'schedule': crontab(),
        },
        'detect-asleep': {
            'task': 'froide.foirequest.tasks.detect_asleep',
            'schedule': crontab(hour=0, minute=0),
        },
        'detect-overdue': {
            'task': 'froide.foirequest.tasks.detect_overdue',
            'schedule': crontab(hour=0, minute=0),
        },
        'update-foirequestfollowers': {
            'task': 'froide.foirequestfollower.tasks.batch_update',
            'schedule': crontab(hour=0, minute=0),
        },
        'classification-reminder': {
            'task': 'froide.foirequest.tasks.classification_reminder',
            'schedule': crontab(hour=7, minute=0, day_of_week=6),
        },
        'bounce-checker': {
            'task': 'froide.bounce.tasks.check_bounces',
            'schedule': crontab(hour=3, minute=0),
        },
        'account-maintenance': {
            'task': 'froide.account.tasks.account_maintenance_task',
            'schedule': crontab(hour=4, minute=0)
        }
    }

    CELERY_TASK_ALWAYS_EAGER = values.BooleanValue(True)

    CELERY_TASK_ROUTES = {
        'froide.foirequest.tasks.fetch_mail': {
            "queue": "emailfetch"
        },
        'froide.foirequest.tasks.process_mail': {
            "queue": "email"
        },
        'djcelery_email_send_multiple': {
            "queue": "emailsend"
        },
        'froide.helper.tasks.*': {
            "queue": "searchindex"
        },
    }
    CELERY_TIMEZONE = 'UTC'
    # We need to serialize email data as binary
    # which doesn't work well in JSON
    CELERY_TASK_SERIALIZER = 'pickle'
    CELERY_RESULT_SERIALIZER = 'pickle'
    CELERY_ACCEPT_CONTENT = ['pickle']

    CELERY_EMAIL_TASK_CONFIG = {'queue': 'emailsend'}

    # ######## Search ###########

    ELASTICSEARCH_INDEX_PREFIX = 'froide'
    ELASTICSEARCH_DSL = {
        'default': {
            'hosts': 'localhost:9200'
        },
    }
    ELASTICSEARCH_DSL_SIGNAL_PROCESSOR = 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor'

    # ######### API #########

    # Do not include xml by default, so lxml doesn't need to be present
    TASTYPIE_DEFAULT_FORMATS = ['json']

    OAUTH2_PROVIDER = {
        'SCOPES': {
            'read:user': _('Access to user status'),
            'read:profile': _('Read user profile information'),
            'read:email': _('Read user email'),
            'read:request': _('Read your (private) requests'),
            'make:request': _('Make requests on your behalf'),
            'follow:request': _('Follow/Unfollow requests'),
        }
    }
    OAUTH2_PROVIDER_APPLICATION_MODEL = 'account.Application'

    LOGIN_URL = 'account-login'

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
            'rest_framework.authentication.SessionAuthentication',
        ),
        'DEFAULT_PERMISSION_CLASSES':
        ('rest_framework.permissions.IsAuthenticatedOrReadOnly', ),
        'DEFAULT_PAGINATION_CLASS':
        'froide.helper.api_utils.CustomLimitOffsetPagination',
        'PAGE_SIZE':
        50,
        'DEFAULT_FILTER_BACKENDS':
        ('django_filters.rest_framework.DjangoFilterBackend', ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework.renderers.JSONRenderer',
            'froide.helper.api_renderers.CustomPaginatedCSVRenderer',
            # 'rest_framework.renderers.BrowsableAPIRenderer',
        )
    }

    # ######### Froide settings ########

    FROIDE_CONFIG = dict(
        user_can_hide_web=True,
        public_body_officials_public=True,
        public_body_officials_email_public=False,
        request_public_after_due_days=14,
        payment_possible=True,
        currency="Euro",
        default_law=1,
        search_engine_query=
        "http://www.google.de/search?as_q=%(query)s&as_epq=&as_oq=&as_eq=&hl=en&lr=&cr=&as_ft=i&as_filetype=&as_qdr=all&as_occt=any&as_dt=i&as_sitesearch=%(domain)s&as_rights=&safe=images",
        greetings=[rec(r"Dear (?:Mr\.?|Mr?s\.? .*?)")],
        redact_salutation=r"(?:Mr\.?|Mr?s\.?)",
        custom_replacements=[],
        closings=[rec(r"Sincerely yours,?")],
        public_body_boosts={},
        autocomplete_body_boosts={},
        dryrun=False,
        read_receipt=False,
        delivery_receipt=False,
        dsn=False,
        delivery_reporter=None,
        request_throttle=
        None,  # Set to [(15, 7 * 24 * 60 * 60),] for 15 requests in 7 days
        dryrun_domain="testmail.example.com",
        allow_pseudonym=False,
        doc_conversion_binary=None,  # replace with libreoffice instance
        doc_conversion_call_func=None,  # see settings_test for use
        content_urls={
            'terms': '/terms/',
            'privary': '/privacy/',
            'about': '/about/',
            'help': '/help/',
        },
        message_handlers={
            'email': 'froide.foirequest.message_handlers.EmailMessageHandler'
        },
        max_attachment_size=1024 * 1024 * 10,  # 10 MB
        bounce_enabled=False,
        bounce_max_age=60 * 60 * 24 * 14,  # 14 days
        bounce_format='bounce+{token}@example.com',
        auto_reply_subject_regex=rec('^(Auto-?Reply|Out of office)'),
        auto_reply_email_regex=rec('^auto(reply|responder)@'))

    TESSERACT_DATA_PATH = values.Value('/usr/local/share/tessdata')

    # ###### Email ##############

    # Django settings

    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    EMAIL_SUBJECT_PREFIX = values.Value('[Froide] ')
    SERVER_EMAIL = values.Value('*****@*****.**')
    DEFAULT_FROM_EMAIL = values.Value('*****@*****.**')

    # Official Notification Mail goes through
    # the normal Django SMTP Backend
    EMAIL_HOST = values.Value("")
    EMAIL_PORT = values.IntegerValue(587)
    EMAIL_HOST_USER = values.Value("")
    EMAIL_HOST_PASSWORD = values.Value("")
    EMAIL_USE_TLS = values.BooleanValue(True)

    # Froide special case settings
    # IMAP settings for fetching mail
    FOI_EMAIL_PORT_IMAP = values.IntegerValue(993)
    FOI_EMAIL_HOST_IMAP = values.Value("imap.example.com")
    FOI_EMAIL_ACCOUNT_NAME = values.Value("*****@*****.**")
    FOI_EMAIL_ACCOUNT_PASSWORD = values.Value("")
    FOI_EMAIL_USE_SSL = values.BooleanValue(True)

    # SMTP settings for sending FoI mail
    FOI_EMAIL_HOST_USER = values.Value(FOI_EMAIL_ACCOUNT_NAME)
    FOI_EMAIL_HOST_FROM = values.Value(FOI_EMAIL_HOST_USER)
    FOI_EMAIL_HOST_PASSWORD = values.Value(FOI_EMAIL_ACCOUNT_PASSWORD)
    FOI_EMAIL_HOST = values.Value("smtp.example.com")
    FOI_EMAIL_PORT = values.IntegerValue(587)
    FOI_EMAIL_USE_TLS = values.BooleanValue(True)

    # The FoI Mail can use a different account
    FOI_EMAIL_DOMAIN = values.Value("example.com")

    FOI_EMAIL_TEMPLATE = None
    # Example:
    # FOI_EMAIL_TEMPLATE = lambda user_name, secret: "{username}.{secret}@{domain}" % (user_name, secret, FOI_EMAIL_DOMAIN)

    # Is the message you can send from fixed
    # or can you send from any address you like?
    FOI_EMAIL_FIXED_FROM_ADDRESS = values.BooleanValue(True)

    BOUNCE_EMAIL_HOST_IMAP = values.Value('')
    BOUNCE_EMAIL_PORT_IMAP = values.Value(993)
    BOUNCE_EMAIL_ACCOUNT_NAME = values.Value('')
    BOUNCE_EMAIL_ACCOUNT_PASSWORD = values.Value('')
    BOUNCE_EMAIL_USE_SSL = values.Value(False)
Ejemplo n.º 24
0
class Base(StyleguideMixin, DRFMixin, RichieCoursesConfigurationMixin,
           Configuration):
    """
    This is the base configuration every configuration (aka environnement) should inherit from. It
    is recommended to configure third-party applications by creating a configuration mixins in
    ./configurations and compose the Base configuration with those mixins.

    It depends on an environment variable that SHOULD be defined:

    * DJANGO_SECRET_KEY

    You may also want to override default configuration by setting the following environment
    variables:

    * DJANGO_SENTRY_DSN
    * RICHIE_ES_HOST
    * DB_NAME
    * DB_HOST
    * DB_PASSWORD
    * DB_USER
    """

    DEBUG = False

    SITE_ID = 1

    # Security
    ALLOWED_HOSTS = []
    SECRET_KEY = values.Value(None)
    # System check reference:
    # https://docs.djangoproject.com/en/2.2/ref/checks/#security
    SILENCED_SYSTEM_CHECKS = values.ListValue([
        # Allow the X_FRAME_OPTIONS to be set to "SAMEORIGIN"
        "security.W019"
    ])
    # The X_FRAME_OPTIONS value should be set to "SAMEORIGIN" to display
    # DjangoCMS frontend admin frames. Dockerflow raises a system check security
    # warning with this setting, one should add "security.W019" to the
    # SILENCED_SYSTEM_CHECKS setting (see above).
    X_FRAME_OPTIONS = "SAMEORIGIN"

    # Application definition
    ROOT_URLCONF = "urls"
    WSGI_APPLICATION = "wsgi.application"

    # Database
    DATABASES = {
        "default": {
            "ENGINE":
            values.Value(
                "django.db.backends.postgresql_psycopg2",
                environ_name="DB_ENGINE",
                environ_prefix=None,
            ),
            "NAME":
            values.Value("richie", environ_name="DB_NAME",
                         environ_prefix=None),
            "USER":
            values.Value("fun", environ_name="DB_USER", environ_prefix=None),
            "PASSWORD":
            values.Value("pass",
                         environ_name="DB_PASSWORD",
                         environ_prefix=None),
            "HOST":
            values.Value("localhost",
                         environ_name="DB_HOST",
                         environ_prefix=None),
            "PORT":
            values.Value(5432, environ_name="DB_PORT", environ_prefix=None),
        }
    }
    MIGRATION_MODULES = {}

    # Static files (CSS, JavaScript, Images)
    STATIC_URL = "/static/"
    MEDIA_URL = "/media/"
    MEDIA_ROOT = os.path.join(DATA_DIR, "media")
    STATIC_ROOT = os.path.join(DATA_DIR, "static")

    # Login/registration related settings
    LOGIN_REDIRECT_URL = "/"
    LOGOUT_REDIRECT_URL = "/"
    LOGIN_URL = "login"
    LOGOUT_URL = "logout"

    AUTHENTICATION_BACKENDS = (
        "richie.apps.social.backends.EdXOAuth2",
        "richie.apps.social.backends.EdXOIDC",
        "django.contrib.auth.backends.ModelBackend",
    )

    # Social auth
    SOCIAL_AUTH_EDX_OAUTH2_KEY = values.Value()
    SOCIAL_AUTH_EDX_OAUTH2_SECRET = values.Value()
    SOCIAL_AUTH_EDX_OAUTH2_ENDPOINT = values.Value()
    SOCIAL_AUTH_EDX_OIDC_KEY = values.Value()
    SOCIAL_AUTH_EDX_OIDC_SECRET = values.Value()
    SOCIAL_AUTH_EDX_OIDC_ID_TOKEN_DECRYPTION_KEY = values.Value()
    SOCIAL_AUTH_EDX_OIDC_ENDPOINT = values.Value()
    SOCIAL_AUTH_POSTGRES_JSONFIELD = False  # Mysql compatibility by default

    SOCIAL_AUTH_PIPELINE = (
        # Get the information we can about the user and return it in a simple
        # format to create the user instance later. In some cases the details are
        # already part of the auth response from the provider, but sometimes this
        # could hit a provider API.
        "social_core.pipeline.social_auth.social_details",
        # Get the social uid from whichever service we're authing thru. The uid is
        # the unique identifier of the given user in the provider.
        "social_core.pipeline.social_auth.social_uid",
        # Verifies that the current auth process is valid within the current
        # project, this is where emails and domains whitelists are applied (if
        # defined).
        "social_core.pipeline.social_auth.auth_allowed",
        # Checks if the current social-account is already associated in the site.
        "social_core.pipeline.social_auth.social_user",
        # Make up a username for this person.
        "richie.apps.social.pipeline.user.get_username",
        # Create a user account if we haven't found one yet.
        "social_core.pipeline.user.create_user",
        # Create the record that associates the social account with the user.
        "social_core.pipeline.social_auth.associate_user",
        # Populate the extra_data field in the social record with the values
        # specified by settings (and the default ones like access_token, etc).
        "social_core.pipeline.social_auth.load_extra_data",
        # Update the user record with any changed info from the auth service.
        "social_core.pipeline.user.user_details",
    )

    # Mapping between edx and richie profile fields
    EDX_USER_PROFILE_TO_DJANGO = values.DictValue()

    SOCIAL_ERROR_REVERSE_ID = values.Value()

    # AUTHENTICATION
    RICHIE_AUTHENTICATION_DELEGATION = {
        "BASE_URL":
        values.Value("",
                     environ_name="AUTHENTICATION_BASE_URL",
                     environ_prefix=None),
        "BACKEND":
        values.Value("base",
                     environ_name="AUTHENTICATION_BACKEND",
                     environ_prefix=None),
        # PROFILE_URLS are custom links to access to Auth profile views
        # from Richie. Link order will reflect the order of display in frontend.
        # (i) Info - {base_url} is RICHIE_AUTHENTICATION_DELEGATION.BASE_URL
        # (i) If you need to bind user data into href url, wrap the property between ()
        # e.g: for user.username = johndoe, /u/(username) will be /u/johndoe
        "PROFILE_URLS":
        values.ListValue(
            [
                {
                    "label": _("Profile"),
                    "href": _("{base_url:s}/u/(username)")
                },
                {
                    "label": _("Account"),
                    "href": _("{base_url:s}/account/settings")
                },
            ],
            environ_name="AUTHENTICATION_PROFILE_URLS",
            environ_prefix=None,
        ),
    }

    # LMS
    RICHIE_LMS_BACKENDS = [{
        # We configure default values that work with the test configuration of
        # github.com/openfun/openedx-docker.
        "BASE_URL":
        values.Value(environ_name="EDX_BASE_URL", environ_prefix=None),
        # Django backend
        "BACKEND":
        values.Value(
            "richie.apps.courses.lms.edx.EdXLMSBackend",
            environ_name="EDX_BACKEND",
            environ_prefix=None,
        ),
        "COURSE_REGEX":
        values.Value(
            r"^.*/courses/(?P<course_id>.*)/course/?$",
            environ_name="EDX_COURSE_REGEX",
            environ_prefix=None,
        ),
        "DEFAULT_COURSE_RUN_SYNC_MODE":
        "sync_to_public",
        # React frontend
        "JS_BACKEND":
        values.Value("base",
                     environ_name="EDX_JS_BACKEND",
                     environ_prefix=None),
        "JS_COURSE_REGEX":
        values.Value(
            r"^.*/courses/(?<course_id>.*)/course/?$",
            environ_name="EDX_JS_COURSE_REGEX",
            environ_prefix=None,
        ),
    }]
    RICHIE_COURSE_RUN_SYNC_SECRETS = values.ListValue([])

    # Elasticsearch
    RICHIE_ES_HOST = values.Value("elasticsearch",
                                  environ_name="RICHIE_ES_HOST",
                                  environ_prefix=None)
    RICHIE_ES_INDICES_PREFIX = values.Value(
        default="richie",
        environ_name="RICHIE_ES_INDICES_PREFIX",
        environ_prefix=None)

    # Internationalization
    TIME_ZONE = "Europe/Paris"
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True

    # Templates
    TEMPLATES = [{
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(BASE_DIR, "templates")],
        "OPTIONS": {
            "context_processors": [
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "django.template.context_processors.i18n",
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.template.context_processors.media",
                "django.template.context_processors.csrf",
                "django.template.context_processors.tz",
                "sekizai.context_processors.sekizai",
                "django.template.context_processors.static",
                "cms.context_processors.cms_settings",
                "richie.apps.core.context_processors.site_metas",
                "social_django.context_processors.backends",
                "social_django.context_processors.login_redirect",
            ],
            "loaders": [
                "django.template.loaders.filesystem.Loader",
                "django.template.loaders.app_directories.Loader",
            ],
        },
    }]

    MIDDLEWARE = (
        "richie.apps.core.cache.LimitBrowserCacheTTLHeaders",
        "cms.middleware.utils.ApphookReloadMiddleware",
        "django.middleware.security.SecurityMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.middleware.common.CommonMiddleware",
        "django.middleware.clickjacking.XFrameOptionsMiddleware",
        "dockerflow.django.middleware.DockerflowMiddleware",
        "cms.middleware.user.CurrentUserMiddleware",
        "cms.middleware.page.CurrentPageMiddleware",
        "cms.middleware.toolbar.ToolbarMiddleware",
        "cms.middleware.language.LanguageCookieMiddleware",
        "dj_pagination.middleware.PaginationMiddleware",
        "richie.apps.social.middleware.SocialAuthExceptionMiddleware",
    )

    # Django applications from the highest priority to the lowest
    INSTALLED_APPS = (
        # Richie stuff
        "richie.apps.demo",
        "richie.apps.search",
        "richie.apps.courses",
        "richie.apps.core",
        "richie.apps.social",
        "richie.plugins.glimpse",
        "richie.plugins.html_sitemap",
        "richie.plugins.large_banner",
        "richie.plugins.nesteditem",
        "richie.plugins.plain_text",
        "richie.plugins.section",
        "richie.plugins.simple_picture",
        "richie.plugins.simple_text_ckeditor",
        "richie",
        # Third party apps
        "dj_pagination",
        "dockerflow.django",
        "parler",
        "rest_framework",
        "social_django",
        # Django-cms
        "djangocms_admin_style",
        "djangocms_googlemap",
        "djangocms_link",
        "djangocms_picture",
        "djangocms_text_ckeditor",
        "djangocms_video",
        "cms",
        "menus",
        "sekizai",
        "treebeard",
        "filer",
        "easy_thumbnails",
        # Django
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.admin",
        "django.contrib.sites",
        "django.contrib.sitemaps",
        "django.contrib.staticfiles",
        "django.contrib.messages",
    )

    # Languages
    # - Django
    LANGUAGE_CODE = "en"

    # Careful! Languages should be ordered by priority, as this tuple is used to get
    # fallback/default languages throughout the app.
    # Use "en" as default as it is the language that is most likely to be spoken by any visitor
    # when their preferred language, whatever it is, is unavailable
    LANGUAGES = (("en", _("English")), ("fr", _("French")))

    # - Django CMS
    CMS_LANGUAGES = {
        "default": {
            "public": True,
            "hide_untranslated": False,
            "redirect_on_fallback": True,
            "fallbacks": ["en", "fr"],
        },
        1: [
            {
                "public": True,
                "code": "en",
                "hide_untranslated": False,
                "name": _("English"),
                "fallbacks": ["fr"],
                "redirect_on_fallback": True,
            },
            {
                "public": True,
                "code": "fr",
                "hide_untranslated": False,
                "name": _("French"),
                "fallbacks": ["en"],
                "redirect_on_fallback": True,
            },
        ],
    }

    # - Django Parler
    PARLER_LANGUAGES = CMS_LANGUAGES

    # Permisions
    # - Django CMS
    CMS_PERMISSION = True

    # - Django Filer
    FILER_ENABLE_PERMISSIONS = True
    FILER_IS_PUBLIC_DEFAULT = True

    # - Django Pagination
    PAGINATION_INVALID_PAGE_RAISES_404 = True
    PAGINATION_DEFAULT_WINDOW = 2
    PAGINATION_DEFAULT_MARGIN = 1

    # Logging
    LOGGING = {
        "version": 1,
        "disable_existing_loggers": True,
        "formatters": {
            "verbose": {
                "format":
                "%(levelname)s %(asctime)s %(module)s "
                "%(process)d %(thread)d %(message)s"
            }
        },
        "handlers": {
            "console": {
                "level": "DEBUG",
                "class": "logging.StreamHandler",
                "formatter": "verbose",
            }
        },
        "loggers": {
            "django.db.backends": {
                "level": "ERROR",
                "handlers": ["console"],
                "propagate": False,
            }
        },
    }

    # Cache
    CACHES = {
        "default": {
            "BACKEND":
            values.Value(
                "django.core.cache.backends.locmem.LocMemCache",
                environ_name="CACHE_DEFAULT_BACKEND",
                environ_prefix=None,
            ),
            "LOCATION":
            values.Value("",
                         environ_name="CACHE_DEFAULT_LOCATION",
                         environ_prefix=None),
            "OPTIONS":
            values.DictValue({},
                             environ_name="CACHE_DEFAULT_OPTIONS",
                             environ_prefix=None),
        }
    }

    # For more details about CMS_CACHE_DURATION, see :
    # http://docs.django-cms.org/en/latest/reference/configuration.html#cms-cache-durations
    CMS_CACHE_DURATIONS = values.DictValue({
        "menus": 3600,
        "content": 60,
        "permissions": 3600
    })

    # Sessions
    SESSION_ENGINE = values.Value("django.contrib.sessions.backends.db")

    # Sentry
    SENTRY_DSN = values.Value(None, environ_name="SENTRY_DSN")

    # pylint: disable=invalid-name
    @property
    def ENVIRONMENT(self):
        """Environment in which the application is launched."""
        return self.__class__.__name__.lower()

    # pylint: disable=invalid-name
    @property
    def RELEASE(self):
        """
        Return the release information.

        Delegate to the module function to enable easier testing.
        """
        return get_release()

    @classmethod
    def post_setup(cls):
        """Post setup configuration.
        This is the place where you can configure settings that require other
        settings to be loaded.
        """
        super().post_setup()

        # The SENTRY_DSN setting should be available to activate sentry for an environment
        if cls.SENTRY_DSN is not None:
            sentry_sdk.init(
                dsn=cls.SENTRY_DSN,
                environment=cls.__name__.lower(),
                release=get_release(),
                integrations=[DjangoIntegration()],
            )
            with sentry_sdk.configure_scope() as scope:
                scope.set_extra("application", "backend")
class Common(Configuration):
    # this will be the django-projects root directory where the manage.py file exists.
    BASE_DIR = os.path.normpath(
        os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

    # this will be directory under which all the project's assets will be stored
    ASSETS_DIR = os.path.join(BASE_DIR, 'assets')

    CONTENTS_DIR = os.path.join(BASE_DIR, 'contents')

    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = values.SecretValue()

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = values.BooleanValue(False)

    ALLOWED_HOSTS = values.ListValue([])

    # Application definition
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'django_extensions',
        'rest_framework',
        'phonenumber_field',
        'project.apps.membership.apps.MembershipConfig',
        'project.apps.api.apps.ApiConfig',
    ]

    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',
    ]

    ROOT_URLCONF = 'project.urls'

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            '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',
                ],
            },
        },
    ]

    WSGI_APPLICATION = 'project.wsgi.application'

    # Database
    # https://docs.djangoproject.com/en/2.1/ref/settings/#databases
    DATABASES = values.DatabaseURLValue('sqlite:///{}'.format(
        os.path.join(BASE_DIR, 'db.sqlite3')))

    # Password validation
    # https://docs.djangoproject.com/en/2.1/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',
        },
    ]

    AUTHENTICATION_BACKENDS = [
        'django.contrib.auth.backends.ModelBackend',
        'project.apps.membership.backends.MobileBackend'
    ]

    APPEND_SLASH = False

    # Internationalization
    # https://docs.djangoproject.com/en/2.1/topics/i18n/
    LANGUAGE_CODE = 'en-us'

    TIME_ZONE = 'UTC'

    USE_I18N = True

    USE_L10N = True

    USE_TZ = True

    MEDIA_URL = values.Value('/media/')

    STATIC_URL = values.Value('/statics/')

    MEDIA_ROOT = os.path.join(CONTENTS_DIR, 'media')

    STATIC_ROOT = os.path.join(CONTENTS_DIR, 'statics')

    STATICFILES_DIRS = (os.path.join(ASSETS_DIR, 'static'), )

    LOCALE_PATHS = (os.path.join(ASSETS_DIR, 'locale'), )

    FIXTURE_DIRS = (os.path.join(ASSETS_DIR, 'fixtures'), )

    AUTH_USER_MODEL = 'membership.User'

    LOGGING_LEVEL = values.Value('DEBUG', environ_prefix='ACHARE')

    LOGGING = values.DictValue({
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'verbose': {
                'format':
                '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
                'style': '{',
            },
            'simple': {
                'format': '{levelname} {message}',
                'style': '{',
            },
        },
        'filters': {
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            }
        },
        'handlers': {
            'console': {
                'level': 'INFO',
                'filters': ['require_debug_true'],
                'class': 'logging.StreamHandler',
                'formatter': 'verbose'
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler',
            }
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'INFO'
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': True,
            },
            'achare': {
                'handlers': ['console'],
                'level': 'DEBUG',
                'propagate': True,
            }
        }
    })

    REST_FRAMEWORK = {
        'DEFAULT_VERSION':
        'v1',
        'DEFAULT_VERSIONING_CLASS':
        'rest_framework.versioning.URLPathVersioning',
        'EXCEPTION_HANDLER':
        'project.apps.api.views.api_exception_handler',
        # 'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated', ],
        'DEFAULT_PERMISSION_CLASSES': [
            'project.apps.api.permissions.IsRegistered',
        ],
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_simplejwt.authentication.JWTAuthentication',
        ]
    }

    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
        'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
        'ROTATE_REFRESH_TOKENS': False,
        'BLACKLIST_AFTER_ROTATION': True,

        # 'ALGORITHM': 'HS256',
        # 'SIGNING_KEY': SECRET_KEY,
        # 'VERIFYING_KEY': None,
        'AUTH_HEADER_TYPES': ('Bearer', ),
        'USER_ID_FIELD': 'id',
        'USER_ID_CLAIM': 'user_id',
        'AUTH_TOKEN_CLASSES':
        ('rest_framework_simplejwt.tokens.AccessToken', ),
        'TOKEN_TYPE_CLAIM': 'token_type',

        # 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
        # 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
        # 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
    }

    # membership and registration settings
    REGISTRATION_PIN_EXPIRATION_MINUTES = values.IntegerValue(
        5, environ_prefix='ACHARE')

    VALID_MOBILE_COUNTRY_CODES = values.ListValue(['98'],
                                                  environ_prefix='ACHARE')

    REGISTRATION_SEND_SMS_INTERVAL = values.IntegerValue(
        120, environ_prefix='ACHARE')

    REGISTER_ATTEMPTS_LIMIT = values.IntegerValue(3, environ_prefix='ACHARE')

    VERIFY_ATTEMPTS_LIMIT = values.IntegerValue(10, environ_prefix='ACHARE')

    REGISTRATION_BAN_MINUTES = values.IntegerValue(30, environ_prefix='ACHARE')
Ejemplo n.º 26
0
class Base(StyleguideMixin, DRFMixin, RichieCoursesConfigurationMixin,
           Configuration):
    """
    This is the base configuration every configuration (aka environnement) should inherit from. It
    is recommended to configure third-party applications by creating a configuration mixins in
    ./configurations and compose the Base configuration with those mixins.

    It depends on an environment variable that SHOULD be defined:

    * DJANGO_SECRET_KEY

    You may also want to override default configuration by setting the following environment
    variables:

    * DJANGO_SENTRY_DSN
    * RICHIE_ES_HOST
    * DB_NAME
    * DB_USER
    * DB_PASSWORD
    * DB_HOST
    * DB_PORT
    """

    DEBUG = False

    SITE_ID = 1

    # Security
    ALLOWED_HOSTS = values.ListValue([])
    SECRET_KEY = "ThisIsAnExampleKeyForDevPurposeOnly"  # nosec
    # System check reference:
    # https://docs.djangoproject.com/en/3.1/ref/checks/#security
    SILENCED_SYSTEM_CHECKS = values.ListValue([
        # Allow the X_FRAME_OPTIONS to be set to "SAMEORIGIN"
        "security.W019"
    ])
    # The X_FRAME_OPTIONS value should be set to "SAMEORIGIN" to display
    # DjangoCMS frontend admin frames. Dockerflow raises a system check security
    # warning with this setting, one should add "security.W019" to the
    # SILENCED_SYSTEM_CHECKS setting (see above).
    X_FRAME_OPTIONS = "SAMEORIGIN"

    # Application definition
    ROOT_URLCONF = "demo.urls"
    WSGI_APPLICATION = "demo.wsgi.application"

    # Database
    DATABASES = {
        "default": {
            "ENGINE":
            values.Value(
                "django.db.backends.postgresql_psycopg2",
                environ_name="DB_ENGINE",
                environ_prefix=None,
            ),
            "NAME":
            values.Value("richie", environ_name="DB_NAME",
                         environ_prefix=None),
            "USER":
            values.Value("richie_user",
                         environ_name="DB_USER",
                         environ_prefix=None),
            "PASSWORD":
            values.Value("pass",
                         environ_name="DB_PASSWORD",
                         environ_prefix=None),
            "HOST":
            values.Value("localhost",
                         environ_name="DB_HOST",
                         environ_prefix=None),
            "PORT":
            values.Value(5432, environ_name="DB_PORT", environ_prefix=None),
        }
    }
    MIGRATION_MODULES = {}

    # Static files (CSS, JavaScript, Images)
    STATIC_URL = "/static/"
    MEDIA_URL = "/media/"
    MEDIA_ROOT = os.path.join(DATA_DIR, "media")
    STATIC_ROOT = os.path.join(DATA_DIR, "static")

    # For static files, we want to use a backend that includes a hash in
    # the filename, that is calculated from the file content, so that browsers always
    # get the updated version of each file.
    STATICFILES_STORAGE = values.Value(
        "base.storage.CDNManifestStaticFilesStorage")

    AUTHENTICATION_BACKENDS = ("django.contrib.auth.backends.ModelBackend", )

    # AUTHENTICATION DELEGATION
    AUTHENTICATION_DELEGATION = {
        "BASE_URL":
        values.Value("",
                     environ_name="AUTHENTICATION_BASE_URL",
                     environ_prefix=None),
        "BACKEND":
        values.Value(
            "base",
            environ_name="AUTHENTICATION_BACKEND",
            environ_prefix=None,
        ),
        # PROFILE_URLS are custom links to access to Auth profile views
        # from Richie. Link order will reflect the order of display in frontend.
        # (i) Info - {base_url} is AUTHENTICATION_DELEGATION.BASE_URL
        # (i) If you need to bind user data into href url, wrap the property between ()
        # e.g: for user.username = johndoe, /u/(username) will be /u/johndoe
        "PROFILE_URLS":
        values.ListValue(
            [
                {
                    "label": _("Profile"),
                    "href": "{base_url:s}/u/(username)"
                },
                {
                    "label": _("Account"),
                    "href": "{base_url:s}/account/settings"
                },
            ],
            environ_name="AUTHENTICATION_PROFILE_URLS",
            environ_prefix=None,
        ),
    }

    # LMS
    LMS_BACKENDS = [{
        "BACKEND":
        values.Value(
            "richie.apps.courses.lms.base.BaseLMSBackend",
            environ_name="EDX_BACKEND",
            environ_prefix=None,
        ),
        "JS_BACKEND":
        values.Value(
            "base",
            environ_name="EDX_JS_BACKEND",
            environ_prefix=None,
        ),
        "SELECTOR_REGEX":
        values.Value(r".*",
                     environ_name="EDX_SELECTOR_REGEX",
                     environ_prefix=None),
        "JS_SELECTOR_REGEX":
        values.Value(r".*",
                     environ_name="EDX_JS_SELECTOR_REGEX",
                     environ_prefix=None),
        "JS_COURSE_REGEX":
        values.Value(
            r"^.*/courses/(?<course_id>.*)/info$",
            environ_name="EDX_JS_COURSE_REGEX",
            environ_prefix=None,
        ),
        "BASE_URL":
        values.Value(environ_name="EDX_BASE_URL", environ_prefix=None),
    }]

    # Internationalization
    TIME_ZONE = "Europe/Paris"
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True
    LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]

    # Mapping between edx and richie profile fields
    EDX_USER_PROFILE_TO_DJANGO = {
        "preferred_username": "******",
        "email": "email",
        "name": "full_name",
        "given_name": "first_name",
        "family_name": "last_name",
        "locale": "language",
        "user_id": "user_id",
        "administrator": "is_staff",
    }

    # Templates
    TEMPLATES = [{
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(BASE_DIR, "templates")],
        "OPTIONS": {
            "context_processors": [
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "django.template.context_processors.i18n",
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.template.context_processors.media",
                "django.template.context_processors.csrf",
                "django.template.context_processors.tz",
                "sekizai.context_processors.sekizai",
                "django.template.context_processors.static",
                "cms.context_processors.cms_settings",
                "richie.apps.core.context_processors.site_metas",
            ],
            "loaders": [
                "django.template.loaders.filesystem.Loader",
                "django.template.loaders.app_directories.Loader",
            ],
        },
    }]

    MIDDLEWARE = (
        "richie.apps.core.cache.LimitBrowserCacheTTLHeaders",
        "cms.middleware.utils.ApphookReloadMiddleware",
        "django.middleware.security.SecurityMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.middleware.common.CommonMiddleware",
        "django.middleware.clickjacking.XFrameOptionsMiddleware",
        "dockerflow.django.middleware.DockerflowMiddleware",
        "cms.middleware.user.CurrentUserMiddleware",
        "cms.middleware.page.CurrentPageMiddleware",
        "cms.middleware.toolbar.ToolbarMiddleware",
        "cms.middleware.language.LanguageCookieMiddleware",
        "dj_pagination.middleware.PaginationMiddleware",
    )

    INSTALLED_APPS = (
        # Richie demo stuff
        "base",
        # Richie stuff
        "richie.apps.demo",
        "richie.apps.search",
        "richie.apps.courses",
        "richie.apps.core",
        "richie.plugins.glimpse",
        "richie.plugins.html_sitemap",
        "richie.plugins.large_banner",
        "richie.plugins.nesteditem",
        "richie.plugins.plain_text",
        "richie.plugins.section",
        "richie.plugins.simple_picture",
        "richie.plugins.simple_text_ckeditor",
        "richie",
        # Third party apps
        "dj_pagination",
        "dockerflow.django",
        "parler",
        "rest_framework",
        "storages",
        # Django-cms
        "djangocms_admin_style",
        "djangocms_googlemap",
        "djangocms_link",
        "djangocms_picture",
        "djangocms_text_ckeditor",
        "djangocms_video",
        "cms",
        "menus",
        "sekizai",
        "treebeard",
        "filer",
        "easy_thumbnails",
        # Django
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.admin",
        "django.contrib.sites",
        "django.contrib.sitemaps",
        "django.contrib.staticfiles",
        "django.contrib.messages",
    )

    # Languages
    # - Django
    LANGUAGE_CODE = "en"

    # Careful! Languages should be ordered by priority, as this tuple is used to get
    # fallback/default languages throughout the app.
    # Use "en" as default as it is the language that is most likely to be spoken by any visitor
    # when their preferred language, whatever it is, is unavailable
    LANGUAGES = (("en", _("English")), ("fr", _("French")))

    # - Django CMS
    CMS_LANGUAGES = {
        "default": {
            "public": True,
            "hide_untranslated": False,
            "redirect_on_fallback": True,
            "fallbacks": ["en", "fr"],
        },
        1: [
            {
                "public": True,
                "code": "en",
                "hide_untranslated": False,
                "name": _("English"),
                "fallbacks": ["fr"],
                "redirect_on_fallback": True,
            },
            {
                "public": True,
                "code": "fr",
                "hide_untranslated": False,
                "name": _("French"),
                "fallbacks": ["en"],
                "redirect_on_fallback": True,
            },
        ],
    }

    # - Django Parler
    PARLER_LANGUAGES = CMS_LANGUAGES

    # Permisions
    # - Django CMS
    CMS_PERMISSION = True

    # - Django Filer
    FILER_ENABLE_PERMISSIONS = True
    FILER_IS_PUBLIC_DEFAULT = True

    # - Django Pagination
    PAGINATION_INVALID_PAGE_RAISES_404 = True
    PAGINATION_DEFAULT_WINDOW = 2
    PAGINATION_DEFAULT_MARGIN = 1

    # Logging
    LOGGING = {
        "version": 1,
        "disable_existing_loggers": True,
        "formatters": {
            "verbose": {
                "format":
                "%(levelname)s %(asctime)s %(module)s "
                "%(process)d %(thread)d %(message)s"
            }
        },
        "handlers": {
            "console": {
                "level": "DEBUG",
                "class": "logging.StreamHandler",
                "formatter": "verbose",
            }
        },
        "loggers": {
            "django.db.backends": {
                "level": "ERROR",
                "handlers": ["console"],
                "propagate": False,
            }
        },
    }

    # Demo
    RICHIE_DEMO_SITE_DOMAIN = "localhost:8080"
    RICHIE_DEMO_FIXTURES_DIR = os.path.join(BASE_DIR, "base", "fixtures")

    # Elasticsearch
    RICHIE_ES_HOST = values.Value("elasticsearch",
                                  environ_name="RICHIE_ES_HOST",
                                  environ_prefix=None)
    RICHIE_ES_INDICES_PREFIX = values.Value(
        default="richie",
        environ_name="RICHIE_ES_INDICES_PREFIX",
        environ_prefix=None)

    # Cache
    CACHES = values.DictValue({
        "default": {
            "BACKEND":
            values.Value(
                "django_redis.cache.RedisCache",
                environ_name="CACHE_DEFAULT_BACKEND",
                environ_prefix=None,
            ),
            "LOCATION":
            values.Value(
                "mymaster/redis-sentinel:26379,redis-sentinel:26379/0",
                environ_name="CACHE_DEFAULT_LOCATION",
                environ_prefix=None,
            ),
            "OPTIONS":
            values.DictValue(
                {"CLIENT_CLASS": "richie.apps.core.cache.SentinelClient"},
                environ_name="CACHE_DEFAULT_OPTIONS",
                environ_prefix=None,
            ),
            "TIMEOUT":
            values.IntegerValue(
                300,
                environ_name="CACHE_DEFAULT_TIMEOUT",
                environ_prefix=None,
            ),
        }
    })

    # For more details about CMS_CACHE_DURATION, see :
    # http://docs.django-cms.org/en/latest/reference/configuration.html#cms-cache-durations
    CMS_CACHE_DURATIONS = values.DictValue({
        "menus": 3600,
        "content": 86400,
        "permissions": 86400
    })
    MAX_BROWSER_CACHE_TTL = 600

    # Sessions
    SESSION_ENGINE = values.Value("django.contrib.sessions.backends.cache")

    # Sentry
    SENTRY_DSN = values.Value(None, environ_name="SENTRY_DSN")

    # pylint: disable=invalid-name
    @property
    def ENVIRONMENT(self):
        """Environment in which the application is launched."""
        return self.__class__.__name__.lower()

    # pylint: disable=invalid-name
    @property
    def RELEASE(self):
        """
        Return the release information.

        Delegate to the module function to enable easier testing.
        """
        return get_release()

    # pylint: disable=invalid-name
    @property
    def CMS_CACHE_PREFIX(self):
        """
        Set cache prefix specific to release so existing cache is invalidated for new deployments.
        """
        return f"cms_{get_release():s}_"

    @classmethod
    def post_setup(cls):
        """Post setup configuration.
        This is the place where you can configure settings that require other
        settings to be loaded.
        """
        super().post_setup()

        # The SENTRY_DSN setting should be available to activate sentry for an environment
        if cls.SENTRY_DSN is not None:
            sentry_sdk.init(
                dsn=cls.SENTRY_DSN,
                environment=cls.ENVIRONMENT,
                release=cls.RELEASE,
                integrations=[DjangoIntegration()],
            )
            with sentry_sdk.configure_scope() as scope:
                scope.set_extra("application", "backend")
Ejemplo n.º 27
0
class Base(Configuration):
    """Base configuration every configuration (aka environment) should inherit from.

    It depends on an environment variable that SHOULD be defined:
    - DJANGO_SECRET_KEY

    You may also want to override default configuration by setting the following
    environment variables:
    - DJANGO_DEBUG
    """

    BASE_DIR = os.path.dirname(__file__)
    DATA_DIR = values.Value(os.path.join("/", "data"))

    # Static files (CSS, JavaScript, Images)
    STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"), )
    STATIC_URL = "/static/"
    MEDIA_URL = "/media/"
    # Allow to configure location of static/media files for non-Docker installation
    MEDIA_ROOT = values.Value(os.path.join(str(DATA_DIR), "media"))
    STATIC_ROOT = values.Value(os.path.join(str(DATA_DIR), "static"))

    SECRET_KEY = values.SecretValue()

    DEBUG = values.BooleanValue(False)

    DATABASES = {
        "default": {
            "ENGINE":
            values.Value(
                "django.db.backends.postgresql_psycopg2",
                environ_name="DATABASE_ENGINE",
                environ_prefix=None,
            ),
            "NAME":
            values.Value("marsha",
                         environ_name="POSTGRES_DB",
                         environ_prefix=None),
            "USER":
            values.Value("marsha_user",
                         environ_name="POSTGRES_USER",
                         environ_prefix=None),
            "PASSWORD":
            values.Value("pass",
                         environ_name="POSTGRES_PASSWORD",
                         environ_prefix=None),
            "HOST":
            values.Value("localhost",
                         environ_name="POSTGRES_HOST",
                         environ_prefix=None),
            "PORT":
            values.Value(5432,
                         environ_name="POSTGRES_PORT",
                         environ_prefix=None),
        }
    }

    ALLOWED_HOSTS = []

    SITE_ID = 1

    SECURE_BROWSER_XSS_FILTER = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    X_FRAME_OPTIONS = "DENY"
    SILENCED_SYSTEM_CHECKS = values.ListValue([])

    # Application definition

    INSTALLED_APPS = [
        "django.contrib.admin.apps.SimpleAdminConfig",
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.messages",
        "django.contrib.sites",
        "django.contrib.staticfiles",
        "django_extensions",
        "dockerflow.django",
        "rest_framework",
        "marsha.core.apps.CoreConfig",
    ]

    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",
        "dockerflow.django.middleware.DockerflowMiddleware",
    ]

    ROOT_URLCONF = "marsha.urls"

    TEMPLATES = [{
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "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",
            ]
        },
    }]

    AUTH_USER_MODEL = "core.User"

    WSGI_APPLICATION = "marsha.wsgi.application"

    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":
        ("rest_framework_simplejwt.authentication.JWTTokenUserAuthentication",
         )
    }

    # Password validation
    # https://docs.djangoproject.com/en/2.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"
        },
    ]

    JWT_SIGNING_KEY = values.Value(SECRET_KEY)

    # Internationalization
    # https://docs.djangoproject.com/en/2.0/topics/i18n/

    # Django sets `LANGUAGES` by default with all supported languages. Let's save it to a
    # different setting before overriding it with the languages active in Marsha. We can use it
    # for example for the choice of time text tracks languages which should not be limited to
    # the few languages active in Marsha.
    # pylint: disable=no-member
    ALL_LANGUAGES = Configuration.LANGUAGES

    LANGUAGE_CODE = "en-us"

    # Careful! Languages should be ordered by priority, as this tuple is used to get
    # fallback/default languages throughout the app.
    # Use "en" as default as it is the language that is most likely to be spoken by any visitor
    # when their preferred language, whatever it is, is unavailable
    LANGUAGES = [("en", _("english")), ("fr", _("french"))]
    LANGUAGES_DICT = dict(LANGUAGES)

    # Internationalization
    TIME_ZONE = "UTC"
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True

    REACT_LOCALES = values.ListValue(["en_US", "es_ES", "fr_FR", "fr_CA"])

    VIDEO_RESOLUTIONS = [144, 240, 480, 720, 1080]

    # Logging
    LOGGING = values.DictValue({
        "version": 1,
        "disable_existing_loggers": False,
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
            }
        },
        "loggers": {
            "marsha": {
                "handlers": ["console"],
                "level": "INFO",
                "propagate": True
            }
        },
    })

    # AWS
    AWS_ACCESS_KEY_ID = values.SecretValue()
    AWS_SECRET_ACCESS_KEY = values.SecretValue()
    AWS_S3_REGION_NAME = values.Value("eu-west-1")
    AWS_S3_URL_PROTOCOL = values.Value("https")
    AWS_SOURCE_BUCKET_NAME = values.Value()
    UPDATE_STATE_SHARED_SECRETS = values.ListValue()

    # Cloud Front key pair for signed urls
    CLOUDFRONT_ACCESS_KEY_ID = values.Value(None)
    CLOUDFRONT_PRIVATE_KEY_PATH = values.Value(
        os.path.join(BASE_DIR, "..", ".ssh", "cloudfront_private_key"))
    CLOUDFRONT_SIGNED_URLS_ACTIVE = values.BooleanValue(True)
    CLOUDFRONT_SIGNED_URLS_VALIDITY = 2 * 60 * 60  # 2 hours

    CLOUDFRONT_DOMAIN = values.Value(None)

    BYPASS_LTI_VERIFICATION = values.BooleanValue(False)

    # Cache
    APP_DATA_CACHE_DURATION = values.Value(60)  # 60 secondes

    # pylint: disable=invalid-name
    @property
    def SIMPLE_JWT(self):
        """Define settings for `djangorestframework_simplejwt`.

        The JWT_SIGNING_KEY must be evaluated late as the jwt library check for string type.
        """
        return {
            "ACCESS_TOKEN_LIFETIME":
            timedelta(days=1),
            "ALGORITHM":
            "HS256",
            "SIGNING_KEY":
            str(self.JWT_SIGNING_KEY),
            "USER_ID_CLAIM":
            "resource_id",
            "AUTH_TOKEN_CLASSES":
            ("rest_framework_simplejwt.tokens.AccessToken", ),
        }

    @classmethod
    def post_setup(cls):
        """Post setup configuration.

        This is the place where you can configure settings that require other
        settings to be loaded.
        """
        super().post_setup()

        # Try to get the current release from the version.json file generated by
        # the CI during the Docker image build
        try:
            with open(os.path.join(cls.BASE_DIR, "version.json")) as version:
                release = json.load(version)["version"]
        except FileNotFoundError:
            release = "NA"

        # The DJANGO_SENTRY_DSN environment variable should be set to activate
        # sentry for an environment
        sentry_dsn = values.Value(None, environ_name="SENTRY_DSN")
        if sentry_dsn is not None:
            sentry_sdk.init(
                dsn=sentry_dsn,
                environment=cls.__name__.lower(),
                release=release,
                integrations=[DjangoIntegration()],
            )
Ejemplo n.º 28
0
class Base(StyleguideMixin, DRFMixin, RichieCoursesConfigurationMixin,
           Configuration):
    """
    This is the base configuration every configuration (aka environnement) should inherit from. It
    is recommended to configure third-party applications by creating a configuration mixins in
    ./configurations and compose the Base configuration with those mixins.

    It depends on an environment variable that SHOULD be defined:

    * DJANGO_SECRET_KEY

    You may also want to override default configuration by setting the following environment
    variables:

    * DJANGO_SENTRY_DSN
    * RICHIE_ES_HOST
    * DB_NAME
    * DB_USER
    * DB_PASSWORD
    * DB_HOST
    * DB_PORT
    """

    DEBUG = False

    SITE_ID = 1

    # Security
    ALLOWED_HOSTS = values.ListValue([])
    SECRET_KEY = "ThisIsAnExampleKeyForDevPurposeOnly"  # nosec
    # System check reference:
    # https://docs.djangoproject.com/en/3.1/ref/checks/#security
    SILENCED_SYSTEM_CHECKS = values.ListValue([
        # Allow the X_FRAME_OPTIONS to be set to "SAMEORIGIN"
        "security.W019"
    ])
    # The X_FRAME_OPTIONS value should be set to "SAMEORIGIN" to display
    # DjangoCMS frontend admin frames. Dockerflow raises a system check security
    # warning with this setting, one should add "security.W019" to the
    # SILENCED_SYSTEM_CHECKS setting (see above).
    X_FRAME_OPTIONS = "SAMEORIGIN"

    # Application definition
    ROOT_URLCONF = "cnfpt.urls"
    WSGI_APPLICATION = "cnfpt.wsgi.application"

    # Database
    DATABASES = {
        "default": {
            "ENGINE":
            values.Value(
                "django.db.backends.postgresql_psycopg2",
                environ_name="DB_ENGINE",
                environ_prefix=None,
            ),
            "NAME":
            values.Value("cnfpt", environ_name="DB_NAME", environ_prefix=None),
            "USER":
            values.Value("fun", environ_name="DB_USER", environ_prefix=None),
            "PASSWORD":
            values.Value("pass",
                         environ_name="DB_PASSWORD",
                         environ_prefix=None),
            "HOST":
            values.Value("localhost",
                         environ_name="DB_HOST",
                         environ_prefix=None),
            "PORT":
            values.Value(5432, environ_name="DB_PORT", environ_prefix=None),
        }
    }
    MIGRATION_MODULES = {}

    # Static files (CSS, JavaScript, Images)
    STATIC_URL = "/static/"
    MEDIA_URL = "/media/"
    MEDIA_ROOT = os.path.join(DATA_DIR, "media")
    STATIC_ROOT = os.path.join(DATA_DIR, "static")

    # For static files, we want to use a backend that includes a hash in
    # the filename, that is calculated from the file content, so that browsers always
    # get the updated version of each file.
    STATICFILES_STORAGE = values.Value(
        "base.storage.CDNManifestStaticFilesStorage")

    AUTHENTICATION_BACKENDS = ("django.contrib.auth.backends.ModelBackend", )

    # AUTHENTICATION DELEGATION
    RICHIE_AUTHENTICATION_DELEGATION = {
        "BASE_URL":
        values.Value("",
                     environ_name="AUTHENTICATION_BASE_URL",
                     environ_prefix=None),
        "BACKEND":
        values.Value(
            "openedx-hawthorn",
            environ_name="AUTHENTICATION_BACKEND",
            environ_prefix=None,
        ),
        # PROFILE_URLS are custom links to access to Auth profile views
        # from Richie. Link order will reflect the order of display in frontend.
        # (i) Info - {base_url} is AUTHENTICATION_DELEGATION.BASE_URL
        # (i) If you need to bind user data into href url, wrap the property between ()
        # e.g: for user.username = johndoe, /u/(username) will be /u/johndoe
        "PROFILE_URLS":
        values.DictValue(
            {
                "dashboard": {
                    "label": _("Dashboard"),
                    "href": _("{base_url:s}/dashboard"),
                },
                "profile": {
                    "label": _("Profile"),
                    "href": _("{base_url:s}/u/(username)"),
                },
                "account": {
                    "label": _("Account"),
                    "href": _("{base_url:s}/account/settings"),
                },
            },
            environ_name="AUTHENTICATION_PROFILE_URLS",
            environ_prefix=None,
        ),
    }

    # LMS
    RICHIE_LMS_BACKENDS = [{
        "BACKEND":
        values.Value(
            "richie.apps.courses.lms.edx.EdXLMSBackend",
            environ_name="EDX_BACKEND",
            environ_prefix=None,
        ),
        "JS_BACKEND":
        values.Value(
            "openedx-hawthorn",
            environ_name="EDX_JS_BACKEND",
            environ_prefix=None,
        ),
        "COURSE_REGEX":
        values.Value(
            r"^.*/courses/(?P<course_id>.*)/course/?$",
            environ_name="EDX_COURSE_REGEX",
            environ_prefix=None,
        ),
        "JS_COURSE_REGEX":
        values.Value(
            r"^.*/courses/(.*)/course/?$",
            environ_name="EDX_JS_COURSE_REGEX",
            environ_prefix=None,
        ),
        "BASE_URL":
        values.Value(environ_name="EDX_BASE_URL", environ_prefix=None),
    }]
    RICHIE_COURSE_RUN_SYNC_SECRETS = values.ListValue([])

    # CMS
    # Minimum enrollment count value that would be shown on course detail page
    RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT = values.Value(
        0,
        environ_name="RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT",
        environ_prefix=None,
    )

    # Internationalization
    TIME_ZONE = "Europe/Paris"
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True
    LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]

    # Templates
    TEMPLATES = [{
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(BASE_DIR, "templates")],
        "OPTIONS": {
            "context_processors": [
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "django.template.context_processors.i18n",
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.template.context_processors.media",
                "django.template.context_processors.csrf",
                "django.template.context_processors.tz",
                "sekizai.context_processors.sekizai",
                "django.template.context_processors.static",
                "cms.context_processors.cms_settings",
                "richie.apps.core.context_processors.site_metas",
            ],
            "loaders": [
                "django.template.loaders.filesystem.Loader",
                "django.template.loaders.app_directories.Loader",
            ],
        },
    }]

    # Django CMS
    CMS_PLACEHOLDER_CONF_OVERRIDES = {
        "courses/cms/course_detail.html course_teaser": {
            "name": _("Teaser"),
            "plugins": ["LTIConsumerPlugin"],
            "limits": {
                "LTIConsumerPlugin": 1
            },
        },
        "courses/cms/course_detail.html course_audience": {
            "name": _("Audience"),
            "plugins": ["CKEditorPlugin"],
            "limits": {
                "CKEditorPlugin": 1
            },
        },
    }

    RICHIE_SIMPLETEXT_CONFIGURATION = [
        *RichieCoursesConfigurationMixin.RICHIE_SIMPLETEXT_CONFIGURATION,
        {
            "placeholders": ["course_audience"],
            "ckeditor": "CKEDITOR_LIMITED_CONFIGURATION",
            "max_length": 1200,
        },
    ]

    MIDDLEWARE = (
        "richie.apps.core.cache.LimitBrowserCacheTTLHeaders",
        "cms.middleware.utils.ApphookReloadMiddleware",
        "django.middleware.security.SecurityMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.middleware.common.CommonMiddleware",
        "django.middleware.clickjacking.XFrameOptionsMiddleware",
        "dockerflow.django.middleware.DockerflowMiddleware",
        "cms.middleware.user.CurrentUserMiddleware",
        "cms.middleware.page.CurrentPageMiddleware",
        "cms.middleware.toolbar.ToolbarMiddleware",
        "cms.middleware.language.LanguageCookieMiddleware",
        "dj_pagination.middleware.PaginationMiddleware",
    )

    INSTALLED_APPS = (
        # CNFPT stuff
        "base",
        # Richie stuff
        "richie.apps.demo",
        "richie.apps.search",
        "richie.apps.courses",
        "richie.apps.core",
        "richie.plugins.glimpse",
        "richie.plugins.html_sitemap",
        "richie.plugins.large_banner",
        "richie.plugins.lti_consumer",
        "richie.plugins.nesteditem",
        "richie.plugins.plain_text",
        "richie.plugins.section",
        "richie.plugins.simple_picture",
        "richie.plugins.simple_text_ckeditor",
        "richie",
        # Third party apps
        "dj_pagination",
        "dockerflow.django",
        "parler",
        "rest_framework",
        "storages",
        # Django-cms
        "djangocms_admin_style",
        "djangocms_googlemap",
        "djangocms_link",
        "djangocms_picture",
        "djangocms_text_ckeditor",
        "djangocms_video",
        "django_check_seo",
        "cms",
        "menus",
        "sekizai",
        "treebeard",
        "filer",
        "easy_thumbnails",
        # Django
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.admin",
        "django.contrib.sites",
        "django.contrib.sitemaps",
        "django.contrib.staticfiles",
        "django.contrib.messages",
        "django.contrib.humanize",
    )

    # Languages
    # - Django
    LANGUAGE_CODE = "fr"

    # Careful! Languages should be ordered by priority, as this tuple is used to get
    # fallback/default languages throughout the app.
    # Use "en" as default as it is the language that is most likely to be spoken by any visitor
    # when their preferred language, whatever it is, is unavailable
    LANGUAGES = (("en", _("English")), ("fr", _("French")))

    # - Django CMS
    CMS_LANGUAGES = {
        "default": {
            "public": True,
            "hide_untranslated": False,
            "redirect_on_fallback": True,
            "fallbacks": ["en", "fr"],
        },
        1: [
            {
                "public": False,
                "code": "en",
                "hide_untranslated": False,
                "name": _("English"),
                "fallbacks": ["fr"],
                "redirect_on_fallback": True,
            },
            {
                "public": True,
                "code": "fr",
                "hide_untranslated": False,
                "name": _("French"),
                "fallbacks": ["en"],
                "redirect_on_fallback": True,
            },
        ],
    }

    # - Django Parler
    PARLER_LANGUAGES = CMS_LANGUAGES

    # Permisions
    # - Django CMS
    CMS_PERMISSION = True

    # - Django Filer
    FILER_ENABLE_PERMISSIONS = True
    FILER_IS_PUBLIC_DEFAULT = True

    # - Django Pagination
    PAGINATION_INVALID_PAGE_RAISES_404 = True
    PAGINATION_DEFAULT_WINDOW = 2
    PAGINATION_DEFAULT_MARGIN = 1

    # Logging
    LOGGING = {
        "version": 1,
        "disable_existing_loggers": True,
        "formatters": {
            "verbose": {
                "format":
                "%(levelname)s %(asctime)s %(module)s "
                "%(process)d %(thread)d %(message)s"
            }
        },
        "handlers": {
            "console": {
                "level": "DEBUG",
                "class": "logging.StreamHandler",
                "formatter": "verbose",
            }
        },
        "loggers": {
            "django.db.backends": {
                "level": "ERROR",
                "handlers": ["console"],
                "propagate": False,
            }
        },
    }

    # Demo
    RICHIE_DEMO_SITE_DOMAIN = "localhost:8000"
    RICHIE_DEMO_FIXTURES_DIR = os.path.join(BASE_DIR, "base", "fixtures")

    # Elasticsearch
    RICHIE_ES_HOST = values.Value("elasticsearch",
                                  environ_name="RICHIE_ES_HOST",
                                  environ_prefix=None)
    RICHIE_ES_INDICES_PREFIX = values.Value(
        default="richie",
        environ_name="RICHIE_ES_INDICES_PREFIX",
        environ_prefix=None)
    RICHIE_ES_STATE_WEIGHTS = values.ListValue(None)

    # LTI Content
    RICHIE_LTI_PROVIDERS = {
        "marsha": {
            "oauth_consumer_key":
            values.Value(
                "InsecureOauthConsumerKey",
                environ_name="LTI_OAUTH_CONSUMER_KEY",
                environ_prefix=None,
            ),
            "shared_secret":
            values.Value(
                "InsecureSharedSecret",
                environ_name="LTI_SHARED_SECRET",
                environ_prefix=None,
            ),
            "base_url":
            values.Value(
                "https://marsha\.education/lti/videos/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",  # noqa
                environ_name="LTI_BASE_URL",
                environ_prefix=None,
            ),
            "display_name":
            "Marsha Video",
            "is_base_url_regex":
            True,
            "automatic_resizing":
            True,
            "inline_ratio":
            0.5625,
        }
    }

    # Cache
    CACHES = values.DictValue({
        "default": {
            "BACKEND":
            values.Value(
                "base.cache.RedisCacheWithFallback",
                environ_name="CACHE_DEFAULT_BACKEND",
                environ_prefix=None,
            ),
            "LOCATION":
            values.Value(
                "mymaster/redis-sentinel:26379,redis-sentinel:26379/0",
                environ_name="CACHE_DEFAULT_LOCATION",
                environ_prefix=None,
            ),
            "OPTIONS":
            values.DictValue(
                {
                    "CLIENT_CLASS": "richie.apps.core.cache.SentinelClient",
                },
                environ_name="CACHE_DEFAULT_OPTIONS",
                environ_prefix=None,
            ),
            "TIMEOUT":
            values.IntegerValue(300,
                                environ_name="CACHE_DEFAULT_TIMEOUT",
                                environ_prefix=None),
        },
        "memory_cache": {
            "BACKEND":
            values.Value(
                "django.core.cache.backends.locmem.LocMemCache",
                environ_name="CACHE_FALLBACK_BACKEND",
                environ_prefix=None,
            ),
            "LOCATION":
            values.Value(
                None,
                environ_name="CACHE_FALLBACK_LOCATION",
                environ_prefix=None,
            ),
            "OPTIONS":
            values.DictValue(
                {},
                environ_name="CACHE_FALLBACK_OPTIONS",
                environ_prefix=None,
            ),
        },
    })

    # Search
    RICHIE_FILTERS_CONFIGURATION = [
        (
            "richie.apps.search.filter_definitions.NestingWrapper",
            {
                "name":
                "course_runs",
                "filters": [
                    (
                        "richie.apps.search.filter_definitions.AvailabilityFilterDefinition",
                        {
                            "human_name": _("Availability"),
                            "is_drilldown": True,
                            "min_doc_count": 0,
                            "name": "availability",
                            "position": 1,
                        },
                    ),
                ],
            },
        ),
        (
            "richie.apps.search.filter_definitions.IndexableHierarchicalFilterDefinition",
            {
                "human_name": _("Subjects"),
                "min_doc_count": 0,
                "name": "subjects",
                "position": 2,
                "reverse_id": "subjects",
                "term": "categories",
            },
        ),
    ]

    # For more details about CMS_CACHE_DURATION, see :
    # http://docs.django-cms.org/en/latest/reference/configuration.html#cms-cache-durations
    CMS_CACHE_DURATIONS = values.DictValue({
        "menus": 3600,
        "content": 86400,
        "permissions": 86400
    })
    MAX_BROWSER_CACHE_TTL = 600

    # Sessions
    SESSION_ENGINE = values.Value("django.contrib.sessions.backends.cache")

    # Sentry
    SENTRY_DSN = values.Value(None, environ_name="SENTRY_DSN")

    # Admin
    # - Django CMS
    # Maximum children nodes to allow a parent to be unfoldable
    # in the page tree admin view
    CMS_PAGETREE_DESCENDANTS_LIMIT = 80

    # - Django CMS Check SEO
    # Excludes all elements that are not related to the page content
    DJANGO_CHECK_SEO_EXCLUDE_CONTENT = (
        "body > svg, #main-menu, .body-footer, .body-mentions")

    # pylint: disable=invalid-name
    @property
    def ENVIRONMENT(self):
        """Environment in which the application is launched."""
        return self.__class__.__name__.lower()

    # pylint: disable=invalid-name
    @property
    def RELEASE(self):
        """
        Return the release information.

        Delegate to the module function to enable easier testing.
        """
        return get_release()

    # pylint: disable=invalid-name
    @property
    def CMS_CACHE_PREFIX(self):
        """
        Set cache prefix specific to release so existing cache is invalidated for new deployments.
        """
        return f"cms_{get_release():s}_"

    @classmethod
    def post_setup(cls):
        """Post setup configuration.
        This is the place where you can configure settings that require other
        settings to be loaded.
        """
        super().post_setup()

        # The SENTRY_DSN setting should be available to activate sentry for an environment
        if cls.SENTRY_DSN is not None:
            sentry_sdk.init(
                dsn=cls.SENTRY_DSN,
                environment=cls.__name__.lower(),
                release=get_release(),
                integrations=[DjangoIntegration()],
            )
            with sentry_sdk.configure_scope() as scope:
                scope.set_extra("application", "backend")

        # Customize DjangoCMS placeholders configuration
        cls.CMS_PLACEHOLDER_CONF = merge_dict(
            cls.CMS_PLACEHOLDER_CONF, cls.CMS_PLACEHOLDER_CONF_OVERRIDES)
Ejemplo n.º 29
0
class UipaOrgThemeBase(ThemeBase):
    FROIDE_THEME = 'uipa_org.theme'

    SITE_NAME = "UIPA.org"
    SITE_EMAIL = "*****@*****.**"
    SITE_URL = 'http://localhost:8000'

    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
    STATIC_ROOT = os.path.abspath(os.path.join(PROJECT_ROOT, "..", "public"))

    FIXTURE_DIRS = ('fixtures',)

    MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'

    SECRET_KEY = os_env('SECRET_KEY')

    MEDIA_ROOT = os_env('MEDIA_ROOT')

    DATA_UPLOAD_MAX_MEMORY_SIZE = 26214400  # 25MB

    TAGGING_AUTOCOMPLETE_MAX_TAGS = 100

    @property
    def INSTALLED_APPS(self):
        installed = super(UipaOrgThemeBase, self).INSTALLED_APPS
        installed += [
            'celery_haystack',
            'djcelery_email',
            'django.contrib.redirects',
            'uipa_org.uipa_constants',
            'uipa_org.theme.templatetags.uipa_extras',
            'tinymce',
            'raven.contrib.django.raven_compat'
        ]
        return installed

    MIDDLEWARE_CLASSES = [
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
        'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
        'froide.account.middleware.AcceptNewTermsMiddleware',
    ]

    TINYMCE_DEFAULT_CONFIG = {
        'plugins': "table,spellchecker,paste,searchreplace",
        'theme': "advanced",
        'cleanup_on_startup': False
    }

    SECRET_URLS = values.DictValue({
        "admin": "uipa-admin",
        "postmark_inbound": "uipa_postmark_inbound",
        "postmark_bounce": "uipa_postmark_bounce"
    })

    HAYSTACK_CONNECTIONS = {
        'default': {
            'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
            'URL': 'http://127.0.0.1:9200/',
            'INDEX_NAME': 'haystack',
        }
    }

    TIME_ZONE = values.Value('Pacific/Honolulu')

    CELERY_IMPORTS = ('uipa_org.tasks',)
    CELERY_TIMEZONE = values.Value('Pacific/Honolulu')

    CELERYBEAT_SCHEDULE = {
        'fetch-mail': {
            'task': 'froide.foirequest.tasks.fetch_mail',
            'schedule': crontab(),
        },
        'detect-asleep': {
            'task': 'froide.foirequest.tasks.detect_asleep',
            'schedule': crontab(hour=0, minute=0),
        },
        'detect-overdue': {
            'task': 'froide.foirequest.tasks.detect_overdue',
            'schedule': crontab(hour=0, minute=0),
        },
        'update-foirequestfollowers': {
            'task': 'froide.foirequestfollower.tasks.batch_update',
            'schedule': crontab(hour=0, minute=0),
        },
        'classification-reminder': {
            'task': 'froide.foirequest.tasks.classification_reminder',
            'schedule': crontab(hour=7, minute=0, day_of_week=6),
        },
        'uipa-private_public_reminder': {
            'task': 'uipa_org.tasks.private_public_reminder',
            'schedule': crontab(hour=0, minute=0),
        },
        'uipa-make_public_private': {
            'task': 'uipa_org.tasks.make_private_public',
            'schedule': crontab(hour=0, minute=0),
        },
        'uipa-deferred_message_notification': {
            'task': 'uipa_org.tasks.deferred_message_notification',
            'schedule': crontab(hour=6, minute=0),
        },
    }

    CELERY_RESULT_BACKEND = 'rpc'
    CELERY_RESULT_PERSISTENT = True

    @property
    def FROIDE_CONFIG(self):
        config = super(UipaOrgThemeBase, self).FROIDE_CONFIG
        config.update(dict(
            currency="Dollars",
            create_new_publicbody=False,
            publicbody_empty=False,
            user_can_hide_web=True,
            public_body_officials_public=True,
            public_body_officials_email_public=False,
            request_public_after_due_days=14,
            payment_possible=False,
            default_law=1,
            greetings=[rec(u"Aloha (?:Mr\.?|Ms\.? .*?)")],
            closings=[rec(u"Mahalo,?")],
            public_body_boosts={},
            dryrun=True,
            dryrun_domain="beta.uipa.org",
            allow_pseudonym=False,
            # doc_conversion_binary=None,  # replace with libreoffice instance
            doc_conversion_binary="/Applications/LibreOffice.app/Contents/MacOS/soffice",
            doc_conversion_call_func=None,  # see settings_test for use
            api_activated=True,
            search_engine_query='http://www.google.com/search?as_q=%(query)s&as_epq=&as_oq=&as_eq=&hl=en&lr=&cr=&as_ft=i&as_filetype=&as_qdr=all&as_occt=any&as_dt=i&as_sitesearch=%(domain)s&as_rights=&safe=images',
            show_public_body_employee_name=False,
            make_public_num_days_after_due_date=365,
            ga_tracking_id=os_env('GA_TRACKING_ID'),
        ))
        return config
Ejemplo n.º 30
0
class Production(Base):
    INSTALLED_APPS = Base.INSTALLED_APPS + [
        'raven.contrib.django.raven_compat',
    ]
    RAVEN_CONFIG = values.DictValue()