Source code for geonode.settings

    #########################################################################
#
# Copyright (C) 2016 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

# Django settings for the GeoNode project.
import os
import re
import ast
import sys
import subprocess
import dj_database_url
from schema import Optional
from datetime import timedelta
from urllib.parse import urlparse, urljoin

#
# General Django development settings
#
from django.conf.global_settings import DATETIME_INPUT_FORMATS
from geonode import get_version
from kombu import Queue, Exchange
from kombu.serialization import register

from . import serializer

[docs] SILENCED_SYSTEM_CHECKS = [ "1_8.W001", "fields.W340", "auth.W004", "urls.W002", "drf_spectacular.W001", "drf_spectacular.W002", ]
# GeoNode Version
[docs] VERSION = get_version()
[docs] DEFAULT_CHARSET = "utf-8"
# Defines the directory that contains the settings file as the PROJECT_ROOT # It is used for relative settings elsewhere.
[docs] PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
# Setting debug to true makes Django serve static media and # present pretty error pages.
[docs] DEBUG = ast.literal_eval(os.getenv("DEBUG", "True"))
# Set to True to load non-minified versions of (static) client dependencies # Requires to set-up Node and tools that are required for static development # otherwise it will raise errors for the missing non-minified dependencies
[docs] DEBUG_STATIC = ast.literal_eval(os.getenv("DEBUG_STATIC", "False"))
[docs] FORCE_SCRIPT_NAME = os.getenv("FORCE_SCRIPT_NAME", "")
# Define email service on GeoNode
[docs] EMAIL_ENABLE = ast.literal_eval(os.getenv("EMAIL_ENABLE", "False"))
if EMAIL_ENABLE:
[docs] EMAIL_BACKEND = os.getenv("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend")
EMAIL_HOST = os.getenv("DJANGO_EMAIL_HOST", "localhost") EMAIL_PORT = os.getenv("DJANGO_EMAIL_PORT", 25) EMAIL_HOST_USER = os.getenv("DJANGO_EMAIL_HOST_USER", "") EMAIL_HOST_PASSWORD = os.getenv("DJANGO_EMAIL_HOST_PASSWORD", "") EMAIL_USE_TLS = ast.literal_eval(os.getenv("DJANGO_EMAIL_USE_TLS", "False")) EMAIL_USE_SSL = ast.literal_eval(os.getenv("DJANGO_EMAIL_USE_SSL", "False")) DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", "GeoNode <no-reply@geonode.org>") else: EMAIL_BACKEND = os.getenv("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend") # Make this unique, and don't share it with anybody.
[docs] _DEFAULT_SECRET_KEY = "myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a"
[docs] SECRET_KEY = os.getenv("SECRET_KEY", _DEFAULT_SECRET_KEY)
[docs] SITE_HOST_SCHEMA = os.getenv("SITE_HOST_SCHEMA", "http")
[docs] SITE_HOST_NAME = os.getenv("SITE_HOST_NAME", "localhost")
[docs] SITE_HOST_PORT = os.getenv("SITE_HOST_PORT", 8000)
[docs] _default_siteurl = ( f"{SITE_HOST_SCHEMA}://{SITE_HOST_NAME}:{SITE_HOST_PORT}/" if SITE_HOST_PORT else f"{SITE_HOST_SCHEMA}://{SITE_HOST_NAME}/" )
SITEURL = os.getenv("SITEURL", _default_siteurl) # we need hostname for deployed
[docs] _surl = urlparse(SITEURL)
[docs] HOSTNAME = _surl.hostname
# add trailing slash to site url. geoserver url will be relative to this if not SITEURL.endswith("/"):
[docs] SITEURL = f"{SITEURL}/"
[docs] _DB_PATH = os.path.join(PROJECT_ROOT, "development.db")
[docs] DATABASE_URL = os.getenv("DATABASE_URL", f"spatialite:///{_DB_PATH}")
if DATABASE_URL.startswith("spatialite"): try:
[docs] spatialite_proc = subprocess.run(["spatialite", "-version"], stdout=subprocess.PIPE)
spatialite_version = int(spatialite_proc.stdout.decode()[0]) if spatialite_version < 5: # To workaround Shapely/Spatialite interaction bug for Spatialite < 5 from shapely import speedups speedups.enable() except FileNotFoundError as ex: print(ex) # DATABASE_URL = 'postgresql://test_geonode:test_geonode@localhost:5432/geonode' # Defines settings for development # since GeoDjango is in use, you should use gis-enabled engine, for example: # 'ENGINE': 'django.contrib.gis.db.backends.postgis' # see https://docs.djangoproject.com/en/1.8/ref/contrib/gis/db-api/#module-django.contrib.gis.db.backends for # detailed list of supported backends and notes.
[docs] GEONODE_DB_CONN_MAX_AGE = int(os.getenv("GEONODE_DB_CONN_MAX_AGE", 0))
[docs] GEONODE_DB_CONN_TOUT = int(os.getenv("GEONODE_DB_CONN_TOUT", 5))
[docs] _db_conf = dj_database_url.parse(DATABASE_URL, conn_max_age=GEONODE_DB_CONN_MAX_AGE)
if "CONN_TOUT" in _db_conf: _db_conf["CONN_TOUT"] = GEONODE_DB_CONN_TOUT if "postgresql" in DATABASE_URL or "postgis" in DATABASE_URL: if "OPTIONS" not in _db_conf: _db_conf["OPTIONS"] = {} _db_conf["OPTIONS"].update( { "connect_timeout": GEONODE_DB_CONN_TOUT, } )
[docs] DATABASES = {"default": _db_conf}
if os.getenv("DEFAULT_BACKEND_DATASTORE"):
[docs] GEODATABASE_URL = os.getenv( "GEODATABASE_URL", "postgis://\ geonode_data:geonode_data@localhost:5432/geonode_data", )
DATABASES[os.getenv("DEFAULT_BACKEND_DATASTORE")] = dj_database_url.parse( GEODATABASE_URL, conn_max_age=GEONODE_DB_CONN_MAX_AGE ) _geo_db = DATABASES[os.getenv("DEFAULT_BACKEND_DATASTORE")] if "CONN_TOUT" in DATABASES["default"]: _geo_db["CONN_TOUT"] = DATABASES["default"]["CONN_TOUT"] if "postgresql" in GEODATABASE_URL or "postgis" in GEODATABASE_URL: _geo_db["OPTIONS"] = DATABASES["default"]["OPTIONS"] if "OPTIONS" in DATABASES["default"] else {} _geo_db["OPTIONS"].update( { "connect_timeout": GEONODE_DB_CONN_TOUT, } ) DATABASES[os.getenv("DEFAULT_BACKEND_DATASTORE")] = _geo_db # If set to 'True' it will refresh/regenrate all resource links everytime a 'migrate' will be performed MANAGERS = ADMINS = os.getenv("ADMINS", []) # 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. # If running in a Windows environment this must be set to the same as your # system time zone.
[docs] TIME_ZONE = os.getenv("TIME_ZONE", "UTC")
[docs] SITE_ID = int(os.getenv("SITE_ID", "1"))
[docs] USE_TZ = True
[docs] USE_I18N = ast.literal_eval(os.getenv("USE_I18N", "True"))
[docs] USE_L10N = ast.literal_eval(os.getenv("USE_I18N", "True"))
# Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html
[docs] LANGUAGE_CODE = os.getenv("LANGUAGE_CODE", "en")
[docs] _DEFAULT_LANGUAGES = """( ('af', 'Afrikaans'), ('sq', 'Albanian'), ('am', 'Amharic'), ('ar', 'Arabic'), ('id', 'Bahasa Indonesia'), ('bn', 'Bengali'), ('de', 'Deutsch'), ('en', 'English'), ('es', 'Español'), ('fr', 'Français'), ('it', 'Italiano'), ('km', 'Khmer'), ('nl', 'Nederlands'), ('ne', 'Nepali'), ('fa', 'Persian'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Portuguese (Brazil)'), ('ru', 'Russian'), ('si', 'Sinhala'), ('sw', 'Swahili'), ('sv', 'Swedish'), ('tl', 'Tagalog'), ('ta', 'Tamil'), ('uk', 'Ukranian'), ('vi', 'Vietnamese'), ('el', 'Ελληνικά'), ('th', 'ไทย'), ('zh-cn', '中文'), ('ja', '日本語'), ('ko', '한국어'), ('sk', 'Slovensky'), )"""
[docs] LANGUAGES = ast.literal_eval(os.getenv("LANGUAGES", _DEFAULT_LANGUAGES))
[docs] EXTRA_LANG_INFO = { "am": { "bidi": False, "code": "am", "name": "Amharic", "name_local": "Amharic", }, "tl": { "bidi": False, "code": "tl", "name": "Tagalog", "name_local": "tagalog", }, "ta": { "bidi": False, "code": "ta", "name": "Tamil", "name_local": "tamil", }, "si": { "bidi": False, "code": "si", "name": "Sinhala", "name_local": "sinhala", }, }
[docs] AUTH_USER_MODEL = os.getenv("AUTH_USER_MODEL", "people.Profile")
[docs] PASSWORD_HASHERS = [ "django.contrib.auth.hashers.SHA1PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", # 'django.contrib.auth.hashers.Argon2PasswordHasher', # 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', # 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
[docs] MODELTRANSLATION_LANGUAGES = [ "en", ]
[docs] MODELTRANSLATION_DEFAULT_LANGUAGE = "en"
[docs] MODELTRANSLATION_FALLBACK_LANGUAGES = ("en",)
# Location of translation files
[docs] _DEFAULT_LOCALE_PATHS = (os.path.join(PROJECT_ROOT, "locale"),)
[docs] LOCALE_PATHS = os.getenv("LOCALE_PATHS", _DEFAULT_LOCALE_PATHS)
# Location of url mappings
[docs] ROOT_URLCONF = os.getenv("ROOT_URLCONF", "geonode.urls")
# ########################################################################### # # MEDIA / STATICS STORAGES SETTINGS # ########################################################################### #
[docs] STATICFILES_LOCATION = "static"
[docs] MEDIAFILES_LOCATION = "uploaded"
[docs] THUMBNAIL_LOCATION = "thumbs"
# Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/"
[docs] MEDIA_ROOT = os.getenv("MEDIA_ROOT", os.path.join(PROJECT_ROOT, MEDIAFILES_LOCATION))
# URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/"
[docs] MEDIA_URL = os.getenv("MEDIA_URL", f"{FORCE_SCRIPT_NAME}/{MEDIAFILES_LOCATION}/")
[docs] LOCAL_MEDIA_URL = os.getenv("LOCAL_MEDIA_URL", f"{FORCE_SCRIPT_NAME}/{MEDIAFILES_LOCATION}/")
# Absolute path to the directory that holds static files like app media. # Example: "/home/media/media.lawrence.com/apps/"
[docs] STATIC_ROOT = os.getenv("STATIC_ROOT", os.path.join(PROJECT_ROOT, "static_root"))
# Cache Bustin Settings: enable WhiteNoise compression and caching support # ref: http://whitenoise.evans.io/en/stable/django.html#add-compression-and-caching-support
[docs] CACHE_BUSTING_STATIC_ENABLED = ast.literal_eval(os.environ.get("CACHE_BUSTING_STATIC_ENABLED", "False"))
# Optionally Use a Content-Delivery Network # ref: http://whitenoise.evans.io/en/stable/django.html#use-a-content-delivery-network
[docs] STATIC_HOST = os.environ.get("STATIC_URL", "")
# URL that handles the static files like app media. # Example: "http://media.lawrence.com" if FORCE_SCRIPT_NAME:
[docs] STATIC_URL = f"{STATIC_HOST}/{FORCE_SCRIPT_NAME}/{STATICFILES_LOCATION}/"
else: STATIC_URL = f"{STATIC_HOST}/{STATICFILES_LOCATION}/" # Additional directories which hold static files
[docs] _DEFAULT_STATICFILES_DIRS = [ os.path.join(PROJECT_ROOT, STATICFILES_LOCATION), ]
[docs] STATICFILES_DIRS = os.getenv("STATICFILES_DIRS", _DEFAULT_STATICFILES_DIRS)
# List of finder classes that know how to find static files in # various locations.
[docs] STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", # 'django.contrib.staticfiles.finders.DefaultStorageFinder', )
[docs] CACHES = { # DUMMY CACHE FOR DEVELOPMENT "default": { "BACKEND": "django.core.cache.backends.dummy.DummyCache", }, # MEMCACHED EXAMPLE # 'default': { # 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', # 'LOCATION': '127.0.0.1:11211', # }, # FILECACHE EXAMPLE # 'default': { # 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 'LOCATION': '/tmp/django_cache', # }, # DATABASE EXAMPLE -> python manage.py createcachetable # 'default': { # 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', # 'LOCATION': 'my_cache_table', # }, # LOCAL-MEMORY CACHING # 'default': { # 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 'LOCATION': 'geonode-cache', # 'TIMEOUT': 10, # 'OPTIONS': { # 'MAX_ENTRIES': 10000 # } # }, "resources": { "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "TIMEOUT": 600, "OPTIONS": {"MAX_ENTRIES": 10000}, }, }
# Whitenoise Settings - ref.: http://whitenoise.evans.io/en/stable/django.html
[docs] WHITENOISE_MANIFEST_STRICT = ast.literal_eval(os.getenv("WHITENOISE_MANIFEST_STRICT", "False"))
[docs] COMPRESS_STATIC_FILES = ast.literal_eval(os.getenv("COMPRESS_STATIC_FILES", "False"))
[docs] MEMCACHED_ENABLED = ast.literal_eval(os.getenv("MEMCACHED_ENABLED", "False"))
[docs] MEMCACHED_BACKEND = os.getenv("MEMCACHED_BACKEND", "django.core.cache.backends.memcached.PyMemcacheCache")
[docs] MEMCACHED_LOCATION = os.getenv("MEMCACHED_LOCATION", "127.0.0.1:11211")
[docs] MEMCACHED_LOCK_EXPIRE = int(os.getenv("MEMCACHED_LOCK_EXPIRE", 3600))
[docs] MEMCACHED_LOCK_TIMEOUT = int(os.getenv("MEMCACHED_LOCK_TIMEOUT", 10))
if MEMCACHED_ENABLED: CACHES["default"] = { "BACKEND": MEMCACHED_BACKEND, "LOCATION": MEMCACHED_LOCATION, } # Define the STATICFILES_STORAGE accordingly if not DEBUG and CACHE_BUSTING_STATIC_ENABLED:
[docs] STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
elif COMPRESS_STATIC_FILES: STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage" else: STATICFILES_STORAGE = "whitenoise.storage.StaticFilesStorage"
[docs] GEONODE_CORE_APPS = ( # GeoNode internal apps "geonode.api", "geonode.base", "geonode.br", "geonode.layers", "geonode.maps", "geonode.geoapps", "geonode.documents", "geonode.security", "geonode.catalogue", "geonode.catalogue.metadataxsl", "geonode.harvesting", )
# GeoNode Apps
[docs] GEONODE_APPS_ENABLE = ast.literal_eval(os.getenv("GEONODE_APPS_ENABLE", "True"))
[docs] GEONODE_APPS_NAME = os.getenv("GEONODE_APPS_NAME", "Apps")
[docs] GEONODE_APPS_NAV_MENU_ENABLE = ast.literal_eval(os.getenv("GEONODE_APPS_NAV_MENU_ENABLE", "True"))
[docs] GEONODE_INTERNAL_APPS = ( # GeoNode internal apps "geonode.people", "geonode.client", "geonode.themes", "geonode.proxy", "geonode.social", "geonode.groups", "geonode.services", "geonode.management_commands_http", "geonode.resource", "geonode.resource.processing", "geonode.storage", # GeoServer Apps # Geoserver needs to come last because # it's signals may rely on other apps' signals. "geonode.geoserver", "geonode.geoserver.processing", "geonode.upload", "geonode.tasks", "geonode.messaging", "geonode.favorite", "geonode.monitoring", )
[docs] GEONODE_CONTRIB_APPS = ( # GeoNode Contrib Apps )
# Uncomment the following line to enable contrib apps
[docs] GEONODE_APPS = GEONODE_CORE_APPS + GEONODE_INTERNAL_APPS + GEONODE_CONTRIB_APPS
[docs] INSTALLED_APPS = ( # Boostrap admin theme # 'django_admin_bootstrapped.bootstrap3', # 'django_admin_bootstrapped', # Apps bundled with Django "modeltranslation", "dal", "dal_select2", "grappelli", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.admin", "django.contrib.sitemaps", "whitenoise.runserver_nostatic", "django.contrib.staticfiles", "django.contrib.messages", "django.contrib.humanize", "django.contrib.gis", "sequences.apps.SequencesConfig", # Utility "dj_pagination", "taggit", "treebeard", "bootstrap3_datetime", "django_filters", "mptt", "storages", "floppyforms", "tinymce", "widget_tweaks", "django_celery_results", "markdownify", "django_user_agents", # REST APIs "rest_framework", "rest_framework_gis", "dynamic_rest", "drf_spectacular", # Theme "django_select2", "django_forms_bootstrap", # Social "avatar", "pinax.ratings", "announcements", "actstream", "user_messages", "tastypie", "polymorphic", "guardian", "oauth2_provider", "corsheaders", "invitations", # login with external providers "allauth", "allauth.account", "allauth.socialaccount", # GeoNode "geonode", )
[docs] markdown_white_listed_tags = [ "a", "p", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "ul", "li", "span", "blockquote", "strong", "code", ]
[docs] MARKDOWNIFY = {"default": {"WHITELIST_TAGS": os.getenv("MARKDOWNIFY_WHITELIST_TAGS", markdown_white_listed_tags)}}
[docs] MARKDOWNIFY_STRIP = os.getenv("MARKDOWNIFY_STRIP", False)
INSTALLED_APPS += GEONODE_APPS
[docs] REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", "oauth2_provider.contrib.rest_framework.OAuth2Authentication", ], "DEFAULT_RENDERER_CLASSES": [ "rest_framework.renderers.JSONRenderer", "dynamic_rest.renderers.DynamicBrowsableAPIRenderer", ], "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", "EXCEPTION_HANDLER": "geonode.base.api.exceptions.geonode_exception_handler", }
[docs] REST_FRAMEWORK_EXTENSIONS = { "DEFAULT_PARENT_LOOKUP_KWARG_NAME_PREFIX": "", }
[docs] REST_API_DEFAULT_PAGE = os.getenv("REST_API_DEFAULT_PAGE", 1)
[docs] REST_API_DEFAULT_PAGE_SIZE = os.getenv("REST_API_DEFAULT_PAGE_SIZE", 10)
[docs] REST_API_DEFAULT_PAGE_QUERY_PARAM = os.getenv("REST_API_DEFAULT_PAGE_QUERY_PARAM", "page_size")
[docs] DYNAMIC_REST = { # DEBUG: enable/disable internal debugging "DEBUG": False, # ENABLE_BROWSABLE_API: enable/disable the browsable API. # It can be useful to disable it in production. "ENABLE_BROWSABLE_API": True, # ENABLE_LINKS: enable/disable relationship links "ENABLE_LINKS": False, # ENABLE_SERIALIZER_CACHE: enable/disable caching of related serializers "ENABLE_SERIALIZER_CACHE": False, # ENABLE_SERIALIZER_OPTIMIZATIONS: enable/disable representation speedups "ENABLE_SERIALIZER_OPTIMIZATIONS": True, # DEFER_MANY_RELATIONS: automatically defer many-relations, unless # `deferred=False` is explicitly set on the field. "DEFER_MANY_RELATIONS": False, # MAX_PAGE_SIZE: global setting for max page size. # Can be overriden at the viewset level. "MAX_PAGE_SIZE": None, # PAGE_QUERY_PARAM: global setting for the pagination query parameter. # Can be overriden at the viewset level. "PAGE_QUERY_PARAM": "page", # PAGE_SIZE: global setting for page size. # Can be overriden at the viewset level. "PAGE_SIZE": None, # PAGE_SIZE_QUERY_PARAM: global setting for the page size query parameter. # Can be overriden at the viewset level. "PAGE_SIZE_QUERY_PARAM": "per_page", # ADDITIONAL_PRIMARY_RESOURCE_PREFIX: String to prefix additional # instances of the primary resource when sideloading. "ADDITIONAL_PRIMARY_RESOURCE_PREFIX": "+", # Enables host-relative links. Only compatible with resources registered # through the dynamic router. If a resource doesn't have a canonical # path registered, links will default back to being resource-relative urls "ENABLE_HOST_RELATIVE_LINKS": True, }
[docs] GRAPPELLI_ADMIN_TITLE = os.getenv("GRAPPELLI_ADMIN_TITLE", "GeoNode")
# Documents application try: # try to parse python notation, default in dockerized env
[docs] ALLOWED_DOCUMENT_TYPES = ast.literal_eval(os.getenv("ALLOWED_DOCUMENT_TYPES"))
except ValueError: # fallback to regular list of values separated with misc chars ALLOWED_DOCUMENT_TYPES = ( [ "txt", "csv", "log", "doc", "docx", "ods", "odt", "sld", "qml", "xls", "xlsx", "xml", "bm", "bmp", "dwg", "dxf", "fif", "gif", "jpg", "jpe", "jpeg", "png", "tif", "tiff", "pbm", "odp", "ppt", "pptx", "pdf", "tar", "tgz", "rar", "gz", "7z", "zip", "aif", "aifc", "aiff", "au", "mp3", "mpga", "wav", "afl", "avi", "avs", "fli", "mp2", "mp4", "mpg", "ogg", "webm", "3gp", "flv", "vdo", "glb", "pcd", "gltf", "ifc", ] if os.getenv("ALLOWED_DOCUMENT_TYPES") is None else re.split(r" *[,|:;] *", os.getenv("ALLOWED_DOCUMENT_TYPES")) )
[docs] MAX_DOCUMENT_SIZE = int(os.getenv("MAX_DOCUMENT_SIZE ", "2")) # MB
# DOCUMENT_TYPE_MAP and DOCUMENT_MIMETYPE_MAP update enumerations in # documents/enumerations.py and should only # need to be uncommented if adding other types # to settings.ALLOWED_DOCUMENT_TYPES # DOCUMENT_TYPE_MAP = {} # DOCUMENT_MIMETYPE_MAP = {}
[docs] UNOCONV_ENABLE = ast.literal_eval(os.getenv("UNOCONV_ENABLE", "False"))
if UNOCONV_ENABLE:
[docs] UNOCONV_EXECUTABLE = os.getenv("UNOCONV_EXECUTABLE", "/usr/bin/unoconv")
UNOCONV_TIMEOUT = int(os.getenv("UNOCONV_TIMEOUT", 30)) # seconds
[docs] LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { "verbose": {"format": "%(levelname)s %(asctime)s %(module)s %(process)d " "%(thread)d %(message)s"}, "simple": { "format": "%(message)s", }, "br": {"format": "%(levelname)-7s %(asctime)s %(message)s"}, }, "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, "handlers": { "console": {"level": "ERROR", "class": "logging.StreamHandler", "formatter": "simple"}, "mail_admins": { "level": "ERROR", "filters": ["require_debug_false"], "class": "django.utils.log.AdminEmailHandler", }, "br": {"level": "DEBUG", "class": "logging.StreamHandler", "formatter": "br"}, }, "loggers": { "django": { "level": "ERROR", }, "geonode": { "level": "WARN", }, "geonode.br": {"level": "INFO", "handlers": ["br"], "propagate": False}, "geoserver-restconfig.catalog": { "level": "ERROR", }, "owslib": { "level": "ERROR", }, "pycsw": { "level": "ERROR", }, "celery": { "level": "WARN", }, "mapstore2_adapter.plugins.serializers": { "level": "ERROR", }, "geonode_logstash.logstash": { "level": "ERROR", }, }, }
# # Test Settings #
[docs] on_travis = ast.literal_eval(os.environ.get("ON_TRAVIS", "False"))
[docs] core_tests = ast.literal_eval(os.environ.get("TEST_RUN_CORE", "False"))
[docs] internal_apps_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTERNAL_APPS", "False"))
[docs] integration_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION", "False"))
[docs] integration_server_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION_SERVER", "False"))
[docs] integration_upload_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION_UPLOAD", "False"))
[docs] integration_monitoring_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION_MONITORING", "False"))
[docs] integration_csw_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION_CSW", "False"))
[docs] integration_bdd_tests = ast.literal_eval(os.environ.get("TEST_RUN_INTEGRATION_BDD", "False"))
[docs] selenium_tests = ast.literal_eval(os.environ.get("TEST_RUN_SELENIUM", "False"))
# Django 1.11 ParallelTestSuite # TEST_RUNNER = 'geonode.tests.suite.runner.GeoNodeBaseSuiteDiscoverRunner'
[docs] TEST_RUNNER_KEEPDB = os.environ.get("TEST_RUNNER_KEEPDB", 0)
[docs] TEST_RUNNER_PARALLEL = os.environ.get("TEST_RUNNER_PARALLEL", 1)
# GeoNode test suite # TEST_RUNNER = 'geonode.tests.suite.runner.DjangoParallelTestSuiteRunner' # TEST_RUNNER_WORKER_MAX = 3 # TEST_RUNNER_WORKER_COUNT = 'auto' # TEST_RUNNER_NOT_THREAD_SAFE = None # TEST_RUNNER_PARENT_TIMEOUT = 10 # TEST_RUNNER_WORKER_TIMEOUT = 10
[docs] TEST = "test" in sys.argv
[docs] INTEGRATION = "geonode.tests.integration" in sys.argv
# # Customizations to built in Django settings required by GeoNode # # Django automatically includes the "templates" dir in all the INSTALLED_APPS.
[docs] CONTEXT_PROCESSORS = [ "django.template.context_processors.debug", "django.template.context_processors.i18n", "django.template.context_processors.tz", "django.template.context_processors.request", "django.template.context_processors.media", "django.template.context_processors.static", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", "django.contrib.auth.context_processors.auth", "geonode.context_processors.resource_urls", "geonode.themes.context_processors.custom_theme", ]
if "geonode.geoserver" in INSTALLED_APPS: CONTEXT_PROCESSORS += [ "geonode.geoserver.context_processors.geoserver_urls", ]
[docs] TEMPLATES = [ { "NAME": "GeoNode Project Templates", "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [os.path.join(PROJECT_ROOT, "templates")], "APP_DIRS": True, "OPTIONS": { "context_processors": CONTEXT_PROCESSORS, # Either remove APP_DIRS or remove the 'loaders' option. # 'loaders': [ # 'django.template.loaders.filesystem.Loader', # 'django.template.loaders.app_directories.Loader', # ], "debug": DEBUG, }, }, ]
[docs] OPTIONS = { "libraries": { "contact_roles": "geonode.layers.templatetags.contact_roles", }, }
[docs] MIDDLEWARE = ( "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.contrib.sites.middleware.CurrentSiteMiddleware", "dj_pagination.middleware.PaginationMiddleware", # The setting below makes it possible to serve different languages per # user depending on things like headers in HTTP requests. "django.middleware.locale.LocaleMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", # ref to: http://whitenoise.evans.io/en/stable/django.html#enable-whitenoise "oauth2_provider.middleware.OAuth2TokenMiddleware", "django_user_agents.middleware.UserAgentMiddleware", "geonode.base.middleware.MaintenanceMiddleware", "geonode.base.middleware.ReadOnlyMiddleware", # a Middleware enabling Read Only mode of Geonode )
[docs] MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
# Security stuff
[docs] SESSION_EXPIRED_CONTROL_ENABLED = ast.literal_eval(os.environ.get("SESSION_EXPIRED_CONTROL_ENABLED", "True"))
if SESSION_EXPIRED_CONTROL_ENABLED: # This middleware checks for ACCESS_TOKEN validity and if expired forces # user logout MIDDLEWARE += ("geonode.security.middleware.SessionControlMiddleware",)
[docs] CORS_ALLOW_ALL_ORIGINS = ast.literal_eval(os.environ.get("CORS_ALLOW_ALL_ORIGINS", "False"))
[docs] X_FRAME_OPTIONS = os.environ.get("X_FRAME_OPTIONS", "DENY")
[docs] SECURE_CONTENT_TYPE_NOSNIFF = ast.literal_eval(os.environ.get("SECURE_CONTENT_TYPE_NOSNIFF", "True"))
[docs] SECURE_BROWSER_XSS_FILTER = ast.literal_eval(os.environ.get("SECURE_BROWSER_XSS_FILTER", "True"))
[docs] SECURE_SSL_REDIRECT = ast.literal_eval(os.environ.get("SECURE_SSL_REDIRECT", "False"))
[docs] SECURE_HSTS_SECONDS = int(os.getenv("SECURE_HSTS_SECONDS", "3600"))
[docs] SECURE_HSTS_INCLUDE_SUBDOMAINS = ast.literal_eval(os.environ.get("SECURE_HSTS_INCLUDE_SUBDOMAINS", "True"))
# Replacement of the default authentication backend in order to support # permissions per object. AUTHENTICATION_BACKENDS = ( # 'oauth2_provider.backends.OAuth2Backend', "django.contrib.auth.backends.ModelBackend", "guardian.backends.ObjectPermissionBackend", "allauth.account.auth_backends.AuthenticationBackend", ) if "announcements" in INSTALLED_APPS: AUTHENTICATION_BACKENDS += ("announcements.auth_backends.AnnouncementPermissionsBackend",)
[docs] OAUTH2_PROVIDER = { "SCOPES": { "openid": "Default to OpenID", "read": "Read scope", "write": "Write scope", "groups": "Access to your groups", }, "CLIENT_ID_GENERATOR_CLASS": "oauth2_provider.generators.ClientIdGenerator", "OAUTH2_SERVER_CLASS": "geonode.security.oauth2_servers.OIDCServer", # 'OAUTH2_VALIDATOR_CLASS': 'geonode.security.oauth2_validators.OIDCValidator', # OpenID Connect "OIDC_ENABLED": True, "OIDC_ISS_ENDPOINT": SITEURL, "OIDC_USERINFO_ENDPOINT": f"{SITEURL}api/o/v4/tokeninfo/", "OIDC_RSA_PRIVATE_KEY": """-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCIThjbTwpYu4Lwqp8oA7PqD6Ij/GwpLFJuPbWVaeCDaX6T7mh8 mJMIEgl/VIZasLH8SwU5mZ4sPeiqk7NgJq1XDo97q5mlFoNVHMCH38KQzSIBWtbq WnEEnQdiqBbCmmIebLd4OcfpbIVUI89cnCq7U0M1ie0KOopWSHWOP6/35QIDAQAB AoGBAIdwmtBotM5A3LaJxAY9z6uXhzSc4Vj0OqBiXymtgDL0Q5t4/Yg5D3ioe5lz guFgzCr23KVEmOA7UBMXGtlC9V+iizVSbF4g2GqPLBKk+IYcAhfbSCg5rbbtQ5m2 PZxKZlJOQnjFLeh4sxitd84GfX16RfAhsvIiaN4d4CG+RAlhAkEA1Vitep0aHKmA KRIGvZrgfH7uEZh2rRsCoo9lTxCT8ocCU964iEUxNH050yKdqYzVnNyFysY7wFgL gsVzPROE6QJBAKOOWj9mN7uxhjRv2L4iYJ/rZaloVA49KBZEhvI+PgC5kAIrNVaS n1kbJtFg54IS8HsYIP4YxONLqmDuhZL2rZ0CQQDId9wCo85eclMPxHV7AiXANdDj zbxt6jxunYlXYr9yG7RvNI921HVo2eZU42j8YW5zR6+cGusYUGL4jSo8kLPJAkAG SLPi97Rwe7OiVCHJvFxmCI9RYPbJzUO7B0sAB7AuKvMDglF8UAnbTJXDOavrbXrb 3+N0n9MAwKl9K+zp5pxpAkBSEUlYA0kDUqRgfuAXrrO/JYErGzE0UpaHxq5gCvTf g+gp5fQ4nmDrSNHjakzQCX2mKMsx/GLWZzoIDd7ECV9f -----END RSA PRIVATE KEY-----""", }
[docs] OAUTH2_PROVIDER_APPLICATION_MODEL = "oauth2_provider.Application"
[docs] OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = "oauth2_provider.AccessToken"
[docs] OAUTH2_PROVIDER_ID_TOKEN_MODEL = "oauth2_provider.IDToken"
[docs] OAUTH2_PROVIDER_GRANT_MODEL = "oauth2_provider.Grant"
[docs] OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "oauth2_provider.RefreshToken"
[docs] OAUTH2_DEFAULT_BACKEND_CLIENT_NAME = os.environ.get("OAUTH2_DEFAULT_BACKEND_CLIENT_NAME", "GeoServer")
# In order to protect oauth2 REST endpoints, used by GeoServer to fetch user roles and # infos, you should set this key and configure the "geonode REST role service" # accordingly. Keep it secret! # WARNING: If not set, the endpoint can be accessed by users without authorization.
[docs] OAUTH2_API_KEY = os.environ.get("OAUTH2_API_KEY", None)
# 1 day expiration time by default
[docs] ACCESS_TOKEN_EXPIRE_SECONDS = int(os.getenv("ACCESS_TOKEN_EXPIRE_SECONDS", "86400"))
# Require users to authenticate before using Geonode
[docs] LOCKDOWN_GEONODE = ast.literal_eval(os.getenv("LOCKDOWN_GEONODE", "False"))
# Add additional paths (as regular expressions) that don't require # authentication. # - authorized exempt urls needed for oauth when GeoNode is set to lockdown
[docs] AUTH_EXEMPT_URLS = ( f"{FORCE_SCRIPT_NAME}/o/*", f"{FORCE_SCRIPT_NAME}/gs/*", f"{FORCE_SCRIPT_NAME}/account/*", f"{FORCE_SCRIPT_NAME}/static/*", f"{FORCE_SCRIPT_NAME}/api/o/*", f"{FORCE_SCRIPT_NAME}/api/roles", f"{FORCE_SCRIPT_NAME}/api/adminRole", f"{FORCE_SCRIPT_NAME}/api/users", f"{FORCE_SCRIPT_NAME}/api/datasets", f"{FORCE_SCRIPT_NAME}/monitoring", r"^/i18n/setlang/?$", )
[docs] ANONYMOUS_USER_ID = os.getenv("ANONYMOUS_USER_ID", "-1")
[docs] GUARDIAN_GET_INIT_ANONYMOUS_USER = os.getenv( "GUARDIAN_GET_INIT_ANONYMOUS_USER", "geonode.people.models.get_anonymous_user_instance" )
# Whether the uplaoded resources should be public and downloadable by default # or not
[docs] DEFAULT_ANONYMOUS_VIEW_PERMISSION = ast.literal_eval(os.getenv("DEFAULT_ANONYMOUS_VIEW_PERMISSION", "True"))
[docs] DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION = ast.literal_eval(os.getenv("DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION", "True"))
# # Settings for default search size #
[docs] DEFAULT_SEARCH_SIZE = int(os.getenv("DEFAULT_SEARCH_SIZE", "10"))
# # Settings for third party apps # # Pinax Ratings
[docs] PINAX_RATINGS_CATEGORY_CHOICES = { "maps.Map": {"map": "How good is this map?"}, "layers.Dataset": {"dataset": "How good is this dataset?"}, "documents.Document": {"document": "How good is this document?"}, "geoapps.GeoApp": {"geoapp": "How good is this geoapp?"}, }
# Activity Stream
[docs] ACTSTREAM_SETTINGS = { "FETCH_RELATIONS": True, "USE_PREFETCH": False, "USE_JSONFIELD": True, "GFK_FETCH_DEPTH": 1, }
# Email for users to contact admins.
[docs] THEME_ACCOUNT_CONTACT_EMAIL = os.getenv("THEME_ACCOUNT_CONTACT_EMAIL", "admin@example.com")
# # GeoNode specific settings # # per-deployment settings should go here # Login and logout urls override
[docs] LOGIN_URL = os.getenv("LOGIN_URL", f"{SITEURL}account/login/")
[docs] LOGOUT_URL = os.getenv("LOGOUT_URL", f"{SITEURL}account/logout/")
[docs] ACCOUNT_LOGIN_REDIRECT_URL = os.getenv("LOGIN_REDIRECT_URL", SITEURL)
[docs] ACCOUNT_LOGOUT_REDIRECT_URL = os.getenv("LOGOUT_REDIRECT_URL", SITEURL)
# Backend
[docs] DEFAULT_WORKSPACE = os.getenv("DEFAULT_WORKSPACE", "geonode")
[docs] CASCADE_WORKSPACE = os.getenv("CASCADE_WORKSPACE", "geonode")
[docs] OGP_URL = os.getenv("OGP_URL", "http://geodata.tufts.edu/solr/select")
# Topic Categories list should not be modified (they are ISO). In case you # absolutely need it set to True this variable
[docs] MODIFY_TOPICCATEGORY = ast.literal_eval(os.getenv("MODIFY_TOPICCATEGORY", "True"))
# If this option is enabled, Topic Categories will become strictly Mandatory on # Metadata Wizard
[docs] TOPICCATEGORY_MANDATORY = ast.literal_eval(os.environ.get("TOPICCATEGORY_MANDATORY", "False"))
[docs] MISSING_THUMBNAIL = os.getenv("MISSING_THUMBNAIL", "geonode/img/missing_thumb.png")
GEOSERVER_LOCATION = os.getenv("GEOSERVER_LOCATION", "http://localhost:8080/geoserver/") # add trailing slash to geoserver location url. if not GEOSERVER_LOCATION.endswith("/"):
[docs] GEOSERVER_LOCATION = f"{GEOSERVER_LOCATION}/"
[docs] GEOSERVER_PUBLIC_SCHEMA = os.getenv("GEOSERVER_PUBLIC_SCHEMA", SITE_HOST_SCHEMA)
[docs] GEOSERVER_PUBLIC_HOST = os.getenv("GEOSERVER_PUBLIC_HOST", SITE_HOST_NAME)
[docs] GEOSERVER_PUBLIC_PORT = os.getenv("GEOSERVER_PUBLIC_PORT", 8080)
if GEOSERVER_PUBLIC_PORT:
[docs] _default_public_location = f"{GEOSERVER_PUBLIC_SCHEMA}://{GEOSERVER_PUBLIC_HOST}:{GEOSERVER_PUBLIC_PORT}/geoserver/"
else: _default_public_location = f"{GEOSERVER_PUBLIC_SCHEMA}://{GEOSERVER_PUBLIC_HOST}/geoserver/"
[docs] GEOSERVER_PUBLIC_LOCATION = os.getenv("GEOSERVER_PUBLIC_LOCATION", _default_public_location)
[docs] GEOSERVER_WEB_UI_LOCATION = os.getenv("GEOSERVER_WEB_UI_LOCATION", GEOSERVER_PUBLIC_LOCATION)
[docs] GEOSERVER_ADMIN_USER = os.getenv("GEOSERVER_ADMIN_USER", "admin")
[docs] GEOSERVER_ADMIN_PASSWORD = os.getenv("GEOSERVER_ADMIN_PASSWORD", "geoserver")
# This is the password from Geoserver factory data-dir. It's only used at install time to perform the very first configurfation of GEOSERVER_ADMIN_PASSWORD
[docs] GEOSERVER_FACTORY_PASSWORD = os.getenv("GEOSERVER_FACTORY_PASSWORD", "geoserver")
[docs] ACL_SECURITY_ENABLED = ( False if TEST and not INTEGRATION else ast.literal_eval(os.getenv("ACL_SECURITY_ENABLED", "True")) )
# OGC (WMS/WFS/WCS) Server Settings # OGC (WMS/WFS/WCS) Server Settings
[docs] OGC_SERVER = { "default": { "BACKEND": os.getenv("BACKEND", "geonode.geoserver"), "LOCATION": GEOSERVER_LOCATION, "WEB_UI_LOCATION": GEOSERVER_WEB_UI_LOCATION, "LOGIN_ENDPOINT": "j_spring_oauth2_geonode_login", "LOGOUT_ENDPOINT": "j_spring_oauth2_geonode_logout", # PUBLIC_LOCATION needs to be kept like this because in dev mode # the proxy won't work and the integration tests will fail # the entire block has to be overridden in the local_settings "PUBLIC_LOCATION": GEOSERVER_PUBLIC_LOCATION, "USER": GEOSERVER_ADMIN_USER, "PASSWORD": GEOSERVER_ADMIN_PASSWORD, "MAPFISH_PRINT_ENABLED": ast.literal_eval(os.getenv("MAPFISH_PRINT_ENABLED", "True")), "PRINT_NG_ENABLED": ast.literal_eval(os.getenv("PRINT_NG_ENABLED", "True")), "GEONODE_SECURITY_ENABLED": ast.literal_eval(os.getenv("GEONODE_SECURITY_ENABLED", "True")), "ACL_SECURITY_ENABLED": ACL_SECURITY_ENABLED, "ACL_TIMEOUT": int(os.getenv("ACL_TIMEOUT", os.getenv("OGC_REQUEST_TIMEOUT", "60"))), "WMST_ENABLED": ast.literal_eval(os.getenv("WMST_ENABLED", "False")), "BACKEND_WRITE_ENABLED": ast.literal_eval(os.getenv("BACKEND_WRITE_ENABLED", "True")), "WPS_ENABLED": ast.literal_eval(os.getenv("WPS_ENABLED", "False")), "LOG_FILE": f"{os.path.abspath(os.path.join(PROJECT_ROOT, os.pardir))}/geoserver/data/logs/geoserver.log", # Set to name of database in DATABASES dictionary to enable # 'datastore', "DATASTORE": os.getenv("DEFAULT_BACKEND_DATASTORE", ""), "TIMEOUT": int(os.getenv("OGC_REQUEST_TIMEOUT", "60")), "MAX_RETRIES": int(os.getenv("OGC_REQUEST_MAX_RETRIES", "3")), "BACKOFF_FACTOR": float(os.getenv("OGC_REQUEST_BACKOFF_FACTOR", "0.3")), "POOL_MAXSIZE": int(os.getenv("OGC_REQUEST_POOL_MAXSIZE", "10")), "POOL_CONNECTIONS": int(os.getenv("OGC_REQUEST_POOL_CONNECTIONS", "10")), } }
[docs] USE_GEOSERVER = "geonode.geoserver" in INSTALLED_APPS and OGC_SERVER["default"]["BACKEND"] == "geonode.geoserver"
# Uploader Settings
[docs] DATA_UPLOAD_MAX_NUMBER_FIELDS = 100000
""" DEFAULT_BACKEND_UPLOADER = {'geonode.importer'} """
[docs] UPLOADER = { "BACKEND": os.getenv("DEFAULT_BACKEND_UPLOADER", "geonode.importer"), "OPTIONS": { "TIME_ENABLED": ast.literal_eval(os.getenv("TIME_ENABLED", "False")), "MOSAIC_ENABLED": ast.literal_eval(os.getenv("MOSAIC_ENABLED", "False")), }, "SUPPORTED_CRS": ["EPSG:4326", "EPSG:3785", "EPSG:3857", "EPSG:32647", "EPSG:32736"], "SUPPORTED_EXT": [".shp", ".csv", ".kml", ".kmz", ".json", ".geojson", ".tif", ".tiff", ".geotiff", ".gml", ".xml"], }
[docs] EPSG_CODE_MATCHES = { "EPSG:4326": "(4326) WGS 84", "EPSG:900913": "(900913) Google Maps Global Mercator", "EPSG:3857": "(3857) WGS 84 / Pseudo-Mercator", "EPSG:3785": "(3785 DEPRECATED) Popular Visualisation CRS / Mercator", "EPSG:32647": "(32647) WGS 84 / UTM zone 47N", "EPSG:32736": "(32736) WGS 84 / UTM zone 36S", }
# CSW settings
[docs] CATALOGUE = { "default": { # The underlying CSW implementation # default is pycsw in local mode (tied directly to GeoNode Django DB) "ENGINE": os.getenv("CATALOGUE_ENGINE", "geonode.catalogue.backends.pycsw_local"), # pycsw in non-local mode # 'ENGINE': 'geonode.catalogue.backends.pycsw_http', # deegree and others # 'ENGINE': 'geonode.catalogue.backends.generic', # The FULLY QUALIFIED base url to the CSW instance for this GeoNode "URL": os.getenv("CATALOGUE_URL", urljoin(SITEURL, "/catalogue/csw")), # 'URL': 'http://localhost:8080/geonetwork/srv/en/csw', # 'URL': 'http://localhost:8080/deegree-csw-demo-3.0.4/services', # 'ALTERNATES_ONLY': True, } }
# pycsw settings
[docs] PYCSW = { # pycsw configuration "CONFIGURATION": { # uncomment / adjust to override server config system defaults # 'server': { # 'maxrecords': '10', # 'pretty_print': 'true', # 'federatedcatalogues': 'http://catalog.data.gov/csw' # }, "server": { "home": ".", "url": CATALOGUE["default"]["URL"], "encoding": "UTF-8", "language": LANGUAGE_CODE if LANGUAGE_CODE in ("en", "fr", "el") else "en", "maxrecords": "20", "pretty_print": "true", # 'domainquerytype': 'range', "domaincounts": "true", "profiles": "apiso,ebrim", }, "manager": { # authentication/authorization is handled by Django "transactions": "false", "allowed_ips": "*", # 'csw_harvest_pagesize': '10', }, "metadata:main": { "identification_title": "GeoNode Catalogue", "identification_abstract": "GeoNode is an open source platform" " that facilitates the creation, sharing, and collaborative use" " of geospatial data", "identification_keywords": "sdi, catalogue, discovery, metadata," " GeoNode", "identification_keywords_type": "theme", "identification_fees": "None", "identification_accessconstraints": "None", "provider_name": "Organization Name", "provider_url": SITEURL, "contact_name": "Lastname, Firstname", "contact_position": "Position Title", "contact_address": "Mailing Address", "contact_city": "City", "contact_stateorprovince": "Administrative Area", "contact_postalcode": "Zip or Postal Code", "contact_country": "Country", "contact_phone": "+xx-xxx-xxx-xxxx", "contact_fax": "+xx-xxx-xxx-xxxx", "contact_email": "Email Address", "contact_url": "Contact URL", "contact_hours": "Hours of Service", "contact_instructions": "During hours of service. Off on " "weekends.", "contact_role": "pointOfContact", }, "metadata:inspire": { "enabled": "true", "languages_supported": "eng,gre", "default_language": "eng", "date": "YYYY-MM-DD", "gemet_keywords": "Utility and governmental services", "conformity_service": "notEvaluated", "contact_name": "Organization Name", "contact_email": "Email Address", "temp_extent": "YYYY-MM-DD/YYYY-MM-DD", }, } }
[docs] _DATETIME_INPUT_FORMATS = ["%Y-%m-%d %H:%M:%S.%f %Z", "%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%M:%S%Z"]
[docs] DATETIME_INPUT_FORMATS = DATETIME_INPUT_FORMATS + _DATETIME_INPUT_FORMATS
[docs] DISPLAY_SOCIAL = ast.literal_eval(os.getenv("DISPLAY_SOCIAL", "True"))
[docs] DISPLAY_RATINGS = ast.literal_eval(os.getenv("DISPLAY_RATINGS", "True"))
[docs] SOCIAL_ORIGINS = [ {"label": "Email", "url": "mailto:?subject={name}&body={url}", "css_class": "email"}, {"label": "Facebook", "url": "http://www.facebook.com/sharer.php?u={url}", "css_class": "fb"}, {"label": "Twitter", "url": "https://twitter.com/share?url={url}&hashtags={hashtags}", "css_class": "tw"}, ]
# CKAN Query String Parameters names pulled from # http://tinyurl.com/og2jofn
[docs] CKAN_ORIGINS = [ { "label": "Humanitarian Data Exchange (HDX)", "url": "https://data.hdx.rwlabs.org/dataset/new?title={name}&" "dataset_date={date}&notes={abstract}&caveats={caveats}", "css_class": "hdx", } ]
# SOCIAL_ORIGINS.extend(CKAN_ORIGINS) # Setting TWITTER_CARD to True will enable Twitter Cards # https://dev.twitter.com/cards/getting-started # Be sure to replace @GeoNode with your organization or site's twitter handle.
[docs] TWITTER_CARD = ast.literal_eval(os.getenv("TWITTER_CARD", "True"))
[docs] TWITTER_SITE = "@GeoNode"
[docs] TWITTER_HASHTAGS = ["geonode"]
[docs] OPENGRAPH_ENABLED = ast.literal_eval(os.getenv("OPENGRAPH_ENABLED", "True"))
# Enable Licenses User Interface # Regardless of selection, license field stil exists as a field in the # Resourcebase model. # Detail Display: above, below, never # Metadata Options: verbose, light, never
[docs] LICENSES = { "ENABLED": True, "DETAIL": "above", "METADATA": "verbose", }
[docs] SRID = { "DETAIL": "never", }
[docs] SESSION_SERIALIZER = "django.contrib.sessions.serializers.PickleSerializer"
try: # try to parse python notation, default in dockerized env
[docs] ALLOWED_HOSTS = ast.literal_eval(os.getenv("ALLOWED_HOSTS"))
except ValueError: # fallback to regular list of values separated with misc chars ALLOWED_HOSTS = ( [HOSTNAME, "localhost", "django", "geonode"] if os.getenv("ALLOWED_HOSTS") is None else re.split(r" *[,|:;] *", os.getenv("ALLOWED_HOSTS")) ) # AUTH_IP_WHITELIST property limits access to users/groups REST endpoints # to only whitelisted IP addresses. # # Empty list means 'allow all' # # If you need to limit 'api' REST calls to only some specific IPs # fill the list like below: # # AUTH_IP_WHITELIST = ['192.168.1.158', '192.168.1.159']
[docs] AUTH_IP_WHITELIST = ( [HOSTNAME, "localhost", "django", "geonode"] if os.getenv("AUTH_IP_WHITELIST") is None else re.split(r" *[,|:;] *", os.getenv("AUTH_IP_WHITELIST")) )
# ADMIN_IP_WHITELIST property limits access as admin # to only whitelisted IP addresses. # # Empty list means 'allow all' # # If you need to limit admin access to some specific IPs # fill the list like below: # # ADMIN_IP_WHITELIST = ['192.168.1.158', '192.168.1.159']
[docs] ADMIN_IP_WHITELIST = ( [] if os.getenv("ADMIN_IP_WHITELIST") is None else re.split(r" *[,|:;] *", os.getenv("ADMIN_IP_WHITELIST")) )
if len(ADMIN_IP_WHITELIST) > 0:
[docs] AUTHENTICATION_BACKENDS = ("geonode.security.backends.AdminRestrictedAccessBackend",) + AUTHENTICATION_BACKENDS
MIDDLEWARE += ("geonode.security.middleware.AdminAllowedMiddleware",) # A tuple of hosts the proxy can send requests to. try: # try to parse python notation, default in dockerized env
[docs] PROXY_ALLOWED_HOSTS = ast.literal_eval(os.getenv("PROXY_ALLOWED_HOSTS"))
except ValueError: # fallback to regular list of values separated with misc chars PROXY_ALLOWED_HOSTS = ( [ HOSTNAME, "localhost", "django", "geonode", "spatialreference.org", "nominatim.openstreetmap.org", "dev.openlayers.org", ] if os.getenv("PROXY_ALLOWED_HOSTS") is None else re.split(r" *[,|:;] *", os.getenv("PROXY_ALLOWED_HOSTS")) ) # The proxy to use when making cross origin requests.
[docs] PROXY_URL = os.environ.get("PROXY_URL", "/proxy/?url=")
# Haystack Search Backend Configuration. To enable, # first install the following: # - pip install django-haystack # - pip install pyelasticsearch # Set HAYSTACK_SEARCH to True # Run "python manage.py rebuild_index" # Avoid permissions prefiltering
[docs] SKIP_PERMS_FILTER = ast.literal_eval(os.getenv("SKIP_PERMS_FILTER", "False"))
# Update facet counts from Haystack
[docs] HAYSTACK_FACET_COUNTS = ast.literal_eval(os.getenv("HAYSTACK_FACET_COUNTS", "True"))
if HAYSTACK_SEARCH: if "haystack" not in INSTALLED_APPS: INSTALLED_APPS += ("haystack",)
[docs] HAYSTACK_CONNECTIONS = { "default": { "ENGINE": "haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine", "URL": os.getenv("HAYSTACK_ENGINE_URL", "http://127.0.0.1:9200/"), "INDEX_NAME": os.getenv("HAYSTACK_ENGINE_INDEX_NAME", "haystack"), }, }
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor" HAYSTACK_SEARCH_RESULTS_PER_PAGE = int(os.getenv("HAYSTACK_SEARCH_RESULTS_PER_PAGE", "200")) # Available download formats
[docs] DOWNLOAD_FORMATS_METADATA = [ "Atom", "DIF", "Dublin Core", "ebRIM", "FGDC", "ISO", ]
[docs] DOWNLOAD_FORMATS_VECTOR = [ "JPEG", "PDF", "PNG", "Zipped Shapefile", "GML 2.0", "GML 3.1.1", "CSV", "Excel", "GeoJSON", "KML", "View in Google Earth", "Tiles", ]
[docs] DOWNLOAD_FORMATS_RASTER = [ "JPEG", "PDF", "PNG", "ArcGrid", "GeoTIFF", "Gtopo30", "ImageMosaic", "KML", "View in Google Earth", "Tiles", "GML", "GZIP", "Zipped All Files", ]
[docs] ACCOUNT_NOTIFY_ON_PASSWORD_CHANGE = ast.literal_eval(os.getenv("ACCOUNT_NOTIFY_ON_PASSWORD_CHANGE", "False"))
[docs] TASTYPIE_DEFAULT_FORMATS = ["json"]
# gravatar settings
[docs] AUTO_GENERATE_AVATAR_SIZES = (20, 30, 32, 40, 50, 65, 70, 80, 100, 140, 200, 240)
[docs] AVATAR_GRAVATAR_SSL = ast.literal_eval(os.getenv("AVATAR_GRAVATAR_SSL", "False"))
[docs] AVATAR_DEFAULT_URL = os.getenv("AVATAR_DEFAULT_URL", "/geonode/img/avatar.png")
try: # try to parse python notation, default in dockerized env
[docs] AVATAR_PROVIDERS = ast.literal_eval(os.getenv("AVATAR_PROVIDERS"))
except ValueError: # fallback to regular list of values separated with misc chars AVATAR_PROVIDERS = ( ( "avatar.providers.PrimaryAvatarProvider", "avatar.providers.GravatarAvatarProvider", "avatar.providers.DefaultAvatarProvider", ) if os.getenv("AVATAR_PROVIDERS") is None else re.split(r" *[,|:;] *", os.getenv("AVATAR_PROVIDERS")) ) # Number of results per page listed in the GeoNode search pages
[docs] CLIENT_RESULTS_LIMIT = int(os.getenv("CLIENT_RESULTS_LIMIT", "5"))
# LOCKDOWN API endpoints to prevent unauthenticated access. # If set to True, search won't deliver results and filtering ResourceBase-objects is not possible for anonymous users
[docs] API_LOCKDOWN = ast.literal_eval(os.getenv("API_LOCKDOWN", "False"))
# Number of items returned by the apis 0 equals no limit
[docs] API_LIMIT_PER_PAGE = int(os.getenv("API_LIMIT_PER_PAGE", "200"))
[docs] API_INCLUDE_REGIONS_COUNT = ast.literal_eval(os.getenv("API_INCLUDE_REGIONS_COUNT", "False"))
# Settings for EXIF plugin
[docs] EXIF_ENABLED = ast.literal_eval(os.getenv("EXIF_ENABLED", "True"))
if EXIF_ENABLED: if "geonode.documents.exif" not in INSTALLED_APPS: INSTALLED_APPS += ("geonode.documents.exif",) # Settings for CREATE_LAYER plugin
[docs] CREATE_LAYER = ast.literal_eval(os.getenv("CREATE_LAYER", "False"))
if CREATE_LAYER: if "geonode.geoserver.createlayer" not in INSTALLED_APPS: INSTALLED_APPS += ("geonode.geoserver.createlayer",) # Settings for RECAPTCHA plugin
[docs] RECAPTCHA_ENABLED = ast.literal_eval(os.environ.get("RECAPTCHA_ENABLED", "False"))
if RECAPTCHA_ENABLED: if "captcha" not in INSTALLED_APPS: INSTALLED_APPS += ("captcha",)
[docs] ACCOUNT_SIGNUP_FORM_CLASS = os.getenv( "ACCOUNT_SIGNUP_FORM_CLASS", "geonode.people.forms.AllauthReCaptchaSignupForm" )
""" In order to generate reCaptcha keys, please see: - https://pypi.org/project/django-recaptcha/#installation - https://pypi.org/project/django-recaptcha/#local-development-and-functional-testing """ RECAPTCHA_PUBLIC_KEY = os.getenv("RECAPTCHA_PUBLIC_KEY", "geonode_RECAPTCHA_PUBLIC_KEY") RECAPTCHA_PRIVATE_KEY = os.getenv("RECAPTCHA_PRIVATE_KEY", "geonode_RECAPTCHA_PRIVATE_KEY")
[docs] GEONODE_CATALOGUE_METADATA_XSL = ast.literal_eval(os.getenv("GEONODE_CATALOGUE_METADATA_XSL", "True"))
# -- START Client Hooksets Setup # GeoNode javascript client configuration # default map projection # Note: If set to EPSG:4326, then only EPSG:4326 basemaps will work.
[docs] DEFAULT_MAP_CRS = os.environ.get("DEFAULT_MAP_CRS", "EPSG:3857")
[docs] DEFAULT_LAYER_FORMAT = os.environ.get("DEFAULT_LAYER_FORMAT", "image/png")
[docs] DEFAULT_TILE_SIZE = os.environ.get("DEFAULT_TILE_SIZE", 512)
# Where should newly created maps be focused?
[docs] DEFAULT_MAP_CENTER = ( ast.literal_eval(os.environ.get("DEFAULT_MAP_CENTER_X", "0")), ast.literal_eval(os.environ.get("DEFAULT_MAP_CENTER_Y", "0")), )
# How tightly zoomed should newly created maps be? # 0 = entire world; # maximum zoom is between 12 and 15 (for Google Maps, coverage varies by area)
[docs] DEFAULT_MAP_ZOOM = int(os.environ.get("DEFAULT_MAP_ZOOM", 0))
[docs] MAPBOX_ACCESS_TOKEN = os.environ.get("MAPBOX_ACCESS_TOKEN", None)
[docs] BING_API_KEY = os.environ.get("BING_API_KEY", None)
[docs] GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY", None)
[docs] GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY = os.getenv("GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY", "mapstore")
[docs] MAP_BASELAYERS = [{}]
""" MapStore2 REACT based Client parameters """ if GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY == "mapstore":
[docs] GEONODE_CLIENT_HOOKSET = os.getenv("GEONODE_CLIENT_HOOKSET", "geonode_mapstore_client.hooksets.MapStoreHookSet")
if "geonode_mapstore_client" not in INSTALLED_APPS: INSTALLED_APPS += ("geonode_mapstore_client",) def get_geonode_catalogue_service(): if PYCSW: pycsw_config = PYCSW["CONFIGURATION"] if pycsw_config: pycsw_catalogue = { f"{pycsw_config['metadata:main']['identification_title']}": { "url": CATALOGUE["default"]["URL"], "type": "csw", "title": pycsw_config["metadata:main"]["identification_title"], "autoload": True, "layerOptions": {"tileSize": DEFAULT_TILE_SIZE}, } } return pycsw_catalogue return None GEONODE_CATALOGUE_SERVICE = get_geonode_catalogue_service() MAPSTORE_CATALOGUE_SERVICES = {} MAPSTORE_CATALOGUE_SELECTED_SERVICE = "" if GEONODE_CATALOGUE_SERVICE: MAPSTORE_CATALOGUE_SERVICES[list(list(GEONODE_CATALOGUE_SERVICE.keys()))[0]] = GEONODE_CATALOGUE_SERVICE[ list(list(GEONODE_CATALOGUE_SERVICE.keys()))[0] ] # noqa MAPSTORE_CATALOGUE_SELECTED_SERVICE = list(list(GEONODE_CATALOGUE_SERVICE.keys()))[0] DEFAULT_MS2_BACKGROUNDS = [ { "type": "osm", "title": "Open Street Map", "name": "mapnik", "source": "osm", "group": "background", "visibility": True, }, { "type": "tileprovider", "title": "OpenTopoMap", "provider": "OpenTopoMap", "name": "OpenTopoMap", "source": "OpenTopoMap", "group": "background", "visibility": False, }, { "type": "wms", "title": "Sentinel-2 cloudless - https://s2maps.eu", "format": "image/jpeg", "id": "s2cloudless", "name": "s2cloudless:s2cloudless", "url": "https://maps.geosolutionsgroup.com/geoserver/wms", "group": "background", "thumbURL": f"{SITEURL}static/mapstorestyle/img/s2cloudless-s2cloudless.png", "visibility": False, }, { "source": "ol", "group": "background", "id": "none", "name": "empty", "title": "Empty Background", "type": "empty", "visibility": False, "args": ["Empty Background", {"visibility": False}], }, ] if MAPBOX_ACCESS_TOKEN: BASEMAP = { "type": "tileprovider", "title": "MapBox streets-v11", "provider": "MapBoxStyle", "name": "MapBox streets-v11", "accessToken": f"{MAPBOX_ACCESS_TOKEN}", "source": "streets-v11", "thumbURL": f"https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/6/33/23?access_token={MAPBOX_ACCESS_TOKEN}", # noqa "group": "background", "visibility": True, } DEFAULT_MS2_BACKGROUNDS = [ BASEMAP, ] + DEFAULT_MS2_BACKGROUNDS if BING_API_KEY: BASEMAP = { "type": "bing", "title": "Bing Aerial", "name": "AerialWithLabels", "source": "bing", "group": "background", "apiKey": "{{apiKey}}", "visibility": False, } DEFAULT_MS2_BACKGROUNDS = [ BASEMAP, ] + DEFAULT_MS2_BACKGROUNDS MAPSTORE_BASELAYERS = DEFAULT_MS2_BACKGROUNDS # MAPSTORE_BASELAYERS_SOURCES allow to configure tilematrix sets for wmts layers MAPSTORE_BASELAYERS_SOURCES = os.environ.get("MAPSTORE_BASELAYERS_SOURCES", {}) MAPSTORE_DEFAULT_LANGUAGES = ( ("de-de", "Deutsch"), ("en-us", "English"), ("es-es", "Español"), ("fr-fr", "Français"), ("it-it", "Italiano"), ) if os.getenv("LANGUAGES"): # Map given languages to mapstore supported languages. LANGUAGES = tuple( (k, v) for k, v in dict(MAPSTORE_DEFAULT_LANGUAGES).items() if any(m in k for m in dict(LANGUAGES).keys()) ) else: LANGUAGES = MAPSTORE_DEFAULT_LANGUAGES # The default mapstore client compiles the translations json files in the /static/mapstore directory # gn-translations are the custom translations for the client and ms-translations are the translations from the core framework MAPSTORE_TRANSLATIONS_PATH = os.environ.get( "MAPSTORE_TRANSLATIONS_PATH", ["/static/mapstore/ms-translations", "/static/mapstore/gn-translations"] ) # list of projections available in the mapstore client # properties: # - code: epsg code of the projection # - def: definition of projection in Proj4js string # - extent: max extent in projected coordinates [minx, miny, maxx, maxy] # - worldExtent: max extent in WGS84 coordinates [minx, miny, maxx, maxy] # example: # MAPSTORE_PROJECTION_DEFS = [ # { # "code": "EPSG:3395", # "def": "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs", # "extent": [-20026376.39, -15496570.74, 20026376.39, 18764656.23 ], # "worldExtent": [ -180.0, -80.0, 180.0, 84.0 ] # } # ] MAPSTORE_PROJECTION_DEFS = [] # list of rules to change the plugins configuration # allowed operation: add, remove and replace # example: remove Measure plugin from map_viewer page # MAPSTORE_PLUGINS_CONFIG_PATCH_RULES = [ # { # "op": "remove", # "jsonpath": "$.map_viewer..[?(@.name == 'Measure')]" # } # ] # example: add SearchServicesConfig plugin to map_viewer page # MAPSTORE_PLUGINS_CONFIG_PATCH_RULES = [ # { # "op": "add", # "jsonpath": "/map_viewer/-", # "value": { # "name": "SearchServicesConfig" # } # } # ] # example: replace default configuration of Print plugin in map_viewer page # MAPSTORE_PLUGINS_CONFIG_PATCH_RULES = [ # { # "op": "replace", # "jsonpath": "$.map_viewer..[?(@.name == 'Print')].cfg", # "value": { # "useFixedScales": False # } # } # ] MAPSTORE_PLUGINS_CONFIG_PATCH_RULES = [] # Extensions path to use in importing custom extensions into geonode MAPSTORE_EXTENSIONS_FOLDER_PATH = "/static/mapstore/extensions/" # Supported Dataset file types for uploading Datasets. This setting is being from from the client # -- END Client Hooksets Setup
[docs] SERVICE_UPDATE_INTERVAL = 0
[docs] SEARCH_FILTERS = { "TEXT_ENABLED": True, "TYPE_ENABLED": True, "CATEGORIES_ENABLED": True, "OWNERS_ENABLED": True, "KEYWORDS_ENABLED": True, "H_KEYWORDS_ENABLED": True, "T_KEYWORDS_ENABLED": True, "DATE_ENABLED": True, "REGION_ENABLED": True, "EXTENT_ENABLED": True, "GROUPS_ENABLED": True, "GROUP_CATEGORIES_ENABLED": True, }
# HTML WYSIWYG Editor (TINYMCE) Menu Bar Settings
[docs] TINYMCE_DEFAULT_CONFIG = { "theme": "silver", "height": 200, "plugins": "preview paste searchreplace autolink directionality code visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking insertdatetime advlist lists wordcount imagetools textpattern noneditable help charmap quickbars", # noqa "imagetools_cors_hosts": ["picsum.photos"], "menubar": False, "statusbar": False, "toolbar": "bold italic underline | formatselect removeformat | outdent indent | numlist bullist | insertfile image media link codesample | preview", # noqa "toolbar_sticky": "true", "autosave_ask_before_unload": "true", "autosave_interval": "30s", "autosave_prefix": "{path}{query}-{id}-", "autosave_restore_when_empty": "false", "autosave_retention": "2m", "image_advtab": "true", "content_css": "//www.tiny.cloud/css/codepen.min.css", "importcss_append": "true", "image_caption": "true", "quickbars_selection_toolbar": "bold italic | quicklink h2 h3 blockquote quickimage quicktable", "noneditable_noneditable_class": "mceNonEditable", "toolbar_mode": "sliding", "contextmenu": "link image imagetools table", "templates": [ { "title": "New Table", "description": "creates a new table", "content": '<div class="mceTmpl"><table width="98%%" border="0" cellspacing="0" cellpadding="0"><tr><th scope="col"> </th><th scope="col"> </th></tr><tr><td> </td><td> </td></tr></table></div>', # noqa }, {"title": "Starting my story", "description": "A cure for writers block", "content": "Once upon a time..."}, { "title": "New list with dates", "description": "New List with dates", "content": '<div class="mceTmpl"><span class="cdate">cdate</span><br /><span class="mdate">mdate</span><h2>My List</h2><ul><li></li><li></li></ul></div>', # noqa }, ], "template_cdate_format": "[Date Created (CDATE): %m/%d/%Y : %H:%M:%S]", "template_mdate_format": "[Date Modified (MDATE): %m/%d/%Y : %H:%M:%S]", "setup": 'function(editor) {editor.on("input", onInputChange)}', }
# Make Free-Text Kaywords writable from users or read-only # - if True only admins can edit free-text kwds from admin dashboard
[docs] FREETEXT_KEYWORDS_READONLY = ast.literal_eval(os.environ.get("FREETEXT_KEYWORDS_READONLY", "False"))
# ########################################################################### # # ASYNC SETTINGS # ########################################################################### # # async signals can be the same as broker url # but they should have separate setting anyway # use amqp://localhost for local rabbitmq server """ sudo apt-get install -y erlang sudo apt-get install rabbitmq-server sudo update-rc.d rabbitmq-server enable sudo rabbitmqctl stop_app sudo rabbitmqctl reset sudo rabbitmqctl start_app sudo rabbitmqctl list_queues """ # Disabling the heartbeat because workers seems often disabled in flower, # thanks to http://stackoverflow.com/a/14831904/654755
[docs] BROKER_HEARTBEAT = 0
# Avoid long running and retried tasks to be run over-and-over again.
[docs] BROKER_TRANSPORT_OPTIONS = { "fanout_prefix": True, "fanout_patterns": True, "socket_timeout": 60, "visibility_timeout": 86400, }
[docs] CELERY_LOADER = os.environ.get("CELERY_LOADER", "geonode.loaders.GeoNodeCeleryTaksLoader")
[docs] ASYNC_SIGNALS = ast.literal_eval(os.environ.get("ASYNC_SIGNALS", "False"))
[docs] RABBITMQ_SIGNALS_BROKER_URL = "amqp://localhost:5672"
# REDIS_SIGNALS_BROKER_URL = 'redis://localhost:6379/0'
[docs] LOCAL_SIGNALS_BROKER_URL = "memory://"
if ASYNC_SIGNALS:
[docs] _BROKER_URL = RABBITMQ_SIGNALS_BROKER_URL
else: _BROKER_URL = LOCAL_SIGNALS_BROKER_URL
[docs] CELERY_RESULT_BACKEND = "django-db"
[docs] CELERY_BROKER_URL = os.environ.get("BROKER_URL", _BROKER_URL)
[docs] CELERY_RESULT_PERSISTENT = ast.literal_eval(os.environ.get("CELERY_RESULT_PERSISTENT", "False"))
[docs] CELERY_IGNORE_RESULT = ast.literal_eval(os.environ.get("CELERY_IGNORE_RESULT", "False"))
# Allow to recover from any unknown crash.
[docs] CELERY_ACKS_LATE = ast.literal_eval(os.environ.get("CELERY_ACKS_LATE", "True"))
# Add a ten-minutes timeout to all Celery tasks.
[docs] CELERYD_SOFT_TIME_LIMIT = 600
# Set this to False in order to run async
[docs] _EAGER_FLAG = "False" if ASYNC_SIGNALS else "True"
[docs] CELERY_TASK_ALWAYS_EAGER = ast.literal_eval(os.environ.get("CELERY_TASK_ALWAYS_EAGER", _EAGER_FLAG))
[docs] CELERY_TASK_EAGER_PROPAGATES = ast.literal_eval(os.environ.get("CELERY_TASK_EAGER_PROPAGATES", "True"))
[docs] CELERY_TASK_IGNORE_RESULT = ast.literal_eval(os.environ.get("CELERY_TASK_IGNORE_RESULT", "True"))
register("geonode_json", serializer.dumps, serializer.loads, content_type="application/json", content_encoding="utf-8") # I use these to debug kombu crashes; we get a more informative message.
[docs] CELERY_TASK_SERIALIZER = os.environ.get("CELERY_TASK_SERIALIZER", "geonode_json")
[docs] CELERY_RESULT_SERIALIZER = os.environ.get("CELERY_RESULT_SERIALIZER", "geonode_json")
[docs] CELERY_ACCEPT_CONTENT = [ CELERY_RESULT_SERIALIZER, ]
# Set Tasks Queues # CELERY_TASK_DEFAULT_QUEUE = "default" # CELERY_TASK_DEFAULT_EXCHANGE = "default" # CELERY_TASK_DEFAULT_EXCHANGE_TYPE = "direct" # CELERY_TASK_DEFAULT_ROUTING_KEY = "default"
[docs] CELERY_TASK_CREATE_MISSING_QUEUES = ast.literal_eval(os.environ.get("CELERY_TASK_CREATE_MISSING_QUEUES", "True"))
[docs] GEONODE_EXCHANGE = Exchange("default", type="topic", durable=True)
[docs] CELERY_TASK_QUEUES = ( Queue("default", GEONODE_EXCHANGE, routing_key="default", priority=0), Queue("geonode", GEONODE_EXCHANGE, routing_key="geonode", priority=0), Queue("update", GEONODE_EXCHANGE, routing_key="update", priority=0), Queue("upload", GEONODE_EXCHANGE, routing_key="upload", priority=0), Queue("cleanup", GEONODE_EXCHANGE, routing_key="cleanup", priority=0), Queue("email", GEONODE_EXCHANGE, routing_key="email", priority=0), Queue("security", GEONODE_EXCHANGE, routing_key="security", priority=0), Queue("management_commands_http", GEONODE_EXCHANGE, routing_key="management_commands_http", priority=0), Queue("clery_cleanup", GEONODE_EXCHANGE, routing_key="clery_cleanup", priority=0), )
if USE_GEOSERVER:
[docs] GEOSERVER_EXCHANGE = Exchange("geonode", type="topic", durable=True)
CELERY_TASK_QUEUES += ( Queue("broadcast", GEOSERVER_EXCHANGE, routing_key="#"), Queue("email.events", GEOSERVER_EXCHANGE, routing_key="geoserver.email"), Queue("all.geoserver", GEOSERVER_EXCHANGE, routing_key="geoserver.#"), Queue("geoserver.catalog", GEOSERVER_EXCHANGE, routing_key="geoserver.catalog"), Queue("geoserver.data", GEOSERVER_EXCHANGE, routing_key="geoserver.data"), Queue("geoserver.events", GEOSERVER_EXCHANGE, routing_key="geonode.geoserver"), Queue("notifications.events", GEOSERVER_EXCHANGE, routing_key="notifications"), Queue("geonode.layer.viewer", GEOSERVER_EXCHANGE, routing_key="geonode.viewer"), ) # from celery.schedules import crontab # EXAMPLES # ... # 'update_feeds': { # 'task': 'arena.social.tasks.Update', # 'schedule': crontab(minute='*/6'), # }, # ... # 'send-summary-every-hour': { # 'task': 'summary', # # There are 4 ways we can handle time, read further # 'schedule': 3600.0, # # If you're using any arguments # 'args': (‘We don’t need any’,), # }, # # Executes every Friday at 4pm # 'send-notification-on-friday-afternoon': { # 'task': 'my_app.tasks.send_notification', # 'schedule': crontab(hour=16, day_of_week=5), # },
[docs] CELERY_BEAT_SCHEDULER = os.environ.get("CELERY_BEAT_SCHEDULER", "celery.beat:PersistentScheduler")
[docs] CELERY_BEAT_SCHEDULE = {}
[docs] DELAYED_SECURITY_SIGNALS = ast.literal_eval(os.environ.get("DELAYED_SECURITY_SIGNALS", "False"))
[docs] CELERY_ENABLE_UTC = ast.literal_eval(os.environ.get("CELERY_ENABLE_UTC", "True"))
[docs] CELERY_TIMEZONE = TIME_ZONE
# Half a day is enough
[docs] CELERY_TASK_RESULT_EXPIRES = os.environ.get("CELERY_TASK_RESULT_EXPIRES", 43200)
# Sometimes, Ask asks us to enable this to debug issues. # BTW, it will save some CPU cycles.
[docs] CELERY_DISABLE_RATE_LIMITS = ast.literal_eval(os.environ.get("CELERY_DISABLE_RATE_LIMITS", "False"))
[docs] CELERY_SEND_TASK_EVENTS = ast.literal_eval(os.environ.get("CELERY_SEND_TASK_EVENTS", "True"))
[docs] CELERY_WORKER_DISABLE_RATE_LIMITS = ast.literal_eval(os.environ.get("CELERY_WORKER_DISABLE_RATE_LIMITS", "False"))
[docs] CELERY_WORKER_SEND_TASK_EVENTS = ast.literal_eval(os.environ.get("CELERY_WORKER_SEND_TASK_EVENTS", "True"))
# Allow our remote workers to get tasks faster if they have a # slow internet connection (yes Gurney, I'm thinking of you).
[docs] CELERY_MESSAGE_COMPRESSION = os.environ.get("CELERY_MESSAGE_COMPRESSION", "gzip")
# The default beiing 5000, we need more than this.
[docs] CELERY_MAX_CACHED_RESULTS = os.environ.get("CELERY_MAX_CACHED_RESULTS", 32768)
# NOTE: I don't know if this is compatible with upstart.
[docs] CELERYD_POOL_RESTARTS = ast.literal_eval(os.environ.get("CELERYD_POOL_RESTARTS", "True"))
[docs] CELERY_TRACK_STARTED = ast.literal_eval(os.environ.get("CELERY_TRACK_STARTED", "True"))
[docs] CELERY_SEND_TASK_SENT_EVENT = ast.literal_eval(os.environ.get("CELERY_SEND_TASK_SENT_EVENT", "True"))
# Disabled by default and I like it, because we use Sentry for this.
[docs] CELERY_SEND_TASK_ERROR_EMAILS = ast.literal_eval(os.environ.get("CELERY_SEND_TASK_ERROR_EMAILS", "False"))
# ########################################################################### # # NOTIFICATIONS SETTINGS # ########################################################################### #
[docs] NOTIFICATION_ENABLED = ast.literal_eval(os.environ.get("NOTIFICATION_ENABLED", "True")) or TEST
# PINAX_NOTIFICATIONS_LANGUAGE_MODEL = "people.Profile" # notifications backends
[docs] NOTIFICATIONS_BACKEND = os.environ.get("NOTIFICATIONS_BACKEND", "geonode.notifications_backend.EmailBackend")
# setting the spam sensitivity to a number greater than (2) the default sensitivity described in pinax # in order to have email notifications turned off by default.
[docs] PINAX_NOTIFICATIONS_BACKENDS = [ ("email", NOTIFICATIONS_BACKEND, 3), ]
[docs] PINAX_NOTIFICATIONS_HOOKSET = "pinax.notifications.hooks.DefaultHookSet"
# Queue non-blocking notifications. # Set this to False in order to run async
[docs] _QUEUE_ALL_FLAG = "True" if ASYNC_SIGNALS else "False"
[docs] PINAX_NOTIFICATIONS_QUEUE_ALL = ast.literal_eval(os.environ.get("NOTIFICATIONS_QUEUE_ALL", _QUEUE_ALL_FLAG))
[docs] PINAX_NOTIFICATIONS_LOCK_WAIT_TIMEOUT = os.environ.get("NOTIFICATIONS_LOCK_WAIT_TIMEOUT", 600)
# explicitly define NOTIFICATION_LOCK_LOCATION # NOTIFICATION_LOCK_LOCATION = <path> # pinax.notifications # or notification
[docs] NOTIFICATIONS_MODULE = "pinax.notifications"
[docs] ADMINS_ONLY_NOTICE_TYPES = ast.literal_eval(os.getenv("ADMINS_ONLY_NOTICE_TYPES", "['monitoring_alert',]"))
# set to true to have multiple recipients in /message/create/
[docs] USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS = ast.literal_eval( os.environ.get("USER_MESSAGES_ALLOW_MULTIPLE_RECIPIENTS", "True") )
if NOTIFICATIONS_MODULE and NOTIFICATIONS_MODULE not in INSTALLED_APPS: INSTALLED_APPS += (NOTIFICATIONS_MODULE,) # ########################################################################### # # SECURITY SETTINGS # ########################################################################### #
[docs] ENABLE_APIKEY_LOGIN = ast.literal_eval(os.getenv("ENABLE_APIKEY_LOGIN", "False"))
if ENABLE_APIKEY_LOGIN: MIDDLEWARE += ("geonode.security.middleware.LoginFromApiKeyMiddleware",) # Require users to authenticate before using Geonode if LOCKDOWN_GEONODE: MIDDLEWARE += ("geonode.security.middleware.LoginRequiredMiddleware",) # for windows users check if they didn't set GEOS and GDAL in local_settings.py # maybe they set it as a windows environment if os.name == "nt": if "GEOS_LIBRARY_PATH" not in locals() or "GDAL_LIBRARY_PATH" not in locals(): if os.environ.get("GEOS_LIBRARY_PATH", None) and os.environ.get("GDAL_LIBRARY_PATH", None):
[docs] GEOS_LIBRARY_PATH = os.environ.get("GEOS_LIBRARY_PATH")
GDAL_LIBRARY_PATH = os.environ.get("GDAL_LIBRARY_PATH") else: # maybe it will be found regardless if not it will throw 500 error from django.contrib.gis.geos import GEOSGeometry # noqa # Keywords thesauri # e.g. THESAURUS = {'name':'inspire_themes', 'required':True, 'filter':True} # Required: (boolean, optional, default false) mandatory while editing metadata (not implemented yet) # Filter: (boolean, optional, default false) a filter option on that thesaurus will appear in the main search page # THESAURUS = {'name': 'inspire_themes', 'required': True, 'filter': True} # ######################################################## # # Advanced Resource Publishing Worklow Settings - START # # ######################################################## # # option to enable/disable resource unpublishing for administrators and members
[docs] RESOURCE_PUBLISHING = ast.literal_eval(os.getenv("RESOURCE_PUBLISHING", "False"))
# Each uploaded Dataset must be approved by an Admin before becoming visible
[docs] ADMIN_MODERATE_UPLOADS = ast.literal_eval(os.environ.get("ADMIN_MODERATE_UPLOADS", "False"))
# If this option is enabled, Resources belonging to a Group (with access private) won't be # visible by others
[docs] GROUP_PRIVATE_RESOURCES = ast.literal_eval(os.environ.get("GROUP_PRIVATE_RESOURCES", "False"))
# If this option is enabled, Groups will become strictly Mandatory on # Metadata Wizard
[docs] GROUP_MANDATORY_RESOURCES = ast.literal_eval(os.environ.get("GROUP_MANDATORY_RESOURCES", "False"))
# ######################################################## # # Advanced Resource Publishing Worklow Settings - END # # ######################################################## # # A boolean which specifies wether to display the email in user's profile
[docs] SHOW_PROFILE_EMAIL = ast.literal_eval(os.environ.get("SHOW_PROFILE_EMAIL", "False"))
# Enables cross origin requests for geonode-client
[docs] MAP_CLIENT_USE_CROSS_ORIGIN_CREDENTIALS = ast.literal_eval( os.getenv("MAP_CLIENT_USE_CROSS_ORIGIN_CREDENTIALS", "False") )
[docs] ACCOUNT_OPEN_SIGNUP = ast.literal_eval(os.environ.get("ACCOUNT_OPEN_SIGNUP", "True"))
[docs] ACCOUNT_APPROVAL_REQUIRED = ast.literal_eval(os.getenv("ACCOUNT_APPROVAL_REQUIRED", "False"))
[docs] ACCOUNT_ADAPTER = "geonode.people.adapters.LocalAccountAdapter"
[docs] ACCOUNT_AUTHENTICATION_METHOD = os.environ.get("ACCOUNT_AUTHENTICATION_METHOD", "username_email")
[docs] ACCOUNT_CONFIRM_EMAIL_ON_GET = ast.literal_eval(os.environ.get("ACCOUNT_CONFIRM_EMAIL_ON_GET", "True"))
[docs] ACCOUNT_EMAIL_REQUIRED = ast.literal_eval(os.environ.get("ACCOUNT_EMAIL_REQUIRED", "True"))
[docs] ACCOUNT_EMAIL_VERIFICATION = os.environ.get("ACCOUNT_EMAIL_VERIFICATION", "none")
# Since django-allauth 0.43.0.
[docs] ACCOUNT_SIGNUP_REDIRECT_URL = os.environ.get("ACCOUNT_SIGNUP_REDIRECT_URL", os.getenv("SITEURL", _default_siteurl))
[docs] ACCOUNT_LOGIN_ATTEMPTS_LIMIT = int(os.getenv("ACCOUNT_LOGIN_ATTEMPTS_LIMIT", "3"))
[docs] ACCOUNT_MAX_EMAIL_ADDRESSES = int(os.getenv("ACCOUNT_MAX_EMAIL_ADDRESSES", "2"))
[docs] SOCIALACCOUNT_AUTO_SIGNUP = ast.literal_eval(os.environ.get("SOCIALACCOUNT_AUTO_SIGNUP", "True"))
[docs] SOCIALACCOUNT_LOGIN_ON_GET = ast.literal_eval(os.environ.get("SOCIALACCOUNT_LOGIN_ON_GET", "True"))
# This will hide or show local registration form in allauth view. True will show form
[docs] SOCIALACCOUNT_WITH_GEONODE_LOCAL_SINGUP = ast.literal_eval( os.environ.get("SOCIALACCOUNT_WITH_GEONODE_LOCAL_SINGUP", "True") )
# GeoNode Default Generic OIDC Provider
[docs] SOCIALACCOUNT_OIDC_PROVIDER = os.environ.get("SOCIALACCOUNT_OIDC_PROVIDER", "geonode_openid_connect")
[docs] SOCIALACCOUNT_OIDC_PROVIDER_ENABLED = ast.literal_eval(os.environ.get("SOCIALACCOUNT_OIDC_PROVIDER_ENABLED", "False"))
[docs] SOCIALACCOUNT_ADAPTER = os.environ.get("SOCIALACCOUNT_ADAPTER", "geonode.people.adapters.GenericOpenIDConnectAdapter")
[docs] _SOCIALACCOUNT_PROFILE_EXTRACTOR = os.environ.get( "SOCIALACCOUNT_PROFILE_EXTRACTOR", "geonode.people.profileextractors.OpenIDExtractor" )
[docs] SOCIALACCOUNT_PROFILE_EXTRACTORS = { SOCIALACCOUNT_OIDC_PROVIDER: _SOCIALACCOUNT_PROFILE_EXTRACTOR, }
[docs] SOCIALACCOUNT_GROUP_ROLE_MAPPER = os.environ.get( "SOCIALACCOUNT_GROUP_ROLE_MAPPER", "geonode.people.profileextractors.OpenIDGroupRoleMapper" )
# Enable this in order to enable the OIDC SocialAccount Provider if SOCIALACCOUNT_OIDC_PROVIDER_ENABLED: INSTALLED_APPS += ("geonode.people.socialaccount.providers.geonode_openid_connect",)
[docs] _AZURE_TENANT_ID = os.getenv("MICROSOFT_TENANT_ID", "")
[docs] _AZURE_SOCIALACCOUNT_PROVIDER = { "NAME": "Microsoft Azure", "SCOPE": [ "User.Read", "openid", ], "AUTH_PARAMS": { "access_type": "online", "prompt": "select_account", }, "COMMON_FIELDS": {"email": "mail", "last_name": "surname", "first_name": "givenName"}, "UID_FIELD": "unique_name", "GROUP_ROLE_MAPPER_CLASS": SOCIALACCOUNT_GROUP_ROLE_MAPPER, "ACCOUNT_CLASS": "allauth.socialaccount.providers.azure.provider.AzureAccount", "ACCESS_TOKEN_URL": f"https://login.microsoftonline.com/{_AZURE_TENANT_ID}/oauth2/v2.0/token", "AUTHORIZE_URL": f"https://login.microsoftonline.com/{_AZURE_TENANT_ID}/oauth2/v2.0/authorize", "PROFILE_URL": "https://graph.microsoft.com/v1.0/me", }
[docs] _GOOGLE_SOCIALACCOUNT_PROVIDER = { "NAME": "Google", "SCOPE": [ "profile", "email", ], "AUTH_PARAMS": { "access_type": "online", "prompt": "select_account consent", }, "COMMON_FIELDS": {"email": "email", "last_name": "family_name", "first_name": "given_name"}, "GROUP_ROLE_MAPPER_CLASS": SOCIALACCOUNT_GROUP_ROLE_MAPPER, "ACCOUNT_CLASS": "allauth.socialaccount.providers.google.provider.GoogleAccount", "ACCESS_TOKEN_URL": "https://oauth2.googleapis.com/token", "AUTHORIZE_URL": "https://accounts.google.com/o/oauth2/v2/auth", "ID_TOKEN_ISSUER": "https://accounts.google.com", "OAUTH_PKCE_ENABLED": True, }
[docs] SOCIALACCOUNT_PROVIDERS_DEFS = {"azure": _AZURE_SOCIALACCOUNT_PROVIDER, "google": _GOOGLE_SOCIALACCOUNT_PROVIDER}
[docs] _SOCIALACCOUNT_PROVIDER = os.environ.get("SOCIALACCOUNT_PROVIDER", "google")
[docs] SOCIALACCOUNT_PROVIDERS = { SOCIALACCOUNT_OIDC_PROVIDER: SOCIALACCOUNT_PROVIDERS_DEFS.get(_SOCIALACCOUNT_PROVIDER), }
# Invitation Adapter
[docs] INVITATIONS_ADAPTER = ACCOUNT_ADAPTER
[docs] INVITATIONS_CONFIRMATION_URL_NAME = "geonode.invitations:accept-invite"
# Choose thumbnail generator -- this is the default generator
[docs] THUMBNAIL_GENERATOR = os.environ.get("THUMBNAIL_GENERATOR", "geonode.thumbs.thumbnails.create_gs_thumbnail_geonode")
[docs] THUMBNAIL_SIZE = { "width": int(os.environ.get("THUMBNAIL_GENERATOR_DEFAULT_SIZE_WIDTH", 500)), "height": int(os.environ.get("THUMBNAIL_GENERATOR_DEFAULT_SIZE_HEIGHT", 200)), }
[docs] THUMBNAIL_BACKGROUND = { # class generating thumbnail's background # 'class': 'geonode.thumbs.background.WikiMediaTileBackground', "class": "geonode.thumbs.background.OSMTileBackground", # 'class': 'geonode.thumbs.background.GenericXYZBackground', # initialization parameters for generator instance, valid only for generic classes "options": { # 'url': URL for the generic xyz / tms service # 'tms': False by default. Set to True if the service is TMS # 'tile_size': tile size for the generic xyz service, default is 256 }, # example options for a TMS service # 'class': 'geonode.thumbs.background.GenericXYZBackground', # 'options': { # 'url': 'http://maps.geosolutionsgroup.com/geoserver/gwc/service/tms/1.0.0/osm%3Aosm_simple_light@EPSG%3A900913@png/{z}/{x}/{y}.png', # 'tms': True # }, }
# define the urls after the settings are overridden if USE_GEOSERVER:
[docs] LOCAL_GXP_PTYPE = "gxp_wmscsource"
PUBLIC_GEOSERVER = { "source": { "title": "GeoServer - Public Layers", "attribution": f"&copy; {SITEURL}", "ptype": LOCAL_GXP_PTYPE, "url": f"{OGC_SERVER['default']['PUBLIC_LOCATION']}ows", "restUrl": "/gs/rest", } } LOCAL_GEOSERVER = { "source": { "title": "GeoServer - Private Layers", "attribution": f"&copy; {SITEURL}", "ptype": LOCAL_GXP_PTYPE, "url": "/gs/ows", "restUrl": "/gs/rest", } } baselayers = MAP_BASELAYERS MAP_BASELAYERS = [PUBLIC_GEOSERVER] MAP_BASELAYERS.extend(baselayers) # Settings for MONITORING plugin
[docs] MONITORING_ENABLED = ast.literal_eval(os.environ.get("MONITORING_ENABLED", "False"))
[docs] MONITORING_CONFIG = os.getenv("MONITORING_CONFIG", None)
[docs] MONITORING_HOST_NAME = os.getenv("MONITORING_HOST_NAME", HOSTNAME)
[docs] MONITORING_SERVICE_NAME = os.getenv("MONITORING_SERVICE_NAME", "geonode")
# how long monitoring data should be stored
[docs] MONITORING_DATA_TTL = timedelta(days=int(os.getenv("MONITORING_DATA_TTL", 365)))
# this will disable csrf check for notification config views, # use with caution - for dev purpose only
[docs] MONITORING_DISABLE_CSRF = ast.literal_eval(os.environ.get("MONITORING_DISABLE_CSRF", "False"))
if MONITORING_ENABLED: if "geonode.monitoring.middleware.MonitoringMiddleware" not in MIDDLEWARE: MIDDLEWARE += ("geonode.monitoring.middleware.MonitoringMiddleware",) # skip certain paths to not to mud stats too much
[docs] MONITORING_SKIP_PATHS = ( "/api/o/", "/monitoring/", "/admin", "/jsi18n", STATIC_URL, MEDIA_URL, re.compile("^/[a-z]{2}/admin/"), )
# configure aggregation of past data to control data resolution # list of data age, aggregation, in reverse order # for current data, 1 minute resolution # for data older than 1 day, 1-hour resolution # for data older than 2 weeks, 1 day resolution MONITORING_DATA_AGGREGATION = ( ( timedelta(seconds=0), timedelta(minutes=1), ), ( timedelta(days=1), timedelta(minutes=60), ), ( timedelta(days=14), timedelta(days=1), ), )
[docs] USER_ANALYTICS_ENABLED = ast.literal_eval(os.getenv("USER_ANALYTICS_ENABLED", "False"))
[docs] USER_ANALYTICS_GZIP = ast.literal_eval(os.getenv("USER_ANALYTICS_GZIP", "False"))
[docs] GEOIP_PATH = os.getenv("GEOIP_PATH", os.path.join(PROJECT_ROOT, "GeoIPCities.dat"))
# This controls if tastypie search on resourches is performed only with titles
[docs] SEARCH_RESOURCES_EXTENDED = ast.literal_eval(os.getenv("SEARCH_RESOURCES_EXTENDED", "True"))
# -- END Settings for MONITORING plugin
[docs] CATALOG_METADATA_TEMPLATE = os.getenv("CATALOG_METADATA_TEMPLATE", "catalogue/full_metadata.xml")
[docs] DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
[docs] UI_DEFAULT_MANDATORY_FIELDS = [ "id_resource-title", "id_resource-abstract", "id_resource-language", "id_resource-license", "id_resource-regions", "id_resource-date_type", "id_resource-date", "category_form", "id_resource-attribution", "id_resource-constraints_other", "id_resource-data_quality_statement", "id_resource-restriction_code_type", ]
[docs] UI_REQUIRED_FIELDS = ast.literal_eval(os.getenv("UI_REQUIRED_FIELDS ", "[]"))
[docs] UPLOAD_SESSION_EXPIRY_HOURS = os.getenv("UPLOAD_SESSION_EXPIRY_HOURS ", 24)
# If a command name is listed here, the command will be available to admins over http # This list is used by the management_commands_http app
[docs] MANAGEMENT_COMMANDS_EXPOSED_OVER_HTTP = set( [ "ping_mngmt_commands_http", "updatelayers", "sync_geonode_datasets", "sync_geonode_maps", "importlayers", "set_all_datasets_metadata", "set_layers_permissions", ] + ast.literal_eval(os.getenv("MANAGEMENT_COMMANDS_EXPOSED_OVER_HTTP ", "[]")) )
[docs] FILE_UPLOAD_HANDLERS = [ "geonode.upload.uploadhandler.SizeRestrictedFileUploadHandler", "django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler", ]
[docs] DEFAULT_MAX_UPLOAD_SIZE = int(os.getenv("DEFAULT_MAX_UPLOAD_SIZE", 104857600)) # 100 MB
[docs] DEFAULT_BUFFER_CHUNK_SIZE = int(os.getenv("DEFAULT_BUFFER_CHUNK_SIZE", 64 * 1024))
[docs] DEFAULT_MAX_PARALLEL_UPLOADS_PER_USER = int(os.getenv("DEFAULT_MAX_PARALLEL_UPLOADS_PER_USER", 5))
""" Default schema used to store extra and dynamic metadata for the resource """
[docs] DEFAULT_EXTRA_METADATA_SCHEMA = { Optional("id"): int, "filter_header": object, "field_name": object, "field_label": object, "field_value": object, }
""" If present, will extend the available metadata schema used for store new value for each resource. By default overrided the existing one. The expected schema is the same as the default """
[docs] CUSTOM_METADATA_SCHEMA = os.getenv("CUSTOM_METADATA_SCHEMA ", {})
""" Variable used to actually get the expected metadata schema for each resource_type. In this way, each resource type can have a different metadata schema """
[docs] EXTRA_METADATA_SCHEMA = { **{ "map": os.getenv("MAP_EXTRA_METADATA_SCHEMA", DEFAULT_EXTRA_METADATA_SCHEMA), "dataset": os.getenv("DATASET_EXTRA_METADATA_SCHEMA", DEFAULT_EXTRA_METADATA_SCHEMA), "document": os.getenv("DOCUMENT_EXTRA_METADATA_SCHEMA", DEFAULT_EXTRA_METADATA_SCHEMA), "geoapp": os.getenv("GEOAPP_EXTRA_METADATA_SCHEMA", DEFAULT_EXTRA_METADATA_SCHEMA), }, **CUSTOM_METADATA_SCHEMA, }
""" List of modules that implement custom metadata storers that will be called when the metadata of a resource is saved """
[docs] METADATA_STORERS = [ # 'geonode.resource.regions_storer.spatial_predicate_region_assignor', ]
""" Define the URLs patterns used by the SizeRestrictedFileUploadHandler to evaluate if the file is greater than the limit size defined """
[docs] SIZE_RESTRICTED_FILE_UPLOAD_ELEGIBLE_URL_NAMES = ( "data_upload", "uploads-upload", "document_upload", )
[docs] SUPPORTED_DATASET_FILE_TYPES = [ { "id": "shp", "label": "ESRI Shapefile", "format": "vector", "ext": ["shp"], "requires": ["shp", "prj", "dbf", "shx"], "optional": ["xml", "sld"], }, { "id": "tiff", "label": "GeoTIFF", "format": "raster", "ext": ["tiff", "tif", "geotiff", "geotif"], "mimeType": ["image/tiff"], "optional": ["xml", "sld"], }, { "id": "csv", "label": "Comma Separated Value (CSV)", "format": "vector", "ext": ["csv"], "mimeType": ["text/csv"], "optional": ["xml", "sld"], }, { "id": "zip", "label": "Zip Archive", "format": "archive", "ext": ["zip"], "mimeType": ["application/zip"], "optional": ["xml", "sld"], }, { "id": "xml", "label": "XML Metadata File", "format": "metadata", "ext": ["xml"], "mimeType": ["application/json"], "needsFiles": ["shp", "prj", "dbf", "shx", "csv", "tiff", "zip", "sld"], }, { "id": "sld", "label": "Styled Layer Descriptor (SLD)", "format": "metadata", "ext": ["sld"], "mimeType": ["application/json"], "needsFiles": ["shp", "prj", "dbf", "shx", "csv", "tiff", "zip", "xml"], }, ]
INSTALLED_APPS += ( "dynamic_models", "importer", "importer.handlers", ) CELERY_TASK_QUEUES += ( Queue("importer.import_orchestrator", GEONODE_EXCHANGE, routing_key="importer.import_orchestrator"), Queue("importer.import_resource", GEONODE_EXCHANGE, routing_key="importer.import_resource", max_priority=8), Queue("importer.publish_resource", GEONODE_EXCHANGE, routing_key="importer.publish_resource", max_priority=8), Queue( "importer.create_geonode_resource", GEONODE_EXCHANGE, routing_key="importer.create_geonode_resource", max_priority=8, ), Queue( "importer.import_with_ogr2ogr", GEONODE_EXCHANGE, routing_key="importer.import_with_ogr2ogr", max_priority=10 ), Queue("importer.import_next_step", GEONODE_EXCHANGE, routing_key="importer.import_next_step", max_priority=3), Queue( "importer.create_dynamic_structure", GEONODE_EXCHANGE, routing_key="importer.create_dynamic_structure", max_priority=10, ), Queue( "importer.copy_geonode_resource", GEONODE_EXCHANGE, routing_key="importer.copy_geonode_resource", max_priority=0 ), Queue("importer.copy_dynamic_model", GEONODE_EXCHANGE, routing_key="importer.copy_dynamic_model"), Queue("importer.copy_geonode_data_table", GEONODE_EXCHANGE, routing_key="importer.copy_geonode_data_table"), Queue("importer.copy_raster_file", GEONODE_EXCHANGE, routing_key="importer.copy_raster_file"), Queue("importer.rollback", GEONODE_EXCHANGE, routing_key="importer.rollback"), )
[docs] DATABASE_ROUTERS = ["importer.db_router.DatastoreRouter"]
SIZE_RESTRICTED_FILE_UPLOAD_ELEGIBLE_URL_NAMES += ("importer_upload",)
[docs] IMPORTER_HANDLERS = ast.literal_eval( os.getenv( "IMPORTER_HANDLERS", "[\ 'importer.handlers.gpkg.handler.GPKGFileHandler',\ 'importer.handlers.geojson.handler.GeoJsonFileHandler',\ 'importer.handlers.shapefile.handler.ShapeFileHandler',\ 'importer.handlers.kml.handler.KMLFileHandler',\ 'importer.handlers.csv.handler.CSVFileHandler',\ 'importer.handlers.geotiff.handler.GeoTiffFileHandler',\ 'importer.handlers.xml.handler.XMLFileHandler',\ 'importer.handlers.sld.handler.SLDFileHandler',\ ]", ) )
INSTALLED_APPS += ("geonode.facets",) GEONODE_APPS += ("geonode.facets",)
[docs] FACET_PROVIDERS = [ {"class": "geonode.facets.providers.baseinfo.ResourceTypeFacetProvider"}, {"class": "geonode.facets.providers.baseinfo.FeaturedFacetProvider"}, {"class": "geonode.facets.providers.category.CategoryFacetProvider", "config": {"order": 5, "type": "select"}}, {"class": "geonode.facets.providers.keyword.KeywordFacetProvider", "config": {"order": 6, "type": "select"}}, {"class": "geonode.facets.providers.region.RegionFacetProvider", "config": {"order": 7, "type": "select"}}, {"class": "geonode.facets.providers.users.OwnerFacetProvider", "config": {"order": 8, "type": "select"}}, {"class": "geonode.facets.providers.thesaurus.ThesaurusFacetProvider", "config": {"type": "select"}}, ]
[docs] DEFAULT_DATASET_DOWNLOAD_HANDLER = "geonode.layers.download_handler.DatasetDownloadHandler"
[docs] DATASET_DOWNLOAD_HANDLERS = ast.literal_eval(os.getenv("DATASET_DOWNLOAD_HANDLERS", "[]"))
[docs] AUTO_ASSIGN_REGISTERED_MEMBERS_TO_CONTRIBUTORS = ast.literal_eval( os.getenv("AUTO_ASSIGN_REGISTERED_MEMBERS_TO_CONTRIBUTORS", "True") )
# ################# # KAN modifications # ################# import json # Use Argenmap as base layer
[docs] USE_ARGENMAP_BASE_MAP = ast.literal_eval(os.environ.get("USE_ARGENMAP_BASE_MAP", "False"))
if USE_ARGENMAP_BASE_MAP:
[docs] DEFAULT_MS2_BACKGROUNDS = [ { "type": "wms", "title": "Argenmap", "format": "image/jpeg", "id": "capabaseargenmap", "name": "capabaseargenmap", "url": "https://wms.ign.gob.ar/geoserver/wms", "group": "background", "thumbURL": f"{SITEURL}static/mapstorestyle/img/argenmap.png", "visibility": True }, { "type": "osm", "title": "Open Street Map", "name": "mapnik", "source": "osm", "group": "background", "visibility": False, }, { "type": "tileprovider", "title": "OpenTopoMap", "provider": "OpenTopoMap", "name": "OpenTopoMap", "source": "OpenTopoMap", "group": "background", "visibility": False, }, { "type": "wms", "title": "Sentinel-2 cloudless - https://s2maps.eu", "format": "image/jpeg", "id": "s2cloudless", "name": "s2cloudless:s2cloudless", "url": "https://maps.geosolutionsgroup.com/geoserver/wms", "group": "background", "thumbURL": f"{SITEURL}static/mapstorestyle/img/s2cloudless-s2cloudless.png", "visibility": False, }, { "source": "ol", "group": "background", "id": "none", "name": "empty", "title": "Empty Background", "type": "empty", "visibility": False, "args": ["Empty Background", {"visibility": False}], }, ]
[docs] MAPSTORE_BASELAYERS = DEFAULT_MS2_BACKGROUNDS
# Custom collect for logstash if 'geonode_logstash' not in INSTALLED_APPS: INSTALLED_APPS += ('geonode_logstash',) CELERY_BEAT_SCHEDULE['dispatch_metrics'] = { 'task': 'geonode_logstash.tasks.dispatch_metrics', 'schedule': 3600.0, } # Load extra contib apps from .env
[docs] EXTRA_CONTRIB_APPS = json.loads(os.environ['EXTRA_CONTRIB_APPS'])
if EXTRA_CONTRIB_APPS[0]: INSTALLED_APPS += tuple(EXTRA_CONTRIB_APPS)
[docs] ACL_HOST = os.getenv("ACL_HOST", "internal:/")
[docs] ACL_USERNAME = os.getenv("ACL_USERNAME", ""),
[docs] ACL_PASSWORD = os.getenv("ACL_PASSWORD", ""),