""" Django settings for sapl project. Generated by 'django-admin startproject' using Django 1.8.2. For more information on this file, see https://docs.djangoproject.com/en/1.8/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ Quick-start development settings - unsuitable for production See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ """ import logging import socket from decouple import config from dj_database_url import parse as db_url from easy_thumbnails.conf import Settings as thumbnail_settings from unipath import Path logging.captureWarnings(True) logger = logging.getLogger(__name__) host = socket.gethostbyname_ex(socket.gethostname())[0] BASE_DIR = Path(__file__).ancestor(1) PROJECT_DIR = Path(__file__).ancestor(2) DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = config("SECRET_KEY", default="32jk1h412l3kjh421lkj4hlkj234") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = config("DEBUG", default=False, cast=bool) MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage" ALLOWED_HOSTS = ["*"] LOGIN_REDIRECT_URL = "/" LOGIN_URL = "/login/?next=" SAPL_VERSION = "3.1.164-RC1" if DEBUG: EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" else: EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" # SAPL business apps in dependency order SAPL_APPS = ( "sapl.audiencia", "sapl.base", "sapl.crud", "sapl.parlamentares", "sapl.comissoes", "sapl.materia", "sapl.norma", "sapl.sessao", "sapl.lexml", "sapl.painel", "sapl.protocoloadm", "sapl.redireciona_urls", "sapl.compilacao", "sapl.api", "sapl.rules", ) INSTALLED_APPS = ( "django_admin_bootstrapped", # must come before django.contrib.admin "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "django.forms", "django_extensions", "crispy_forms", "crispy_bootstrap4", "waffle", "drf_spectacular", "rest_framework", "rest_framework.authtoken", "django_filters", "easy_thumbnails", "image_cropping", "haystack", "django.contrib.postgres", "webpack_loader", "django_prometheus", ) + SAPL_APPS # FTS = Full Text Search # Desabilita a indexação textual até encontramos uma solução para a issue # https://github.com/interlegis/sapl/issues/2055 HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.BaseSignalProcessor" # Disable auto index SEARCH_BACKEND = "" SEARCH_URL = ["", ""] # SOLR USE_SOLR = config("USE_SOLR", cast=bool, default=False) SOLR_URL = config("SOLR_URL", cast=str, default="http://localhost:8983") SOLR_COLLECTION = config("SOLR_COLLECTION", cast=str, default="sapl") # FOR HAYSTACK 3.3.1 (Django >= 3) # SOLR_USER = config('SOLR_USER', cast=str) # SOLR_PASSWORD = config('SOLR_PASSWORD', cast=str) if USE_SOLR: HAYSTACK_SIGNAL_PROCESSOR = ( "haystack.signals.RealtimeSignalProcessor" # enable auto-index ) SEARCH_BACKEND = "haystack.backends.solr_backend.SolrEngine" SEARCH_URL = ("URL", "{}/solr/{}".format(SOLR_URL, SOLR_COLLECTION)) # BATCH_SIZE: default is 1000 if omitted, avoid Too Large Entity Body errors HAYSTACK_CONNECTIONS = { "default": { "ENGINE": SEARCH_BACKEND, SEARCH_URL[0]: SEARCH_URL[1], "BATCH_SIZE": 1000, "TIMEOUT": 20, # 'KWARGS': { # 'timeout': 60, # 'auth': (SOLR_USER, SOLR_PASSWORD), # <-- for basic auth # }, }, } MIDDLEWARE = [ "django_prometheus.middleware.PrometheusBeforeMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.locale.LocaleMiddleware", "django.middleware.common.CommonMiddleware", "sapl.endpoint_restriction_middleware.EndpointRestrictionMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", "django_prometheus.middleware.PrometheusAfterMiddleware", "waffle.middleware.WaffleMiddleware", "sapl.middleware.CheckWeakPasswordMiddleware", ] if DEBUG: INSTALLED_APPS += ("debug_toolbar",) MIDDLEWARE += [ "debug_toolbar.middleware.DebugToolbarMiddleware", ] INTERNAL_IPS = "127.0.0.1" SITE_URL = config("SITE_URL", cast=str, default="") REST_FRAMEWORK = { "UNICODE_JSON": False, "DEFAULT_PARSER_CLASSES": ( "rest_framework.parsers.JSONParser", "rest_framework.parsers.MultiPartParser", ), "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",), "DEFAULT_PERMISSION_CLASSES": ("sapl.api.permissions.SaplModelPermissions",), "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.SessionAuthentication", ), "DEFAULT_SCHEMA_CLASS": "sapl.api.schema.Schema", "DEFAULT_PAGINATION_CLASS": "sapl.api.pagination.StandardPagination", "DEFAULT_FILTER_BACKENDS": ( "rest_framework.filters.SearchFilter", "django_filters.rest_framework.DjangoFilterBackend", ), } DRFAUTOAPI = { "DEFAULT_SERIALIZER_MODULE": "sapl.api.serializers", "DEFAULT_FILTER_MODULE": "sapl.api.forms", "GLOBAL_SERIALIZER_MIXIN": "sapl.api.serializers.SaplSerializerMixin", "GLOBAL_FILTERSET_MIXIN": "sapl.api.forms.SaplFilterSetMixin", } SPECTACULAR_SETTINGS = { "TITLE": "Sapl API - docs", "DESCRIPTION": "Sapl API - Docs", "VERSION": "1.0.0", } CACHES = { "default": { "BACKEND": "django.core.cache.backends.filebased.FileBasedCache", "LOCATION": "/var/tmp/django_cache", "OPTIONS": {"MAX_ENTRIES": 10000}, } } ROOT_URLCONF = "sapl.urls" FORM_RENDERER = "django.forms.renderers.TemplatesSetting" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": ["sapl/templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.template.context_processors.media", "django.template.context_processors.static", "django.contrib.messages.context_processors.messages", "sapl.context_processors.parliament_info", "sapl.context_processors.mail_service_configured", "sapl.context_processors.google_recaptcha_configured", "sapl.context_processors.enable_sapn", ], "debug": DEBUG, }, }, ] WSGI_APPLICATION = "sapl.wsgi.application" # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases # Parse DATABASE_URL # dj-database-url==0.5.0 is the latest compatible with Django 2.2, later versions required Django >= 4 # but it doesn't support OPTIONS tag, so we need setup_db_tz # This should be removed once we are able to upgrade to Django >= 4 DATABASES = {"default": config("DATABASE_URL", cast=db_url)} def setup_db_tz(): ### TODO: dj-database-url now supports CONN_MAX_AGE and OPTIONS db = DATABASES["default"] # Normalize legacy engine alias returned by old dj-database-url if db.get("ENGINE") == "django.db.backends.postgresql_psycopg2": db["ENGINE"] = "django.db.backends.postgresql" # Force UTC per connection for Postgres (fixes Django’s utc_tzinfo_factory assertion) if db.get("ENGINE") == "django.db.backends.postgresql": opts = db.setdefault("OPTIONS", {}) existing = (opts.get("options") or "").strip() force_utc = "-c timezone=UTC" opts["options"] = f"{existing} {force_utc}".strip() if existing else force_utc # ensure default TCP port if you use HOST; leave sockets alone if HOST is empty if db.get("HOST") and not db.get("PORT"): db["PORT"] = "5432" # Add connection lifetime # in recent dj-database-url versions, replace by config("DATABASE_URL", conn_max_age=300) db["CONN_MAX_AGE"] = 300 # keep connections for 5 minutes # Log if DEBUG mode if config("DEBUG", default=False, cast=bool): logger.debug("DB config: %r", db) setup_db_tz() IMAGE_CROPPING_JQUERY_URL = None THUMBNAIL_PROCESSORS = ( "image_cropping.thumbnail_processors.crop_corners", ) + thumbnail_settings.THUMBNAIL_PROCESSORS THUMBNAIL_SOURCE_GENERATORS = ("sapl.utils.pil_image",) # troque no caso de reimplementação da classe User conforme # https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model AUTH_USER_MODEL = "auth.User" X_FRAME_OPTIONS = "ALLOWALL" EMAIL_HOST = config("EMAIL_HOST", default="localhost") EMAIL_PORT = config("EMAIL_PORT", cast=int, default=587) EMAIL_HOST_USER = config("EMAIL_HOST_USER", default="") EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default="") EMAIL_USE_TLS = config("EMAIL_USE_TLS", cast=bool, default=True) EMAIL_SEND_USER = config("EMAIL_SEND_USER", cast=str, default="") DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL", cast=str, default="") SERVER_EMAIL = config("SERVER_EMAIL", cast=str, default="") EMAIL_RUNNING = None # Feature Flag WAFFLE_FLAG_DEFAULT = False WAFFLE_SWITCH_DEFAULT = False WAFFLE_CREATE_MISSING_FLAGS = True WAFFLE_LOG_MISSING_FLAGS = True WAFFLE_CREATE_MISSING_SWITCHES = True WAFFLE_LOG_MISSING_SWITCHES = True WAFFLE_ENABLE_ADMIN_PAGES = True MAX_DOC_UPLOAD_SIZE = 150 * 1024 * 1024 # 150MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ LANGUAGE_CODE = "pt-br" LANGUAGES = (("pt-br", "Português"),) TIME_ZONE = config("TZ", default="America/Sao_Paulo") if not TIME_ZONE: raise ValueError( "TIMEZONE env variable undefined in .env settings file! Leaving..." ) USE_I18N = True USE_TZ = True # DATE_FORMAT = 'N j, Y' DATE_FORMAT = "d/m/Y" SHORT_DATE_FORMAT = "d/m/Y" DATETIME_FORMAT = "d/m/Y H:i:s" SHORT_DATETIME_FORMAT = "d/m/Y H:i" DATE_INPUT_FORMATS = ("%d/%m/%Y", "%m-%d-%Y", "%Y-%m-%d") LOCALE_PATHS = ("locale",) WEBPACK_LOADER = { "DEFAULT": { "CACHE": not DEBUG, "BUNDLE_DIR_NAME": "sapl/static/sapl/frontend", "STATS_FILE": PROJECT_DIR.child("frontend").child( f'{"dev-" if DEBUG else ""}webpack-stats.json' ), "POLL_INTERVAL": 0.1, "TIMEOUT": None, "IGNORE": [r".+\.hot-update.js", r".+\.map"], } } if DEBUG and not WEBPACK_LOADER["DEFAULT"]["STATS_FILE"].exists(): WEBPACK_LOADER["DEFAULT"]["STATS_FILE"] = PROJECT_DIR.child("frontend").child( f"webpack-stats.json" ) STATIC_URL = "/static/" STATIC_ROOT = PROJECT_DIR.child("collected_static") STATICFILES_DIRS = (BASE_DIR.child("static"),) STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) MEDIA_ROOT = PROJECT_DIR.child("media") MEDIA_URL = "/media/" FILE_UPLOAD_PERMISSIONS = 0o644 DAB_FIELD_RENDERER = "django_admin_bootstrapped.renderers.BootstrapFieldRenderer" CRISPY_TEMPLATE_PACK = "bootstrap4" CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap4" CRISPY_FAIL_SILENTLY = False # suprime texto de ajuda default do django-filter FILTERS_HELP_TEXT_FILTER = False LOGGING_CONSOLE_VERBOSE = config("LOGGING_CONSOLE_VERBOSE", cast=bool, default=False) LOGGING = { "version": 1, "disable_existing_loggers": False, "handlers": { "console": {"class": "logging.StreamHandler"}, }, "root": { # everything falls back here "handlers": ["console"], "level": "DEBUG", }, "loggers": { "django.request": { # 500s go here "handlers": ["console"], "level": "ERROR", "propagate": False, }, }, } PASSWORD_HASHERS = [ "django.contrib.auth.hashers.PBKDF2PasswordHasher", # default "sapl.hashers.ZopeSHA1PasswordHasher", ] LOGOUT_REDIRECT_URL = "/login"