diff --git a/.devcontainer/.env b/.devcontainer/.env deleted file mode 100644 index 4d4e75899e3..00000000000 --- a/.devcontainer/.env +++ /dev/null @@ -1,194 +0,0 @@ -COMPOSE_PROJECT_NAME=geonode -DOCKER_HOST_IP= -DOCKER_ENV=production -BACKUPS_VOLUME_DRIVER=local - -C_FORCE_ROOT=1 -FORCE_REINIT=false -INVOKE_LOG_STDOUT=true - -# LANGUAGE_CODE=pt -# LANGUAGES=(('en','English'),('pt','Portuguese')) - -DJANGO_SETTINGS_MODULE=geonode.settings -GEONODE_INSTANCE_NAME=geonode -GEONODE_LB_HOST_IP= -GEONODE_LB_PORT= - -# ################# -# backend -# ################# -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres -GEONODE_DATABASE=geonode -GEONODE_DATABASE_PASSWORD=geonode -GEONODE_GEODATABASE=geonode_data -GEONODE_GEODATABASE_PASSWORD=geonode_data -GEONODE_DATABASE_SCHEMA=public -GEONODE_GEODATABASE_SCHEMA=public -DATABASE_HOST=db -DATABASE_PORT=5432 -DATABASE_URL=postgis://geonode:geonode@db:5432/geonode -GEODATABASE_URL=postgis://geonode_data:geonode_data@db:5432/geonode_data -GEONODE_DB_CONN_MAX_AGE=0 -GEONODE_DB_CONN_TOUT=5 -DEFAULT_BACKEND_DATASTORE=datastore -BROKER_URL=amqp://guest:guest@rabbitmq:5672/ -CELERY_BEAT_SCHEDULER=celery.beat:PersistentScheduler -ASYNC_SIGNALS=True - -SITEURL=http://localhost:8000/ - -ALLOWED_HOSTS="['django', '*']" - -# Data Uploader -DEFAULT_BACKEND_UPLOADER=geonode.importer -TIME_ENABLED=True -MOSAIC_ENABLED=False -HAYSTACK_SEARCH=False -HAYSTACK_ENGINE_URL=http://elasticsearch:9200/ -HAYSTACK_ENGINE_INDEX_NAME=haystack -HAYSTACK_SEARCH_RESULTS_PER_PAGE=200 - -# ################# -# nginx -# HTTPD Server -# ################# -GEONODE_LB_HOST_IP=localhost -GEONODE_LB_PORT=80 - -# IP or domain name and port where the server can be reached on HTTPS (leave HOST empty if you want to use HTTP only) -# port where the server can be reached on HTTPS -HTTP_HOST=localhost -HTTPS_HOST= - -HTTP_PORT=8000 -HTTPS_PORT=443 - -# Let's Encrypt certificates for https encryption. You must have a domain name as HTTPS_HOST (doesn't work -# with an ip) and it must be reachable from the outside. This can be one of the following : -# disabled : we do not get a certificate at all (a placeholder certificate will be used) -# staging : we get staging certificates (are invalid, but allow to test the process completely and have much higher limit rates) -# production : we get a normal certificate (default) -LETSENCRYPT_MODE=disabled -# LETSENCRYPT_MODE=staging -# LETSENCRYPT_MODE=production - -RESOLVER=127.0.0.11 - -# ################# -# geoserver -# ################# -GEOSERVER_WEB_UI_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_PUBLIC_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_LOCATION=http://geoserver:8080/geoserver/ -GEOSERVER_ADMIN_USER=admin -GEOSERVER_ADMIN_PASSWORD=geoserver - -OGC_REQUEST_TIMEOUT=30 -OGC_REQUEST_MAX_RETRIES=1 -OGC_REQUEST_BACKOFF_FACTOR=0.3 -OGC_REQUEST_POOL_MAXSIZE=10 -OGC_REQUEST_POOL_CONNECTIONS=10 - -# Java Options & Memory -ENABLE_JSONP=true -outFormat=text/javascript -GEOSERVER_JAVA_OPTS="-Djava.awt.headless=true -Xms2G -Xmx4G -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:PerfDataSamplingInterval=500 -XX:SoftRefLRUPolicyMSPerMB=36000 -XX:-UseGCOverheadLimit -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -DALLOW_ENV_PARAMETRIZATION=true -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine" - -# ################# -# Security -# ################# -# Admin Settings -# -# ADMIN_PASSWORD is used to overwrite the GeoNode admin password **ONLY** the first time -# GeoNode is run. If you need to overwrite it again, you need to set the env var FORCE_REINIT, -# otherwise the invoke updateadmin task will be skipped and the current password already stored -# in DB will honored. - -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin -ADMIN_EMAIL=admin@localhost - -# EMAIL Notifications -EMAIL_ENABLE=False -DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend -DJANGO_EMAIL_HOST=localhost -DJANGO_EMAIL_PORT=25 -DJANGO_EMAIL_HOST_USER= -DJANGO_EMAIL_HOST_PASSWORD= -DJANGO_EMAIL_USE_TLS=False -DJANGO_EMAIL_USE_SSL=False -DEFAULT_FROM_EMAIL='GeoNode ' - -# Session/Access Control -LOCKDOWN_GEONODE=False -CORS_ALLOW_ALL_ORIGINS=True -X_FRAME_OPTIONS="SAMEORIGIN" -SESSION_EXPIRED_CONTROL_ENABLED=True -DEFAULT_ANONYMOUS_VIEW_PERMISSION=True -DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION=True - -# Users Registration -ACCOUNT_OPEN_SIGNUP=True -ACCOUNT_EMAIL_REQUIRED=True -ACCOUNT_APPROVAL_REQUIRED=False -ACCOUNT_CONFIRM_EMAIL_ON_GET=False -ACCOUNT_EMAIL_VERIFICATION=none -ACCOUNT_AUTHENTICATION_METHOD=username_email -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_REGISTERED_MEMBERS_GROUP_NAME=True - -# OAuth2 -OAUTH2_API_KEY= -OAUTH2_CLIENT_ID=Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV -OAUTH2_CLIENT_SECRET=rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3 - -# GeoNode APIs -API_LOCKDOWN=False -TASTYPIE_APIKEY= - -# ################# -# Production and -# Monitoring -# ################# -DEBUG=True -DEBUG_STATIC=True - -SECRET_KEY='myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' - -# STATIC_ROOT=/mnt/volumes/statics/static/ -# MEDIA_ROOT=/mnt/volumes/statics/uploaded/ -# GEOIP_PATH=/mnt/volumes/statics/geoip.db - -CACHE_BUSTING_STATIC_ENABLED=False - -MEMCACHED_ENABLED=False -MEMCACHED_BACKEND=django.core.cache.backends.memcached.PyLibMCCache -MEMCACHED_LOCATION=127.0.0.1:11211 -MEMCACHED_LOCK_EXPIRE=3600 -MEMCACHED_LOCK_TIMEOUT=10 - -MAX_DOCUMENT_SIZE=2 -CLIENT_RESULTS_LIMIT=5 -API_LIMIT_PER_PAGE=1000 - -# GIS Client -GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY=mapstore -MAPBOX_ACCESS_TOKEN= -GOOGLE_API_KEY= - -# Monitoring -MONITORING_ENABLED=False -MONITORING_DATA_TTL=365 -USER_ANALYTICS_ENABLED=True -USER_ANALYTICS_GZIP=True -CENTRALIZED_DASHBOARD_ENABLED=False -MONITORING_SERVICE_NAME=local-geonode -MONITORING_HOST_NAME=geonode - -# Other Options/Contribs -MODIFY_TOPICCATEGORY=True -AVATAR_GRAVATAR_SSL=True -EXIF_ENABLED=True -CREATE_LAYER=True -FAVORITE_ENABLED=True diff --git a/.env_dev b/.env_dev deleted file mode 100644 index f4d32a94fa3..00000000000 --- a/.env_dev +++ /dev/null @@ -1,213 +0,0 @@ -COMPOSE_PROJECT_NAME=geonode -# See https://github.com/containers/podman/issues/13889 -# DOCKER_BUILDKIT=0 -DOCKER_ENV=production -BACKUPS_VOLUME_DRIVER=local - -C_FORCE_ROOT=1 -FORCE_REINIT=false -INVOKE_LOG_STDOUT=true - -# LANGUAGE_CODE=it-it -# LANGUAGES=(('en-us','English'),('it-it','Italiano')) - -DJANGO_SETTINGS_MODULE=geonode.settings -GEONODE_INSTANCE_NAME=geonode - -# ################# -# backend -# ################# -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres -GEONODE_DATABASE=geonode -GEONODE_DATABASE_USER=geonode -GEONODE_DATABASE_PASSWORD=geonode -GEONODE_GEODATABASE=geonode_data -GEONODE_GEODATABASE_USER=geonode -GEONODE_GEODATABASE_PASSWORD=geonode -GEONODE_DATABASE_SCHEMA=public -GEONODE_GEODATABASE_SCHEMA=public -DATABASE_HOST=localhost -DATABASE_PORT=5432 -DATABASE_URL=postgis://geonode:geonode@localhost:5432/geonode -GEODATABASE_URL=postgis://geonode:geonode@localhost:5432/geonode_data -GEONODE_DB_CONN_MAX_AGE=0 -GEONODE_DB_CONN_TOUT=5 -DEFAULT_BACKEND_DATASTORE=datastore -BROKER_URL=redis://localhost:6379/0 -CELERY_BEAT_SCHEDULER=celery.beat:PersistentScheduler -ASYNC_SIGNALS=False - -# Harvesting Monitoring configuration -HARVESTING_MONITOR_ENABLED=False -HARVESTING_MONITOR_DELAY=60 - -SITEURL=http://localhost:8000/ - -ALLOWED_HOSTS="['django', '*']" - -# Data Uploader -TIME_ENABLED=True -MOSAIC_ENABLED=False - -# ################# -# nginx -# HTTPD Server -# ################# -GEONODE_LB_HOST_IP=django -GEONODE_LB_PORT=8000 -GEOSERVER_LB_HOST_IP=geoserver -GEOSERVER_LB_PORT=8080 -NGINX_BASE_URL=http://localhost - -# IP or domain name and port where the server can be reached on HTTPS (leave HOST empty if you want to use HTTP only) -# port where the server can be reached on HTTPS -HTTP_HOST=localhost -HTTPS_HOST= - -HTTP_PORT=8000 -HTTPS_PORT=443 - -# Let's Encrypt certificates for https encryption. You must have a domain name as HTTPS_HOST (doesn't work -# with an ip) and it must be reachable from the outside. This can be one of the following : -# disabled : we do not get a certificate at all (a placeholder certificate will be used) -# staging : we get staging certificates (are invalid, but allow to test the process completely and have much higher limit rates) -# production : we get a normal certificate (default) -LETSENCRYPT_MODE=disabled -# LETSENCRYPT_MODE=staging -# LETSENCRYPT_MODE=production - -RESOLVER=127.0.0.11 - -# ################# -# geoserver -# ################# -GEOSERVER_WEB_UI_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_PUBLIC_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_ADMIN_USER=admin -GEOSERVER_ADMIN_PASSWORD=geoserver - -OGC_REQUEST_TIMEOUT=30 -OGC_REQUEST_MAX_RETRIES=1 -OGC_REQUEST_BACKOFF_FACTOR=0.3 -OGC_REQUEST_POOL_MAXSIZE=10 -OGC_REQUEST_POOL_CONNECTIONS=10 - -# Java Options & Memory -ENABLE_JSONP=true -outFormat=text/javascript -GEOSERVER_JAVA_OPTS='-Djava.awt.headless=true -Xms4G -Xmx4G -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:PerfDataSamplingInterval=500 -XX:SoftRefLRUPolicyMSPerMB=36000 -XX:-UseGCOverheadLimit -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://localhost:8080/geoserver/pdf -DALLOW_ENV_PARAMETRIZATION=true -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine' - -# ################# -# Security -# ################# -# Admin Settings -# -# ADMIN_PASSWORD is used to overwrite the GeoNode admin password **ONLY** the first time -# GeoNode is run. If you need to overwrite it again, you need to set the env var FORCE_REINIT, -# otherwise the invoke updateadmin task will be skipped and the current password already stored -# in DB will honored. - -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin -ADMIN_EMAIL=admin@localhost - -# EMAIL Notifications -EMAIL_ENABLE=False -DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend -DJANGO_EMAIL_HOST=localhost -DJANGO_EMAIL_PORT=25 -DJANGO_EMAIL_HOST_USER= -DJANGO_EMAIL_HOST_PASSWORD= -DJANGO_EMAIL_USE_TLS=False -DJANGO_EMAIL_USE_SSL=False -DEFAULT_FROM_EMAIL='GeoNode ' - -# Session/Access Control -LOCKDOWN_GEONODE=False -X_FRAME_OPTIONS="SAMEORIGIN" -SESSION_EXPIRED_CONTROL_ENABLED=True -DEFAULT_ANONYMOUS_VIEW_PERMISSION=True -DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION=True - -CORS_ALLOW_ALL_ORIGINS=True -GEOSERVER_CORS_ENABLED=True -GEOSERVER_CORS_ALLOWED_ORIGINS=* -GEOSERVER_CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS -GEOSERVER_CORS_ALLOWED_HEADERS=* - -# Users Registration -ACCOUNT_OPEN_SIGNUP=True -ACCOUNT_EMAIL_REQUIRED=True -ACCOUNT_APPROVAL_REQUIRED=False -ACCOUNT_CONFIRM_EMAIL_ON_GET=False -ACCOUNT_EMAIL_VERIFICATION=none -ACCOUNT_AUTHENTICATION_METHOD=username_email -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_REGISTERED_MEMBERS_GROUP_NAME=True -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_CONTRIBUTORS=True - -# OAuth2 -OAUTH2_API_KEY= -OAUTH2_CLIENT_ID=Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV -OAUTH2_CLIENT_SECRET=rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3 - -# GeoNode APIs -API_LOCKDOWN=False - -# ################# -# Production and -# Monitoring -# ################# -DEBUG=True - -SECRET_KEY='myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' - -CACHE_BUSTING_STATIC_ENABLED=False - -MEMCACHED_ENABLED=False -MEMCACHED_BACKEND=django.core.cache.backends.memcached.PyLibMCCache -MEMCACHED_LOCATION=127.0.0.1:11211 -MEMCACHED_LOCK_EXPIRE=3600 -MEMCACHED_LOCK_TIMEOUT=10 -PERMISSION_CACHE_EXPIRATION_TIME=604800 -# -# Options for memcached binary, e.g. -vvv to log all requests and cache hits -# -MEMCACHED_OPTIONS= - -MAX_DOCUMENT_SIZE=200 -CLIENT_RESULTS_LIMIT=5 -API_LIMIT_PER_PAGE=1000 - -# GIS Client -GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY=mapstore -MAPBOX_ACCESS_TOKEN= -GOOGLE_API_KEY= - -# Other Options/Contribs -MODIFY_TOPICCATEGORY=True -AVATAR_GRAVATAR_SSL=True -EXIF_ENABLED=True -CREATE_LAYER=True -FAVORITE_ENABLED=True - -# Advanced Workflow -RESOURCE_PUBLISHING=False -ADMIN_MODERATE_UPLOADS=False - -# PostgreSQL -POSTGRESQL_MAX_CONNECTIONS=200 - -# Common containers restart policy -RESTART_POLICY_CONDITION="on-failure" -RESTART_POLICY_DELAY="5s" -RESTART_POLICY_MAX_ATTEMPTS="3" -RESTART_POLICY_WINDOW=120s - -DEFAULT_MAX_PARALLEL_UPLOADS_PER_USER=5 -UPSERT_CHUNK_SIZE= 100 -UPSERT_LIMIT_ERROR_LOG=100 - -# Enable or not the XLSX / XLS upload -XLSX_UPLOAD_ENABLED=False \ No newline at end of file diff --git a/.env_external.sample b/.env_external.sample new file mode 100644 index 00000000000..3ff76085694 --- /dev/null +++ b/.env_external.sample @@ -0,0 +1,25 @@ +# ============================================================ +# .env_external.sample +# +# Copie este arquivo para .env_external e preencha os valores. +# O arquivo .env_external NAO deve ser versionado (esta no .gitignore). +# +# Uso: cp .env_external.sample .env_external +# ============================================================ + +# GeoServer +GEOSERVER_URL=http://localhost:8080/geoserver +GS_USER=admin +GS_PASS=geoserver + +# Banco externo +EXT_DB_HOST= +EXT_DB_PORT=5432 +EXT_DB_NAME= +EXT_DB_SCHEMA=public +EXT_DB_USER= +EXT_DB_PASS= + +# GeoServer workspace/datastore +GS_WORKSPACE=geonode +GS_DATASTORE_NAME= diff --git a/.env_local b/.env_local deleted file mode 100644 index bc9a975fe1a..00000000000 --- a/.env_local +++ /dev/null @@ -1,214 +0,0 @@ -COMPOSE_PROJECT_NAME=geonode -# See https://github.com/containers/podman/issues/13889 -# DOCKER_BUILDKIT=0 -DOCKER_ENV=production -BACKUPS_VOLUME_DRIVER=local - -C_FORCE_ROOT=1 -FORCE_REINIT=false -INVOKE_LOG_STDOUT=true - -# LANGUAGE_CODE=it-it -# LANGUAGES=(('en-us','English'),('it-it','Italiano')) - -DJANGO_SETTINGS_MODULE=geonode.settings -GEONODE_INSTANCE_NAME=geonode - -# ################# -# backend -# ################# -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres -GEONODE_DATABASE=geonode -GEONODE_DATABASE_USER=geonode -GEONODE_DATABASE_PASSWORD=geonode -GEONODE_GEODATABASE=geonode_data -GEONODE_GEODATABASE_USER=geonode -GEONODE_GEODATABASE_PASSWORD=geonode -GEONODE_DATABASE_SCHEMA=public -GEONODE_GEODATABASE_SCHEMA=public -DATABASE_HOST=localhost -DATABASE_PORT=5432 -DATABASE_URL=postgis://geonode:geonode@localhost:5432/geonode -GEODATABASE_URL=postgis://geonode:geonode@localhost:5432/geonode_data -GEONODE_DB_CONN_MAX_AGE=0 -GEONODE_DB_CONN_TOUT=5 -DEFAULT_BACKEND_DATASTORE=datastore -BROKER_URL=redis://localhost:6379/0 -CELERY_BEAT_SCHEDULER=celery.beat:PersistentScheduler -ASYNC_SIGNALS=False - -# Monitoring configuration -HARVESTING_MONITOR_ENABLED=False -HARVESTING_MONITOR_DELAY=60 - -SITEURL=http://localhost:8000/ - -ALLOWED_HOSTS="['django', '*']" - -# Data Uploader -TIME_ENABLED=True -MOSAIC_ENABLED=False - -# ################# -# nginx -# HTTPD Server -# ################# -GEONODE_LB_HOST_IP=django -GEONODE_LB_PORT=8000 -GEOSERVER_LB_HOST_IP=geoserver -GEOSERVER_LB_PORT=8080 -NGINX_BASE_URL=https://localhost - -# IP or domain name and port where the server can be reached on HTTPS (leave HOST empty if you want to use HTTP only) -# port where the server can be reached on HTTPS -HTTP_HOST=localhost -HTTPS_HOST= - -HTTP_PORT=80 -HTTPS_PORT=443 - -# Let's Encrypt certificates for https encryption. You must have a domain name as HTTPS_HOST (doesn't work -# with an ip) and it must be reachable from the outside. This can be one of the following : -# disabled : we do not get a certificate at all (a placeholder certificate will be used) -# staging : we get staging certificates (are invalid, but allow to test the process completely and have much higher limit rates) -# production : we get a normal certificate (default) -LETSENCRYPT_MODE=disabled -# LETSENCRYPT_MODE=staging -# LETSENCRYPT_MODE=production - -RESOLVER=127.0.0.11 - -# ################# -# geoserver -# ################# -GEOSERVER_WEB_UI_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_PUBLIC_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_LOCATION=http://localhost:8080/geoserver/ -GEOSERVER_ADMIN_USER=admin -GEOSERVER_ADMIN_PASSWORD=geoserver - -OGC_REQUEST_TIMEOUT=30 -OGC_REQUEST_MAX_RETRIES=1 -OGC_REQUEST_BACKOFF_FACTOR=0.3 -OGC_REQUEST_POOL_MAXSIZE=10 -OGC_REQUEST_POOL_CONNECTIONS=10 - -# Java Options & Memory -ENABLE_JSONP=true -outFormat=text/javascript -GEOSERVER_JAVA_OPTS='-Djava.awt.headless=true -Xms4G -Xmx4G -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:PerfDataSamplingInterval=500 -XX:SoftRefLRUPolicyMSPerMB=36000 -XX:-UseGCOverheadLimit -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://localhost:8080/geoserver/pdf -DALLOW_ENV_PARAMETRIZATION=true -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine' - -# ################# -# Security -# ################# -# Admin Settings -# -# ADMIN_PASSWORD is used to overwrite the GeoNode admin password **ONLY** the first time -# GeoNode is run. If you need to overwrite it again, you need to set the env var FORCE_REINIT, -# otherwise the invoke updateadmin task will be skipped and the current password already stored -# in DB will honored. - -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin -ADMIN_EMAIL=admin@localhost - -# EMAIL Notifications -EMAIL_ENABLE=False -DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend -DJANGO_EMAIL_HOST=localhost -DJANGO_EMAIL_PORT=25 -DJANGO_EMAIL_HOST_USER= -DJANGO_EMAIL_HOST_PASSWORD= -DJANGO_EMAIL_USE_TLS=False -DJANGO_EMAIL_USE_SSL=False -DEFAULT_FROM_EMAIL='GeoNode ' - -# Session/Access Control -LOCKDOWN_GEONODE=False -X_FRAME_OPTIONS="SAMEORIGIN" -SESSION_EXPIRED_CONTROL_ENABLED=True -DEFAULT_ANONYMOUS_VIEW_PERMISSION=True -DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION=True - -CORS_ALLOW_ALL_ORIGINS=True -GEOSERVER_CORS_ENABLED=True -GEOSERVER_CORS_ALLOWED_ORIGINS=* -GEOSERVER_CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS -GEOSERVER_CORS_ALLOWED_HEADERS=* - -# Users Registration -ACCOUNT_OPEN_SIGNUP=True -ACCOUNT_EMAIL_REQUIRED=True -ACCOUNT_APPROVAL_REQUIRED=False -ACCOUNT_CONFIRM_EMAIL_ON_GET=False -ACCOUNT_EMAIL_VERIFICATION=none -ACCOUNT_AUTHENTICATION_METHOD=username_email -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_REGISTERED_MEMBERS_GROUP_NAME=True -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_CONTRIBUTORS=True - -# OAuth2 -OAUTH2_API_KEY= -OAUTH2_CLIENT_ID=Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV -OAUTH2_CLIENT_SECRET=rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3 - -# GeoNode APIs -API_LOCKDOWN=False - -# ################# -# Production and -# Monitoring -# ################# -DEBUG=False - -SECRET_KEY='myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' - -# STATIC_ROOT=/mnt/volumes/statics/static/ -# MEDIA_ROOT=/mnt/volumes/statics/uploaded/ - -CACHE_BUSTING_STATIC_ENABLED=False - -MEMCACHED_ENABLED=False -MEMCACHED_BACKEND=django.core.cache.backends.memcached.PyLibMCCache -MEMCACHED_LOCATION=127.0.0.1:11211 -MEMCACHED_LOCK_EXPIRE=3600 -MEMCACHED_LOCK_TIMEOUT=10 -PERMISSION_CACHE_EXPIRATION_TIME=604800 -# -# Options for memcached binary, e.g. -vvv to log all requests and cache hits -# -MEMCACHED_OPTIONS= - -MAX_DOCUMENT_SIZE=200 -CLIENT_RESULTS_LIMIT=5 -API_LIMIT_PER_PAGE=1000 - -# GIS Client -GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY=mapstore -MAPBOX_ACCESS_TOKEN= -GOOGLE_API_KEY= - -# Other Options/Contribs -MODIFY_TOPICCATEGORY=True -AVATAR_GRAVATAR_SSL=True -EXIF_ENABLED=True -CREATE_LAYER=True -FAVORITE_ENABLED=True - -# Advanced Workflow -RESOURCE_PUBLISHING=False -ADMIN_MODERATE_UPLOADS=False - -# PostgreSQL -POSTGRESQL_MAX_CONNECTIONS=200 - -# Common containers restart policy -RESTART_POLICY_CONDITION="on-failure" -RESTART_POLICY_DELAY="5s" -RESTART_POLICY_MAX_ATTEMPTS="3" -RESTART_POLICY_WINDOW=120s - -DEFAULT_MAX_PARALLEL_UPLOADS_PER_USER=5 - -# Enable or not the XLSX / XLS upload -XLSX_UPLOAD_ENABLED=False diff --git a/.env_test b/.env_test deleted file mode 100644 index 04e8407217a..00000000000 --- a/.env_test +++ /dev/null @@ -1,229 +0,0 @@ -COMPOSE_PROJECT_NAME=geonode -# See https://github.com/containers/podman/issues/13889 -# DOCKER_BUILDKIT=0 -DOCKER_ENV=production -BACKUPS_VOLUME_DRIVER=local - -C_FORCE_ROOT=1 -FORCE_REINIT=false -INVOKE_LOG_STDOUT=true - -# LANGUAGE_CODE=it-it -# LANGUAGES=(('en-us','English'),('it-it','Italiano')) - -DJANGO_SETTINGS_MODULE=geonode.settings -GEONODE_INSTANCE_NAME=geonode - -# ################# -# backend -# ################# -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres -GEONODE_DATABASE=geonode -GEONODE_DATABASE_USER=geonode -GEONODE_DATABASE_PASSWORD=geonode -GEONODE_GEODATABASE=geonode_data -GEONODE_GEODATABASE_USER=geonode_data -GEONODE_GEODATABASE_PASSWORD=geonode_data -GEONODE_DATABASE_SCHEMA=public -GEONODE_GEODATABASE_SCHEMA=public -DATABASE_HOST=db -DATABASE_PORT=5432 -DATABASE_URL=postgis://geonode:geonode@db:5432/geonode -GEODATABASE_URL=postgis://geonode_data:geonode_data@db:5432/geonode_data -GEONODE_DB_CONN_MAX_AGE=0 -GEONODE_DB_CONN_TOUT=5 -DEFAULT_BACKEND_DATASTORE=datastore -BROKER_URL=redis://localhost:6379/0 -CELERY_BEAT_SCHEDULER=celery.beat:PersistentScheduler -ASYNC_SIGNALS=False - -# Monitoring configuration -HARVESTING_MONITOR_ENABLED=False -HARVESTING_MONITOR_DELAY=60 - -SITEURL=http://localhost:8000/ - -ALLOWED_HOSTS="['django', 'localhost', '127.0.0.1']" - -# Data Uploader -TIME_ENABLED=True -MOSAIC_ENABLED=False - -# ################# -# nginx -# HTTPD Server -# ################# -GEONODE_LB_HOST_IP=django -GEONODE_LB_PORT=8000 -GEOSERVER_LB_HOST_IP=geoserver -GEOSERVER_LB_PORT=8080 -NGINX_BASE_URL=http://localhost - -# IP or domain name and port where the server can be reached on HTTPS (leave HOST empty if you want to use HTTP only) -# port where the server can be reached on HTTPS -HTTP_HOST=localhost -HTTPS_HOST= -POSTGRESQL_MAX_CONNECTIONS=500 -HTTP_PORT=8000 -HTTPS_PORT=443 - -# Let's Encrypt certificates for https encryption. You must have a domain name as HTTPS_HOST (doesn't work -# with an ip) and it must be reachable from the outside. This can be one of the following : -# disabled : we do not get a certificate at all (a placeholder certificate will be used) -# staging : we get staging certificates (are invalid, but allow to test the process completely and have much higher limit rates) -# production : we get a normal certificate (default) -LETSENCRYPT_MODE=disabled -# LETSENCRYPT_MODE=staging -# LETSENCRYPT_MODE=production - -RESOLVER=127.0.0.11 - -# ################# -# geoserver -# ################# -GEOSERVER_WEB_UI_LOCATION=http://localhost:8000/geoserver/ -GEOSERVER_PUBLIC_LOCATION=http://localhost/geoserver/ -GEOSERVER_LOCATION=http://geoserver:8080/geoserver/ -GEOSERVER_ADMIN_USER=admin -GEOSERVER_ADMIN_PASSWORD=geoserver - -OGC_REQUEST_TIMEOUT=5 -OGC_REQUEST_MAX_RETRIES=0 -OGC_REQUEST_BACKOFF_FACTOR=0.3 -OGC_REQUEST_POOL_MAXSIZE=10 -OGC_REQUEST_POOL_CONNECTIONS=10 - -# ################# -# catalogue -# ################# -CATALOGUE_ENGINE=geonode.catalogue.backends.pycsw_local -CATALOGUE_URL=http://localhost:8000/catalogue/csw - -# Java Options & Memory -ENABLE_JSONP=true -outFormat=text/javascript -GEOSERVER_JAVA_OPTS='-Djava.awt.headless=true -Xms4G -Xmx4G -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:PerfDataSamplingInterval=500 -XX:SoftRefLRUPolicyMSPerMB=36000 -XX:-UseGCOverheadLimit -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://localhost/geoserver/pdf -DALLOW_ENV_PARAMETRIZATION=true -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine' - -# ################# -# Security -# ################# -# Admin Settings -# -# ADMIN_PASSWORD is used to overwrite the GeoNode admin password **ONLY** the first time -# GeoNode is run. If you need to overwrite it again, you need to set the env var FORCE_REINIT, -# otherwise the invoke updateadmin task will be skipped and the current password already stored -# in DB will honored. - -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin -ADMIN_EMAIL=admin@localhost - -# EMAIL Notifications -EMAIL_ENABLE=False -DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend -DJANGO_EMAIL_HOST=localhost -DJANGO_EMAIL_PORT=25 -DJANGO_EMAIL_HOST_USER= -DJANGO_EMAIL_HOST_PASSWORD= -DJANGO_EMAIL_USE_TLS=False -DJANGO_EMAIL_USE_SSL=False -DEFAULT_FROM_EMAIL='GeoNode ' - -# Session/Access Control -LOCKDOWN_GEONODE=False -X_FRAME_OPTIONS="SAMEORIGIN" -SESSION_EXPIRED_CONTROL_ENABLED=True -DEFAULT_ANONYMOUS_VIEW_PERMISSION=True -DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION=True - -CORS_ALLOW_ALL_ORIGINS=True -GEOSERVER_CORS_ENABLED=True -GEOSERVER_CORS_ALLOWED_ORIGINS=* -GEOSERVER_CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS -GEOSERVER_CORS_ALLOWED_HEADERS=* - -# Users Registration -ACCOUNT_OPEN_SIGNUP=True -ACCOUNT_EMAIL_REQUIRED=True -ACCOUNT_APPROVAL_REQUIRED=False -ACCOUNT_CONFIRM_EMAIL_ON_GET=False -ACCOUNT_EMAIL_VERIFICATION=none -ACCOUNT_AUTHENTICATION_METHOD=username_email -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_REGISTERED_MEMBERS_GROUP_NAME=True -AUTO_ASSIGN_REGISTERED_MEMBERS_TO_CONTRIBUTORS=True - -# OAuth2 -OAUTH2_API_KEY= -OAUTH2_CLIENT_ID=Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV -OAUTH2_CLIENT_SECRET=rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3 - -SOCIALACCOUNT_OIDC_PROVIDER_ENABLED=True -SOCIALACCOUNT_PROVIDER=google - -# GeoNode APIs -API_LOCKDOWN=False - -# ################# -# Production and -# Monitoring -# ################# -DEBUG=False - -SECRET_KEY='myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a' - -STATIC_ROOT=/mnt/volumes/statics/static/ -MEDIA_ROOT=/mnt/volumes/statics/uploaded/ - -CACHE_BUSTING_STATIC_ENABLED=False - -MEMCACHED_ENABLED=False -MEMCACHED_BACKEND=django.core.cache.backends.memcached.PyLibMCCache -MEMCACHED_LOCATION=memcached:11211 -MEMCACHED_LOCK_EXPIRE=3600 -MEMCACHED_LOCK_TIMEOUT=10 -PERMISSION_CACHE_EXPIRATION_TIME=604800 -# -# Options for memcached binary, e.g. -vvv to log all requests and cache hits -# -MEMCACHED_OPTIONS= - -MAX_DOCUMENT_SIZE=200 -CLIENT_RESULTS_LIMIT=5 -API_LIMIT_PER_PAGE=1000 - -# GIS Client -GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY=mapstore -MAPBOX_ACCESS_TOKEN= -GOOGLE_API_KEY= - -# Other Options/Contribs -MODIFY_TOPICCATEGORY=True -AVATAR_GRAVATAR_SSL=True -EXIF_ENABLED=True -CREATE_LAYER=True -FAVORITE_ENABLED=True - -# Advanced Workflow -RESOURCE_PUBLISHING=False -ADMIN_MODERATE_UPLOADS=False - -# PostgreSQL -POSTGRESQL_MAX_CONNECTIONS=200 - -# Common containers restart policy -RESTART_POLICY_CONDITION="on-failure" -RESTART_POLICY_DELAY="5s" -RESTART_POLICY_MAX_ATTEMPTS="3" -RESTART_POLICY_WINDOW=120s - -DEFAULT_MAX_PARALLEL_UPLOADS_PER_USER=100 - -# Azure AD -MICROSOFT_TENANT_ID= -AZURE_CLIENT_ID= -AZURE_SECRET_KEY= -AZURE_KEY= - -# Enable or not the XLSX / XLS upload -XLSX_UPLOAD_ENABLED=False diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..21f284e2604 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +*.sh text eol=lf +*.py text eol=lf +*.ini text eol=lf +*.cfg text eol=lf +*.yml text eol=auto +*.yaml text eol=auto +*.md text eol=auto +*.txt text eol=auto +*.json text eol=auto +celery-cmd text eol=lf +entrypoint.sh text eol=lf +wait-for-databases.sh text eol=lf +Dockerfile text eol=lf diff --git a/.gitignore b/.gitignore index 2080d18191d..227dada640c 100644 --- a/.gitignore +++ b/.gitignore @@ -97,4 +97,9 @@ scripts/spcgeonode/_volume_* !hooks/* .env +.env_local +.env_external +.env_dev +.env_test +.devcontainer/.env diff --git a/SETUP_REFERENCE.txt b/SETUP_REFERENCE.txt new file mode 100644 index 00000000000..4224343652c --- /dev/null +++ b/SETUP_REFERENCE.txt @@ -0,0 +1,328 @@ +# GeoNode Local - Guia de Referencia para Deploy em Producao +# ========================================================== +# +# Este documento descreve toda a configuracao do ambiente local GeoNode +# funcionando com banco externo PostGIS, servindo como base de referencia +# para replicar em um servidor de producao. +# +# Data de criacao: 2026-04-10 +# Branch: dev +# Repositorio base: GeoNode 5.1.0.dev0 + + +# ===================================================== +# 1. ARQUITETURA +# ===================================================== +# +# Fluxo de dados: +# +# db_geo_prd (PostGIS externo) +# | +# v +# GeoServer (publica camadas via REST/WMS/WFS) +# | +# v +# GeoNode (catalogo, visualizacao, permissoes) +# | +# v +# Nginx (proxy reverso, SSL, static files) +# | +# v +# Usuario final (browser) +# +# +# Containers Docker (9 servicos): +# +# +-----------------+-------+------------------------------------------+ +# | Container | Porta | Funcao | +# +-----------------+-------+------------------------------------------+ +# | django4geonode | 8000 | App Django/GeoNode (uWSGI) | +# | celery4geonode | - | Worker async + Beat scheduler | +# | nginx4geonode | 80 | Proxy reverso (serve GeoNode publico) | +# | geoserver4geo.. | 8080 | GeoServer (OGC services + admin) | +# | db4geonode | 5434* | PostGIS interno (app + geodata GeoNode) | +# | redis4geonode | 6379 | Broker Celery (mensageria) | +# | memcached4geo.. | 11211 | Cache de sessoes | +# | gsconf4geonode | - | Bootstrap de data-dir do GeoServer | +# | letsencrypt4.. | - | Certificados SSL (desativado em dev) | +# +-----------------+-------+------------------------------------------+ +# +# * Porta 5434 no host para nao conflitar com outros PostgreSQL locais. +# Em producao, o DB pode ficar sem porta exposta ou em host dedicado. + + +# ===================================================== +# 2. ARQUIVOS DE CONFIGURACAO +# ===================================================== +# +# Arquivo | Funcao +# ------------------------------|------------------------------------------ +# docker-compose-local.yml | Stack Docker completa (9 servicos) +# .env | Variaveis de ambiente (gerado via create-envfile.py) +# .env_local | Credenciais do banco externo (referencia) +# setup_external_datastore.sh | Registra o banco externo no GeoServer via REST API +# start_local.sh | Script de inicializacao completo +# geonode/settings.py | Settings Django (inclui Celery Beat schedule) +# .gitattributes | Forca LF em scripts shell (evita erro no Linux) +# .gitignore | Protege .env e .env_local de commit + + +# ===================================================== +# 3. PARAMETROS CRITICOS PARA PRODUCAO +# ===================================================== +# +# Os parametros abaixo DEVEM ser alterados ao migrar para producao. +# Use o comando: python create-envfile.py --help para gerar um novo .env +# +# --- SEGURANCA (OBRIGATORIO TROCAR) --- +# +# ADMIN_PASSWORD=admin -> Senha forte +# GEOSERVER_ADMIN_PASSWORD=geoserver -> Senha forte +# POSTGRES_PASSWORD=postgres -> Senha forte +# GEONODE_DATABASE_PASSWORD=geonode -> Senha forte +# GEONODE_GEODATABASE_PASSWORD=geonode_data -> Senha forte +# SECRET_KEY='ohh_7c5...' -> Gerar nova (50+ chars aleatórios) +# OAUTH2_CLIENT_ID=addEB0z1.. -> Gerar novo +# OAUTH2_CLIENT_SECRET=BRyIy.. -> Gerar novo +# +# --- REDE / DOMINIO --- +# +# SITEURL=http://localhost/ -> https://geonode.seudominio.com/ +# ALLOWED_HOSTS="['django','localhost']" -> "['django','geonode.seudominio.com']" +# HTTP_HOST=localhost -> geonode.seudominio.com +# HTTPS_HOST= -> geonode.seudominio.com +# GEOSERVER_WEB_UI_LOCATION -> https://geonode.seudominio.com/geoserver/ +# GEOSERVER_PUBLIC_LOCATION -> https://geonode.seudominio.com/geoserver/ +# NGINX_BASE_URL -> https://geonode.seudominio.com +# +# --- SSL --- +# +# LETSENCRYPT_MODE=disabled -> production +# ADMIN_EMAIL=admin@localhost -> email real (necessario para Let's Encrypt) +# +# --- PERFORMANCE --- +# +# DEBUG=True -> False +# POSTGRESQL_MAX_CONNECTIONS=200 -> Ajustar conforme RAM +# GEOSERVER_JAVA_OPTS -Xms4G -Xmx4G -> Ajustar conforme RAM do servidor +# +# --- BANCO EXTERNO (setup_external_datastore.sh) --- +# +# DB_HOST="172.20.30.31" -> IP do banco em producao +# DB_PORT="5432" -> Porta +# DB_NAME="db_geo_prd" -> Nome do banco +# DB_SCHEMA="geonode" -> Schema +# DB_USER="gabriel.leandro" -> Usuario com permissao SELECT +# DB_PASS="..." -> Senha + + +# ===================================================== +# 4. SINCRONIZACAO AUTOMATICA (Celery Beat) +# ===================================================== +# +# Configurada em: geonode/settings.py -> CELERY_BEAT_SCHEDULE +# +# A task "sync-geoserver-layers" roda a cada N segundos (padrao: 120s) +# e importa automaticamente camadas novas publicadas no GeoServer +# (workspace: geonode, store: db_geo_prd) para o catalogo do GeoNode. +# +# Parametros: +# GEOSERVER_SYNC_INTERVAL=120 (env var, em segundos) +# workspace=geonode (workspace do GeoServer) +# store=db_geo_prd (datastore do banco externo) +# owner=admin (usuario dono das camadas importadas) +# skip_geonode_registered=True (nao reimporta camadas ja existentes) +# +# Para producao, considerar: +# - Aumentar intervalo para 300-600s se ha muitas camadas +# - Trocar owner para usuario especifico +# - Monitorar fila geoserver.catalog no Celery +# +# Sync manual (se necessario): +# docker exec django4geonode python manage.py updatelayers \ +# --workspace geonode --store db_geo_prd \ +# --skip-geonode-registered -u admin +# +# Sync via API REST (admin autenticado): +# GET http://localhost/gs/updatelayers/?workspace=geonode&store=db_geo_prd +# +# Sync via Admin Django: +# http://localhost/admin -> Management command jobs -> updatelayers + + +# ===================================================== +# 5. COMO SUBIR O AMBIENTE +# ===================================================== +# +# Pre-requisitos: +# - Docker Desktop rodando +# - Acesso de rede ao banco externo (172.20.30.31:5432) +# +# Primeira vez (build + config): +# bash start_local.sh +# +# Ou manualmente: +# 1. docker compose -f docker-compose-local.yml up -d --build +# 2. Aguardar todos os containers ficarem healthy +# 3. bash setup_external_datastore.sh +# +# Subidas subsequentes (sem rebuild): +# docker compose -f docker-compose-local.yml up -d +# +# Parar tudo: +# docker compose -f docker-compose-local.yml down +# +# Parar e REMOVER DADOS (reset completo): +# docker compose -f docker-compose-local.yml down -v + + +# ===================================================== +# 6. ACESSOS +# ===================================================== +# +# +-------------+----------------------------------------------+-----------------+ +# | Servico | URL | Credenciais | +# +-------------+----------------------------------------------+-----------------+ +# | GeoNode | http://localhost/ | admin / admin | +# | GeoServer | http://localhost/geoserver/web/ | via OAuth2* | +# | GeoServer | http://localhost:8080/geoserver/ (interno) | admin / geoser. | +# | DB local | localhost:5434 | postgres / post.| +# | DB externo | 172.20.30.31:5432 | gabriel.leandro | +# | Django Admin| http://localhost/admin/ | admin / admin | +# | API v2 | http://localhost/api/v2/ | admin / admin | +# +-------------+----------------------------------------------+-----------------+ +# +# * O GeoServer usa OAuth2 integrado com GeoNode. Login feito pela +# interface do GeoNode, que redireciona de volta para o GeoServer +# autenticado. Acesso direto na porta 8080 via REST API usa basic auth. + + +# ===================================================== +# 7. FLUXO DE PUBLICACAO DE CAMADAS +# ===================================================== +# +# 1. Adicionar tabela/view no banco db_geo_prd (schema: geonode) +# +# 2. Publicar no GeoServer: +# - http://localhost/geoserver/web/ -> Layers -> Add a new layer +# - Selecionar store: geonode:db_geo_prd +# - Clicar Publish na tabela desejada +# - Definir SRS (EPSG:4326 / EPSG:4674 / etc) +# - Compute from data + Compute from native bounds +# - Save +# +# 3. Aguardar sincronizacao automatica (ate 2 min) ou forcar: +# docker exec django4geonode python manage.py updatelayers \ +# --workspace geonode --store db_geo_prd \ +# --skip-geonode-registered -u admin +# +# 4. Camada aparece no catalogo GeoNode (http://localhost/) + + +# ===================================================== +# 8. CHECKLIST DE DEPLOY EM PRODUCAO +# ===================================================== +# +# [ ] Gerar novo .env com senhas fortes: +# python create-envfile.py -hn geonode.seudominio.com \ +# --env_type prod --https --email admin@seudominio.com +# +# [ ] Alterar DEBUG=False no .env +# +# [ ] Configurar dominio e DNS apontando para o servidor +# +# [ ] Configurar LETSENCRYPT_MODE=production no .env +# +# [ ] Ajustar ALLOWED_HOSTS com o dominio +# +# [ ] Ajustar GEOSERVER_JAVA_OPTS conforme RAM disponivel +# +# [ ] Ajustar POSTGRESQL_MAX_CONNECTIONS conforme uso esperado +# +# [ ] Revisar setup_external_datastore.sh com IP/credenciais de producao +# +# [ ] Garantir acesso de rede do servidor ao banco externo +# +# [ ] Configurar GEOSERVER_SYNC_INTERVAL adequado (300-600s sugerido) +# +# [ ] Remover porta 8080 do docker-compose se GeoServer nao precisa acesso direto +# +# [ ] Remover porta 5434 do db se nao precisa acesso externo +# +# [ ] Configurar ACCOUNT_OPEN_SIGNUP=False se nao quer registro publico +# +# [ ] Configurar backup automatico dos volumes Docker +# +# [ ] Testar fluxo completo: publicar camada -> sync -> visualizar + + +# ===================================================== +# 9. COMANDOS UTEIS DE MANUTENCAO +# ===================================================== +# +# Ver logs de um container: +# docker logs -f django4geonode +# docker logs -f celery4geonode +# docker logs -f geoserver4geonode +# +# Acessar shell dentro do container Django: +# docker exec -it django4geonode bash +# +# Rodar management commands: +# docker exec django4geonode python manage.py +# +# Sincronizar permissoes: +# docker exec django4geonode python manage.py sync_geonode_datasets \ +# --updatepermissions --updateattributes +# +# Regenerar thumbnails: +# docker exec django4geonode python manage.py sync_geonode_datasets \ +# --updatethumbnails +# +# Atualizar metadata: +# docker exec django4geonode python manage.py set_all_datasets_metadata +# +# Criar superusuario: +# docker exec -it django4geonode python manage.py createsuperuser +# +# Backup do banco: +# docker exec db4geonode pg_dump -U postgres geonode > backup_geonode.sql +# docker exec db4geonode pg_dump -U postgres geonode_data > backup_geodata.sql +# +# Listar camadas disponiveis no banco externo: +# docker exec geoserver4geonode curl -s -u "admin:geoserver" \ +# "http://localhost:8080/geoserver/rest/workspaces/geonode/datastores/db_geo_prd/featuretypes.json?list=available" + + +# ===================================================== +# 10. TROUBLESHOOTING +# ===================================================== +# +# Problema: Container django fica em restart loop +# Causa: Line endings CRLF nos scripts .sh (Windows) +# Solucao: Verificar .gitattributes forca LF; rodar: +# git add --renormalize . && git checkout -- . +# +# Problema: GeoServer nao aceita login na porta 8080 +# Causa: OAuth2 integrado com GeoNode intercepta autenticacao web +# Solucao: Acessar via http://localhost/geoserver/web/ (Nginx proxy) +# REST API na 8080 funciona com basic auth via curl +# +# Problema: Camada publicada no GeoServer nao aparece no GeoNode +# Causa: Celery Beat pode nao ter rodado ainda (intervalo 120s) +# Solucao: Rodar sync manual: +# docker exec django4geonode python manage.py updatelayers \ +# --workspace geonode --store db_geo_prd --skip-geonode-registered -u admin +# +# Problema: Build falha com "image already exists" +# Causa: django e celery tentaram buildar a mesma imagem em paralelo +# Solucao: Build apenas no servico django (celery reutiliza imagem) +# docker rmi geonode/geonode:local && docker compose -f docker-compose-local.yml up -d --build +# +# Problema: Porta ja em uso (5432, 5433, 8080) +# Causa: Outro servico usando a porta +# Solucao: Alterar porta no docker-compose-local.yml (ex: 5434:5432) +# +# Problema: docker compose falha com "pipe not found" +# Causa: Docker Desktop nao esta rodando +# Solucao: Iniciar Docker Desktop e aguardar ficar verde diff --git a/docker-compose-local.yml b/docker-compose-local.yml new file mode 100644 index 00000000000..23ec91b3062 --- /dev/null +++ b/docker-compose-local.yml @@ -0,0 +1,207 @@ +# ============================================================ +# docker-compose-local.yml +# Stack local GeoNode + GeoServer + DB interno + DB externo +# +# Fluxo: db_geo_prd (externo) -> GeoServer -> publica camada -> GeoNode +# +# Uso: +# docker compose -f docker-compose-local.yml up -d --build +# docker compose -f docker-compose-local.yml down +# ============================================================ + +x-common-django: + &default-common-django + image: geonode/geonode:local + restart: unless-stopped + env_file: + - .env + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - '.:/usr/src/geonode' + - statics:/mnt/volumes/statics + - geoserver-data-dir:/geoserver_data/data + - backup-restore:/backup_restore + - data:/data + - tmp:/tmp + depends_on: + db: + condition: service_healthy + +services: + + # ------------------------------------------------------- + # Django / GeoNode application (build happens here only) + # ------------------------------------------------------- + django: + <<: *default-common-django + build: + context: ./ + dockerfile: Dockerfile + container_name: django4${COMPOSE_PROJECT_NAME} + healthcheck: + test: "curl -m 10 --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://django:8000/" + start_period: 60s + interval: 60s + timeout: 10s + retries: 2 + environment: + - IS_CELERY=False + entrypoint: ["/usr/src/geonode/entrypoint.sh"] + command: "uwsgi --ini /usr/src/geonode/uwsgi.ini" + + # ------------------------------------------------------- + # Celery worker + # ------------------------------------------------------- + celery: + <<: *default-common-django + container_name: celery4${COMPOSE_PROJECT_NAME} + depends_on: + django: + condition: service_healthy + environment: + - IS_CELERY=True + entrypoint: ["/usr/src/geonode/entrypoint.sh"] + command: "celery-cmd" + + # ------------------------------------------------------- + # Nginx (proxy reverso que serve o GeoNode na porta 80) + # ------------------------------------------------------- + geonode: + image: geonode/nginx:1.28.0-v1 + container_name: nginx4${COMPOSE_PROJECT_NAME} + env_file: + - .env + environment: + - RESOLVER=127.0.0.11 + ports: + - "${HTTP_PORT:-80}:80" + - "${HTTPS_PORT:-443}:443" + volumes: + - nginx-confd:/etc/nginx + - nginx-certificates:/geonode-certificates + - statics:/mnt/volumes/statics + restart: unless-stopped + + # ------------------------------------------------------- + # Let's Encrypt (desativado em dev, mas mantido) + # ------------------------------------------------------- + letsencrypt: + image: geonode/letsencrypt:2.6.0-latest + container_name: letsencrypt4${COMPOSE_PROJECT_NAME} + env_file: + - .env + volumes: + - nginx-certificates:/geonode-certificates + restart: unless-stopped + + # ------------------------------------------------------- + # GeoServer + # Porta 8080 exposta para acesso direto (admin console) + # ------------------------------------------------------- + geoserver: + image: geonode/geoserver:2.27.5-latest + container_name: geoserver4${COMPOSE_PROJECT_NAME} + healthcheck: + test: "curl -m 10 --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://geoserver:8080/geoserver/ows" + start_period: 60s + interval: 60s + timeout: 10s + retries: 2 + env_file: + - .env + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "8080:8080" + volumes: + - statics:/mnt/volumes/statics + - geoserver-data-dir:/geoserver_data/data + - backup-restore:/backup_restore + - data:/data + - tmp:/tmp + restart: unless-stopped + depends_on: + data-dir-conf: + condition: service_healthy + django: + condition: service_healthy + + # ------------------------------------------------------- + # GeoServer data directory bootstrap + # ------------------------------------------------------- + data-dir-conf: + image: geonode/geoserver_data:2.27.5-latest + container_name: gsconf4${COMPOSE_PROJECT_NAME} + entrypoint: sleep infinity + volumes: + - geoserver-data-dir:/geoserver_data/data + restart: unless-stopped + healthcheck: + test: "ls -A '/geoserver_data/data' | wc -l" + + # ------------------------------------------------------- + # PostGIS local (banco interno do GeoNode) + # Porta 5434 no host para nao conflitar com outros DBs + # ------------------------------------------------------- + db: + image: geonode/postgis:15-3.5-latest + command: postgres -c "max_connections=${POSTGRESQL_MAX_CONNECTIONS:-200}" + container_name: db4${COMPOSE_PROJECT_NAME} + env_file: + - .env + volumes: + - dbdata:/var/lib/postgresql/data + - dbbackups:/pg_backups + restart: unless-stopped + healthcheck: + test: "pg_isready -d postgres -U postgres" + ports: + - "5434:5432" + + # ------------------------------------------------------- + # Redis (broker do Celery) + # ------------------------------------------------------- + redis: + image: redis:7-alpine + container_name: redis4${COMPOSE_PROJECT_NAME} + volumes: + - redisdata:/data + restart: unless-stopped + + # ------------------------------------------------------- + # Memcached + # ------------------------------------------------------- + memcached: + image: memcached:alpine + container_name: memcached4${COMPOSE_PROJECT_NAME} + command: memcached ${MEMCACHED_OPTIONS} + restart: unless-stopped + healthcheck: + test: nc -z 127.0.0.1 11211 + interval: 30s + timeout: 30s + retries: 5 + start_period: 30s + +volumes: + statics: + name: ${COMPOSE_PROJECT_NAME}-statics + nginx-confd: + name: ${COMPOSE_PROJECT_NAME}-nginxconfd + nginx-certificates: + name: ${COMPOSE_PROJECT_NAME}-nginxcerts + geoserver-data-dir: + name: ${COMPOSE_PROJECT_NAME}-gsdatadir + dbdata: + name: ${COMPOSE_PROJECT_NAME}-dbdata + dbbackups: + name: ${COMPOSE_PROJECT_NAME}-dbbackups + backup-restore: + name: ${COMPOSE_PROJECT_NAME}-backup-restore + data: + name: ${COMPOSE_PROJECT_NAME}-data + tmp: + name: ${COMPOSE_PROJECT_NAME}-tmp + redisdata: + name: ${COMPOSE_PROJECT_NAME}-redisdata diff --git a/geonode/api/paginator.py b/geonode/api/paginator.py index dab5bf844b8..7f2f792eebc 100644 --- a/geonode/api/paginator.py +++ b/geonode/api/paginator.py @@ -1,80 +1,80 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### - -from django.conf import settings -from tastypie.exceptions import BadRequest -from tastypie.paginator import Paginator - - -class CrossSiteXHRPaginator(Paginator): - def get_limit(self): - """ - Determines the proper maximum number of results to return. - - In order of importance, it will use: - - * The user-requested ``limit`` from the GET parameters, if specified. - * The object-level ``limit`` if specified. - * ``settings.API_LIMIT_PER_PAGE`` if specified. - - Default is 20 per page. - """ - - limit = self.request_data.get("limit", self.limit) - if limit is None: - limit = getattr(settings, "API_LIMIT_PER_PAGE", 20) - - try: - limit = int(limit) - except ValueError: - raise BadRequest("Invalid limit provided. Please provide a positive integer.") - - if limit < 0: - raise BadRequest("Invalid limit provided. Please provide a positive integer >= 0.") - - if self.max_limit and (not limit or limit > self.max_limit): - # If it's more than the max, we're only going to return the max. - # This is to prevent excessive DB (or other) load. - return self.max_limit - - return limit - - def get_offset(self): - """ - Determines the proper starting offset of results to return. - - It attempts to use the user-provided ``offset`` from the GET parameters, - if specified. Otherwise, it falls back to the object-level ``offset``. - - Default is 0. - """ - offset = self.offset - - if "offset" in self.request_data: - offset = self.request_data["offset"] - - try: - offset = int(offset) - except ValueError: - raise BadRequest("Invalid offset provided. Please provide an integer.") - - if offset < 0: - raise BadRequest("Invalid offset provided. Please provide a positive integer >= 0.") - - return offset +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### + +from django.conf import settings +from tastypie.exceptions import BadRequest +from tastypie.paginator import Paginator + + +class CrossSiteXHRPaginator(Paginator): + def get_limit(self): + """ + Determines the proper maximum number of results to return. + + In order of importance, it will use: + + * The user-requested ``limit`` from the GET parameters, if specified. + * The object-level ``limit`` if specified. + * ``settings.API_LIMIT_PER_PAGE`` if specified. + + Default is 20 per page. + """ + + limit = self.request_data.get("limit", self.limit) + if limit is None: + limit = getattr(settings, "API_LIMIT_PER_PAGE", 20) + + try: + limit = int(limit) + except ValueError: + raise BadRequest("Invalid limit provided. Please provide a positive integer.") + + if limit < 0: + raise BadRequest("Invalid limit provided. Please provide a positive integer >= 0.") + + if self.max_limit and (not limit or limit > self.max_limit): + # If it's more than the max, we're only going to return the max. + # This is to prevent excessive DB (or other) load. + return self.max_limit + + return limit + + def get_offset(self): + """ + Determines the proper starting offset of results to return. + + It attempts to use the user-provided ``offset`` from the GET parameters, + if specified. Otherwise, it falls back to the object-level ``offset``. + + Default is 0. + """ + offset = self.offset + + if "offset" in self.request_data: + offset = self.request_data["offset"] + + try: + offset = int(offset) + except ValueError: + raise BadRequest("Invalid offset provided. Please provide an integer.") + + if offset < 0: + raise BadRequest("Invalid offset provided. Please provide a positive integer >= 0.") + + return offset diff --git a/geonode/apps.py b/geonode/apps.py index 1be78b5fdfa..c1c37986e10 100644 --- a/geonode/apps.py +++ b/geonode/apps.py @@ -1,36 +1,36 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from django.apps import AppConfig as BaseAppConfig - - -def run_setup_hooks(*args, **kwargs): - from django.conf import settings - from .celery_app import app as celery_app - - if celery_app not in settings.INSTALLED_APPS: - settings.INSTALLED_APPS += (celery_app,) - - -class AppConfig(BaseAppConfig): - name = "geonode" - label = "geonode" - - def ready(self): - super().ready() - run_setup_hooks() +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from django.apps import AppConfig as BaseAppConfig + + +def run_setup_hooks(*args, **kwargs): + from django.conf import settings + from .celery_app import app as celery_app + + if celery_app not in settings.INSTALLED_APPS: + settings.INSTALLED_APPS += (celery_app,) + + +class AppConfig(BaseAppConfig): + name = "geonode" + label = "geonode" + + def ready(self): + super().ready() + run_setup_hooks() diff --git a/geonode/base/fields.py b/geonode/base/fields.py index 94156334b9c..875a2bcfe11 100644 --- a/geonode/base/fields.py +++ b/geonode/base/fields.py @@ -1,29 +1,29 @@ -######################################################################### -# -# 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 . -# -######################################################################### - -from django import forms - - -class MultiThesauriField(forms.ModelMultipleChoiceField): - def label_from_instance(self, obj): - # Note: Not using .get() because filter()[0] is used in original - # code. The hard-coded language is currently used throughout - # geonode. - first_keyword = obj.keyword.first() - return first_keyword.label if first_keyword else "" +######################################################################### +# +# 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 . +# +######################################################################### + +from django import forms + + +class MultiThesauriField(forms.ModelMultipleChoiceField): + def label_from_instance(self, obj): + # Note: Not using .get() because filter()[0] is used in original + # code. The hard-coded language is currently used throughout + # geonode. + first_keyword = obj.keyword.first() + return first_keyword.label if first_keyword else "" diff --git a/geonode/base/fixtures/regions.json b/geonode/base/fixtures/regions.json index 0392627eb0e..aac70db28ce 100644 --- a/geonode/base/fixtures/regions.json +++ b/geonode/base/fixtures/regions.json @@ -1,4405 +1,4405 @@ -[ - { - "pk": 1, - "model": "base.region", - "fields": { - "rght": 516, - "code": "GLO", - "name": "Global", - "parent": null, - "level": 0, - "lft": 1, - "tree_id": 90, - "bbox_x0": -180, - "bbox_x1": 180, - "bbox_y0": -90, - "bbox_y1": 90 - } - }, - { - "pk": 2, - "model": "base.region", - "fields": { - "rght": 212, - "code": "NAM", - "name": "North America", - "parent": 254, - "level": 2, - "lft": 203, - "tree_id": 90, - "bbox_x0": -167.276413, - "bbox_x1": -52.23304, - "bbox_y0": 5.49955, - "bbox_y1": 83.162102 - } - }, - { - "pk": 3, - "model": "base.region", - "fields": { - "rght": 202, - "code": "CAM", - "name": "Central America", - "parent": 254, - "level": 2, - "lft": 187, - "tree_id": 90, - "bbox_x0": -118.867172, - "bbox_x1": -66.869827, - "bbox_y0": -4.23048, - "bbox_y1": 32.71862 - } - }, - { - "pk": 4, - "model": "base.region", - "fields": { - "rght": 242, - "code": "SAM", - "name": "South America", - "parent": 254, - "level": 2, - "lft": 213, - "tree_id": 90, - "bbox_x0": -109.47493, - "bbox_x1": -26.33247, - "bbox_y0": -59.450451, - "bbox_y1": 13.39029 - } - }, - { - "pk": 5, - "model": "base.region", - "fields": { - "rght": 433, - "code": "EUR", - "name": "Europe", - "parent": null, - "level": 1, - "lft": 318, - "tree_id": 90, - "bbox_x0": -31.266001, - "bbox_x1": 39.869301, - "bbox_y0": 27.636311, - "bbox_y1": 81.008797 - } - }, - { - "pk": 6, - "model": "base.region", - "fields": { - "rght": 317, - "code": "ASI", - "name": "Asia", - "parent": null, - "level": 1, - "lft": 246, - "tree_id": 90, - "bbox_x0": 19.6381, - "bbox_x1": 180, - "bbox_y0": -12.56111, - "bbox_y1": 82.50045 - } - }, - { - "pk": 7, - "model": "base.region", - "fields": { - "rght": 316, - "code": "SEA", - "name": "Southeast Asia", - "parent": 6, - "level": 2, - "lft": 293, - "tree_id": 90, - "bbox_x0": 68.0327, - "bbox_x1": 141.021805, - "bbox_y0": -12.56111, - "bbox_y1": 35.504211 - } - }, - { - "pk": 8, - "model": "base.region", - "fields": { - "rght": 260, - "code": "CTA", - "name": "Central Asia", - "parent": 6, - "level": 2, - "lft": 247, - "tree_id": 90, - "bbox_x0": 44.236641, - "bbox_x1": 90.076767, - "bbox_y0": 33.890511, - "bbox_y1": 54.845139 - } - }, - { - "pk": 9, - "model": "base.region", - "fields": { - "rght": 292, - "code": "SAS", - "name": "South Asia", - "parent": 6, - "level": 2, - "lft": 277, - "tree_id": 90, - "bbox_x0": 19.6381, - "bbox_x1": 180, - "bbox_y0": -12.56111, - "bbox_y1": 82.50045 - } - }, - { - "pk": 10, - "model": "base.region", - "fields": { - "rght": 127, - "code": "AFR", - "name": "Africa", - "parent": null, - "level": 1, - "lft": 2, - "tree_id": 90, - "bbox_x0": -25.35874, - "bbox_x1": 63.525379, - "bbox_y0": -46.900452, - "bbox_y1": 37.56712 - } - }, - { - "pk": 11, - "model": "base.region", - "fields": { - "rght": 64, - "code": "NAF", - "name": "North Africa", - "parent": 10, - "level": 2, - "lft": 49, - "tree_id": 90, - "bbox_x0": -17.10317, - "bbox_x1": 38.833801, - "bbox_y0": 3.48639, - "bbox_y1": 37.56712 - } - }, - { - "pk": 12, - "model": "base.region", - "fields": { - "rght": 48, - "code": "EAF", - "name": "East Africa", - "parent": 10, - "level": 2, - "lft": 13, - "tree_id": 90, - "bbox_x0": 22.855089, - "bbox_x1": 63.94656, - "bbox_y0": -25.84763, - "bbox_y1": 17.467039 - } - }, - { - "pk": 13, - "model": "base.region", - "fields": { - "rght": 126, - "code": "WAF", - "name": "West Africa", - "parent": 10, - "level": 2, - "lft": 83, - "tree_id": 90, - "bbox_x0": -26.758421, - "bbox_x1": 24.002661, - "bbox_y0": -9.29925, - "bbox_y1": 27.702801 - } - }, - { - "pk": 14, - "model": "base.region", - "fields": { - "rght": 82, - "code": "SAF", - "name": "Southern Africa", - "parent": 10, - "level": 2, - "lft": 65, - "tree_id": 90, - "bbox_x0": 8.93107, - "bbox_x1": 42.74847, - "bbox_y0": -35.507481, - "bbox_y1": -13.27553 - } - }, - { - "pk": 15, - "model": "base.region", - "fields": { - "rght": 463, - "code": "MES", - "name": "Middle East", - "parent": null, - "level": 1, - "lft": 434, - "tree_id": 90, - "bbox_x0": 24.698099, - "bbox_x1": 63.317459, - "bbox_y0": 12.111, - "bbox_y1": 42.10751 - } - }, - { - "pk": 16, - "model": "base.region", - "fields": { - "rght": 245, - "code": "ANT", - "name": "Antarctica", - "parent": null, - "level": 1, - "lft": 244, - "tree_id": 90, - "bbox_x0": -180, - "bbox_x1": 180, - "bbox_y0": -90, - "bbox_y1": -73 - } - }, - { - "pk": 17, - "model": "base.region", - "fields": { - "rght": 249, - "code": "AFG", - "name": "Afghanistan", - "parent": 8, - "level": 3, - "lft": 248, - "tree_id": 90, - "bbox_x0": 60.478439, - "bbox_x1": 74.879433, - "bbox_y0": 29.37747, - "bbox_y1": 38.483421 - } - }, - { - "pk": 18, - "model": "base.region", - "fields": { - "rght": 320, - "code": "ALA", - "name": "Aland Islands", - "parent": 5, - "level": 2, - "lft": 319, - "tree_id": 90, - "bbox_x0": 19.262711, - "bbox_x1": 21.324409, - "bbox_y0": 59.736301, - "bbox_y1": 60.665581 - } - }, - { - "pk": 19, - "model": "base.region", - "fields": { - "rght": 322, - "code": "ALB", - "name": "Albania", - "parent": 5, - "level": 2, - "lft": 321, - "tree_id": 90, - "bbox_x0": 19.28219, - "bbox_x1": 21.057819, - "bbox_y0": 39.644489, - "bbox_y1": 42.660801 - } - }, - { - "pk": 20, - "model": "base.region", - "fields": { - "rght": 51, - "code": "DZA", - "name": "Algeria", - "parent": 11, - "level": 3, - "lft": 50, - "tree_id": 90, - "bbox_x0": -8.67386, - "bbox_x1": 11.97955, - "bbox_y0": 18.96002, - "bbox_y1": 37.093731 - } - }, - { - "pk": 21, - "model": "base.region", - "fields": { - "rght": 466, - "code": "ASM", - "name": "American Samoa", - "parent": 256, - "level": 2, - "lft": 465, - "tree_id": 90, - "bbox_x0": -171.091873, - "bbox_x1": -169.416077, - "bbox_y0": -14.38247, - "bbox_y1": -11.04969 - } - }, - { - "pk": 22, - "model": "base.region", - "fields": { - "rght": 324, - "code": "AND", - "name": "Andorra", - "parent": 5, - "level": 2, - "lft": 323, - "tree_id": 90, - "bbox_x0": 1.41382, - "bbox_x1": 1.78659, - "bbox_y0": 42.42873, - "bbox_y1": 42.65601 - } - }, - { - "pk": 23, - "model": "base.region", - "fields": { - "rght": 85, - "code": "AGO", - "name": "Angola", - "parent": 13, - "level": 3, - "lft": 84, - "tree_id": 90, - "bbox_x0": 11.6792, - "bbox_x1": 24.082109, - "bbox_y0": -18.04207, - "bbox_y1": -4.37259 - } - }, - { - "pk": 24, - "model": "base.region", - "fields": { - "rght": 131, - "code": "AIA", - "name": "Anguilla", - "parent": 255, - "level": 3, - "lft": 130, - "tree_id": 90, - "bbox_x0": -63.434872, - "bbox_x1": -62.916199, - "bbox_y0": 18.149549, - "bbox_y1": 18.61278 - } - }, - { - "pk": 25, - "model": "base.region", - "fields": { - "rght": 133, - "code": "ATG", - "name": "Antigua and Barbuda", - "parent": 255, - "level": 3, - "lft": 132, - "tree_id": 90, - "bbox_x0": -62.352402, - "bbox_x1": -61.659081, - "bbox_y0": 16.927219, - "bbox_y1": 17.72938 - } - }, - { - "pk": 26, - "model": "base.region", - "fields": { - "rght": 215, - "code": "ARG", - "name": "Argentina", - "parent": 4, - "level": 3, - "lft": 214, - "tree_id": 90, - "bbox_x0": -73.577782, - "bbox_x1": -53.637539, - "bbox_y0": -55.057362, - "bbox_y1": -21.78126 - } - }, - { - "pk": 27, - "model": "base.region", - "fields": { - "rght": 326, - "code": "ARM", - "name": "Armenia", - "parent": 5, - "level": 2, - "lft": 325, - "tree_id": 90, - "bbox_x0": 43.449749, - "bbox_x1": 46.630039, - "bbox_y0": 38.830521, - "bbox_y1": 41.30183 - } - }, - { - "pk": 28, - "model": "base.region", - "fields": { - "rght": 135, - "code": "ABW", - "name": "Aruba", - "parent": 255, - "level": 3, - "lft": 134, - "tree_id": 90, - "bbox_x0": -70.0611, - "bbox_x1": -69.8669, - "bbox_y0": 12.4061, - "bbox_y1": 12.6306 - } - }, - { - "pk": 29, - "model": "base.region", - "fields": { - "rght": 468, - "code": "AUS", - "name": "Australia", - "parent": 256, - "level": 2, - "lft": 467, - "tree_id": 90, - "bbox_x0": 112.921112, - "bbox_x1": 159.278717, - "bbox_y0": -54.640301, - "bbox_y1": -9.22882 - } - }, - { - "pk": 30, - "model": "base.region", - "fields": { - "rght": 328, - "code": "AUT", - "name": "Austria", - "parent": 5, - "level": 2, - "lft": 327, - "tree_id": 90, - "bbox_x0": 9.53079, - "bbox_x1": 17.160749, - "bbox_y0": 46.372299, - "bbox_y1": 49.02071 - } - }, - { - "pk": 31, - "model": "base.region", - "fields": { - "rght": 330, - "code": "AZE", - "name": "Azerbaijan", - "parent": 5, - "level": 2, - "lft": 329, - "tree_id": 90, - "bbox_x0": 44.7719, - "bbox_x1": 50.6078, - "bbox_y0": 38.3970, - "bbox_y1": 41.9056 - } - }, - { - "pk": 32, - "model": "base.region", - "fields": { - "rght": 137, - "code": "BHS", - "name": "Bahamas", - "parent": 255, - "level": 3, - "lft": 136, - "tree_id": 90, - "bbox_x0": -80.499229, - "bbox_x1": -72.649513, - "bbox_y0": 20.916059, - "bbox_y1": 27.933781 - } - }, - { - "pk": 33, - "model": "base.region", - "fields": { - "rght": 436, - "code": "BHR", - "name": "Bahrain", - "parent": 15, - "level": 2, - "lft": 435, - "tree_id": 90, - "bbox_x0": 50.385799, - "bbox_x1": 50.828499, - "bbox_y0": 25.5422, - "bbox_y1": 26.292391 - } - }, - { - "pk": 34, - "model": "base.region", - "fields": { - "rght": 279, - "code": "BGD", - "name": "Bangladesh", - "parent": 9, - "level": 3, - "lft": 278, - "tree_id": 90, - "bbox_x0": 88.028198, - "bbox_x1": 92.673599, - "bbox_y0": 20.585199, - "bbox_y1": 26.631701 - } - }, - { - "pk": 35, - "model": "base.region", - "fields": { - "rght": 139, - "code": "BRB", - "name": "Barbados", - "parent": 255, - "level": 3, - "lft": 138, - "tree_id": 90, - "bbox_x0": -59.648918, - "bbox_x1": -59.420368, - "bbox_y0": 13.03984, - "bbox_y1": 13.32725 - } - }, - { - "pk": 36, - "model": "base.region", - "fields": { - "rght": 332, - "code": "BLR", - "name": "Belarus", - "parent": 5, - "level": 2, - "lft": 331, - "tree_id": 90, - "bbox_x0": 23.17679, - "bbox_x1": 32.77071, - "bbox_y0": 51.256401, - "bbox_y1": 56.16571 - } - }, - { - "pk": 37, - "model": "base.region", - "fields": { - "rght": 334, - "code": "BEL", - "name": "Belgium", - "parent": 5, - "level": 2, - "lft": 333, - "tree_id": 90, - "bbox_x0": 2.54563, - "bbox_x1": 6.40791, - "bbox_y0": 49.496899, - "bbox_y1": 51.505081 - } - }, - { - "pk": 38, - "model": "base.region", - "fields": { - "rght": 189, - "code": "BLZ", - "name": "Belize", - "parent": 3, - "level": 3, - "lft": 188, - "tree_id": 90, - "bbox_x0": -89.224823, - "bbox_x1": -87.468132, - "bbox_y0": 15.8893, - "bbox_y1": 18.49655 - } - }, - { - "pk": 39, - "model": "base.region", - "fields": { - "rght": 87, - "code": "BEN", - "name": "Benin", - "parent": 13, - "level": 3, - "lft": 86, - "tree_id": 90, - "bbox_x0": 0.77456, - "bbox_x1": 3.8517, - "bbox_y0": 6.22574, - "bbox_y1": 12.41834 - } - }, - { - "pk": 40, - "model": "base.region", - "fields": { - "rght": 141, - "code": "BMU", - "name": "Bermuda", - "parent": 255, - "level": 3, - "lft": 140, - "tree_id": 90, - "bbox_x0": -64.896042, - "bbox_x1": -64.642952, - "bbox_y0": 32.230709, - "bbox_y1": 32.393829 - } - }, - { - "pk": 41, - "model": "base.region", - "fields": { - "rght": 281, - "code": "BTN", - "name": "Bhutan", - "parent": 9, - "level": 3, - "lft": 280, - "tree_id": 90, - "bbox_x0": 88.759521, - "bbox_x1": 92.125023, - "bbox_y0": 26.7075, - "bbox_y1": 28.3235 - } - }, - { - "pk": 42, - "model": "base.region", - "fields": { - "rght": 217, - "code": "BOL", - "name": "Bolivia", - "parent": 4, - "level": 3, - "lft": 216, - "tree_id": 90, - "bbox_x0": -69.640762, - "bbox_x1": -57.458092, - "bbox_y0": -22.89613, - "bbox_y1": -9.68056 - } - }, - { - "pk": 43, - "model": "base.region", - "fields": { - "rght": 336, - "code": "BIH", - "name": "Bosnia and Herzegovina", - "parent": 5, - "level": 2, - "lft": 335, - "tree_id": 90, - "bbox_x0": 15.74909, - "bbox_x1": 19.62907, - "bbox_y0": 42.56451, - "bbox_y1": 45.276001 - } - }, - { - "pk": 44, - "model": "base.region", - "fields": { - "rght": 67, - "code": "BWA", - "name": "Botswana", - "parent": 14, - "level": 3, - "lft": 66, - "tree_id": 90, - "bbox_x0": 19.999531, - "bbox_x1": 29.360781, - "bbox_y0": -26.90724, - "bbox_y1": -17.780809 - } - }, - { - "pk": 45, - "model": "base.region", - "fields": { - "rght": 219, - "code": "BRA", - "name": "Brazil", - "parent": 4, - "level": 3, - "lft": 218, - "tree_id": 90, - "bbox_x0": -73.985527, - "bbox_x1": -28.839041, - "bbox_y0": -33.750702, - "bbox_y1": 5.26486 - } - }, - { - "pk": 46, - "model": "base.region", - "fields": { - "rght": 143, - "code": "VGB", - "name": "British Virgin Islands", - "parent": 255, - "level": 3, - "lft": 142, - "tree_id": 90, - "bbox_x0": -64.783012, - "bbox_x1": -64.268761, - "bbox_y0": 18.312731, - "bbox_y1": 18.757219 - } - }, - { - "pk": 47, - "model": "base.region", - "fields": { - "rght": 295, - "code": "BRN", - "name": "Brunei Darussalam", - "parent": 7, - "level": 3, - "lft": 294, - "tree_id": 90, - "bbox_x0": 114.071457, - "bbox_x1": 115.359451, - "bbox_y0": 4.00309, - "bbox_y1": 5.04717 - } - }, - { - "pk": 48, - "model": "base.region", - "fields": { - "rght": 338, - "code": "BGR", - "name": "Bulgaria", - "parent": 5, - "level": 2, - "lft": 337, - "tree_id": 90, - "bbox_x0": 22.35741, - "bbox_x1": 28.60882, - "bbox_y0": 41.235931, - "bbox_y1": 44.227261 - } - }, - { - "pk": 49, - "model": "base.region", - "fields": { - "rght": 89, - "code": "BFA", - "name": "Burkina Faso", - "parent": 13, - "level": 3, - "lft": 88, - "tree_id": 90, - "bbox_x0": -5.51891, - "bbox_x1": 2.40539, - "bbox_y0": 9.4011, - "bbox_y1": 15.08259 - } - }, - { - "pk": 50, - "model": "base.region", - "fields": { - "rght": 15, - "code": "BDI", - "name": "Burundi", - "parent": 12, - "level": 3, - "lft": 14, - "tree_id": 90, - "bbox_x0": 28.993071, - "bbox_x1": 30.847719, - "bbox_y0": -4.46571, - "bbox_y1": -2.31012 - } - }, - { - "pk": 51, - "model": "base.region", - "fields": { - "rght": 297, - "code": "KHM", - "name": "Cambodia", - "parent": 7, - "level": 3, - "lft": 296, - "tree_id": 90, - "bbox_x0": 102.340012, - "bbox_x1": 107.627724, - "bbox_y0": 9.28325, - "bbox_y1": 14.6864 - } - }, - { - "pk": 52, - "model": "base.region", - "fields": { - "rght": 91, - "code": "CMR", - "name": "Cameroon", - "parent": 13, - "level": 3, - "lft": 90, - "tree_id": 90, - "bbox_x0": 8.49477, - "bbox_x1": 16.19211, - "bbox_y0": 1.65254, - "bbox_y1": 13.07805 - } - }, - { - "pk": 53, - "model": "base.region", - "fields": { - "rght": 205, - "code": "CAN", - "name": "Canada", - "parent": 2, - "level": 3, - "lft": 204, - "tree_id": 90, - "bbox_x0": -141.002701, - "bbox_x1": -52.620201, - "bbox_y0": 41.681019, - "bbox_y1": 83.110619 - } - }, - { - "pk": 54, - "model": "base.region", - "fields": { - "rght": 93, - "code": "CPV", - "name": "Cape Verde", - "parent": 13, - "level": 3, - "lft": 92, - "tree_id": 90, - "bbox_x0": -25.35874, - "bbox_x1": -22.666201, - "bbox_y0": 14.80221, - "bbox_y1": 17.19717 - } - }, - { - "pk": 55, - "model": "base.region", - "fields": { - "rght": 145, - "code": "CYM", - "name": "Cayman Islands", - "parent": 255, - "level": 3, - "lft": 144, - "tree_id": 90, - "bbox_x0": -81.420593, - "bbox_x1": -79.722321, - "bbox_y0": 19.262659, - "bbox_y1": 19.75738 - } - }, - { - "pk": 56, - "model": "base.region", - "fields": { - "rght": 5, - "code": "CAF", - "name": "Central African Republic", - "parent": 257, - "level": 3, - "lft": 4, - "tree_id": 90, - "bbox_x0": 14.42009, - "bbox_x1": 27.463421, - "bbox_y0": 2.22051, - "bbox_y1": 11.00756 - } - }, - { - "pk": 57, - "model": "base.region", - "fields": { - "rght": 7, - "code": "TCD", - "name": "Chad", - "parent": 257, - "level": 3, - "lft": 6, - "tree_id": 90, - "bbox_x0": 13.47592, - "bbox_x1": 24.00161, - "bbox_y0": 7.44237, - "bbox_y1": 23.478239 - } - }, - { - "pk": 58, - "model": "base.region", - "fields": { - "rght": 340, - "code": "CIL", - "name": "Channel Islands", - "parent": 5, - "level": 2, - "lft": 339, - "tree_id": 90, - "bbox_x0": -2.67545, - "bbox_x1": -2.01129, - "bbox_y0": 49.16209, - "bbox_y1": 49.7393 - } - }, - { - "pk": 59, - "model": "base.region", - "fields": { - "rght": 221, - "code": "CHL", - "name": "Chile", - "parent": 4, - "level": 3, - "lft": 220, - "tree_id": 90, - "bbox_x0": -109.47493, - "bbox_x1": -66.417549, - "bbox_y0": -56.533779, - "bbox_y1": -17.507549 - } - }, - { - "pk": 60, - "model": "base.region", - "fields": { - "rght": 263, - "code": "CHN", - "name": "China", - "parent": 258, - "level": 3, - "lft": 262, - "tree_id": 90, - "bbox_x0": 73.557701, - "bbox_x1": 134.773605, - "bbox_y0": 15.77539, - "bbox_y1": 53.5606 - } - }, - { - "pk": 61, - "model": "base.region", - "fields": { - "rght": 265, - "code": "HKG", - "name": "China - Hong Kong", - "parent": 258, - "level": 3, - "lft": 264, - "tree_id": 90, - "bbox_x0": 113.835083, - "bbox_x1": 114.441788, - "bbox_y0": 22.153549, - "bbox_y1": 22.56204 - } - }, - { - "pk": 62, - "model": "base.region", - "fields": { - "rght": 267, - "code": "MAC", - "name": "China - Macao", - "parent": 258, - "level": 3, - "lft": 266, - "tree_id": 90, - "bbox_x0": 113.528351, - "bbox_x1": 113.598297, - "bbox_y0": 22.10977, - "bbox_y1": 22.21697 - } - }, - { - "pk": 63, - "model": "base.region", - "fields": { - "rght": 223, - "code": "COL", - "name": "Colombia", - "parent": 4, - "level": 3, - "lft": 222, - "tree_id": 90, - "bbox_x0": -81.728111, - "bbox_x1": -66.869827, - "bbox_y0": -4.23048, - "bbox_y1": 13.39029 - } - }, - { - "pk": 64, - "model": "base.region", - "fields": { - "rght": 17, - "code": "COM", - "name": "Comoros", - "parent": 12, - "level": 3, - "lft": 16, - "tree_id": 90, - "bbox_x0": 43.215778, - "bbox_x1": 44.538219, - "bbox_y0": -12.41382, - "bbox_y1": -11.36238 - } - }, - { - "pk": 65, - "model": "base.region", - "fields": { - "rght": 9, - "code": "COG", - "name": "Congo", - "parent": 257, - "level": 3, - "lft": 8, - "tree_id": 90, - "bbox_x0": 11.205, - "bbox_x1": 18.64983, - "bbox_y0": -5.02831, - "bbox_y1": 3.70308 - } - }, - { - "pk": 66, - "model": "base.region", - "fields": { - "rght": 470, - "code": "COK", - "name": "Cook Islands", - "parent": 256, - "level": 2, - "lft": 469, - "tree_id": 90, - "bbox_x0": -165.858093, - "bbox_x1": -157.312119, - "bbox_y0": -21.94416, - "bbox_y1": -8.94402 - } - }, - { - "pk": 67, - "model": "base.region", - "fields": { - "rght": 191, - "code": "CRI", - "name": "Costa Rica", - "parent": 3, - "level": 3, - "lft": 190, - "tree_id": 90, - "bbox_x0": -87.083778, - "bbox_x1": -82.556, - "bbox_y0": 5.49955, - "bbox_y1": 11.21681 - } - }, - { - "pk": 68, - "model": "base.region", - "fields": { - "rght": 95, - "code": "CIV", - "name": "Cote d'Ivoire", - "parent": 13, - "level": 3, - "lft": 94, - "tree_id": 90, - "bbox_x0": -8.6017249, - "bbox_x1": -2.4930309, - "bbox_y0": 4.1642077, - "bbox_y1": 10.740015 - } - }, - { - "pk": 69, - "model": "base.region", - "fields": { - "rght": 342, - "code": "HRV", - "name": "Croatia", - "parent": 5, - "level": 2, - "lft": 341, - "tree_id": 90, - "bbox_x0": 13.48972, - "bbox_x1": 19.44722, - "bbox_y0": 42.392208, - "bbox_y1": 46.554981 - } - }, - { - "pk": 70, - "model": "base.region", - "fields": { - "rght": 147, - "code": "CUB", - "name": "Cuba", - "parent": 255, - "level": 3, - "lft": 146, - "tree_id": 90, - "bbox_x0": -84.957428, - "bbox_x1": -74.131783, - "bbox_y0": 19.828079, - "bbox_y1": 23.283779 - } - }, - { - "pk": 71, - "model": "base.region", - "fields": { - "rght": 344, - "code": "CYP", - "name": "Cyprus", - "parent": 5, - "level": 2, - "lft": 343, - "tree_id": 90, - "bbox_x0": 32.27309, - "bbox_x1": 34.597919, - "bbox_y0": 34.563511, - "bbox_y1": 35.701542 - } - }, - { - "pk": 72, - "model": "base.region", - "fields": { - "rght": 346, - "code": "CZE", - "name": "Czech Republic", - "parent": 5, - "level": 2, - "lft": 345, - "tree_id": 90, - "bbox_x0": 12.0905901, - "bbox_x1": 18.859216, - "bbox_y0": 48.5518144, - "bbox_y1": 51.0557036 - } - }, - { - "pk": 73, - "model": "base.region", - "fields": { - "rght": 269, - "code": "PRK", - "name": "Democratic People's Republic of Korea", - "parent": 258, - "level": 3, - "lft": 268, - "tree_id": 90, - "bbox_x0": 124.182739, - "bbox_x1": 130.674713, - "bbox_y0": 37.632881, - "bbox_y1": 43.006001 - } - }, - { - "pk": 74, - "model": "base.region", - "fields": { - "rght": 11, - "code": "COD", - "name": "Democratic Republic of the Congo", - "parent": 257, - "level": 3, - "lft": 10, - "tree_id": 90, - "bbox_x0": 12.20663, - "bbox_x1": 31.30591, - "bbox_y0": -13.45567, - "bbox_y1": 5.38609 - } - }, - { - "pk": 75, - "model": "base.region", - "fields": { - "rght": 348, - "code": "DNK", - "name": "Denmark", - "parent": 5, - "level": 2, - "lft": 347, - "tree_id": 90, - "bbox_x0": 8.07472, - "bbox_x1": 15.19324, - "bbox_y0": 54.559132, - "bbox_y1": 57.751949 - } - }, - { - "pk": 76, - "model": "base.region", - "fields": { - "rght": 19, - "code": "DJI", - "name": "Djibouti", - "parent": 12, - "level": 3, - "lft": 18, - "tree_id": 90, - "bbox_x0": 41.773441, - "bbox_x1": 43.450459, - "bbox_y0": 10.90991, - "bbox_y1": 12.70683 - } - }, - { - "pk": 77, - "model": "base.region", - "fields": { - "rght": 149, - "code": "DMA", - "name": "Dominica", - "parent": 255, - "level": 3, - "lft": 148, - "tree_id": 90, - "bbox_x0": -61.4841, - "bbox_x1": -61.244148, - "bbox_y0": 15.20168, - "bbox_y1": 15.6318 - } - }, - { - "pk": 78, - "model": "base.region", - "fields": { - "rght": 151, - "code": "DOM", - "name": "Dominican Republic", - "parent": 255, - "level": 3, - "lft": 150, - "tree_id": 90, - "bbox_x0": -72.003479, - "bbox_x1": -68.319992, - "bbox_y0": 17.469299, - "bbox_y1": 19.92985 - } - }, - { - "pk": 79, - "model": "base.region", - "fields": { - "rght": 225, - "code": "ECU", - "name": "Ecuador", - "parent": 4, - "level": 3, - "lft": 224, - "tree_id": 90, - "bbox_x0": -91.66124, - "bbox_x1": -75.200073, - "bbox_y0": -5.01734, - "bbox_y1": 1.45421 - } - }, - { - "pk": 80, - "model": "base.region", - "fields": { - "rght": 53, - "code": "EGY", - "name": "Egypt", - "parent": 11, - "level": 3, - "lft": 52, - "tree_id": 90, - "bbox_x0": 24.698099, - "bbox_x1": 36.89468, - "bbox_y0": 22, - "bbox_y1": 31.674179 - } - }, - { - "pk": 81, - "model": "base.region", - "fields": { - "rght": 193, - "code": "SLV", - "name": "El Salvador", - "parent": 3, - "level": 3, - "lft": 192, - "tree_id": 90, - "bbox_x0": -90.12867, - "bbox_x1": -87.682869, - "bbox_y0": 13.14867, - "bbox_y1": 14.44506 - } - }, - { - "pk": 82, - "model": "base.region", - "fields": { - "rght": 97, - "code": "GNQ", - "name": "Equatorial Guinea", - "parent": 13, - "level": 3, - "lft": 96, - "tree_id": 90, - "bbox_x0": 5.60236, - "bbox_x1": 11.33572, - "bbox_y0": -1.48378, - "bbox_y1": 3.78597 - } - }, - { - "pk": 83, - "model": "base.region", - "fields": { - "rght": 21, - "code": "ERI", - "name": "Eritrea", - "parent": 12, - "level": 3, - "lft": 20, - "tree_id": 90, - "bbox_x0": 36.43877, - "bbox_x1": 43.14864, - "bbox_y0": 12.35956, - "bbox_y1": 18.00308 - } - }, - { - "pk": 84, - "model": "base.region", - "fields": { - "rght": 350, - "code": "EST", - "name": "Estonia", - "parent": 5, - "level": 2, - "lft": 349, - "tree_id": 90, - "bbox_x0": 21.771851, - "bbox_x1": 28.20989, - "bbox_y0": 57.509312, - "bbox_y1": 59.685749 - } - }, - { - "pk": 85, - "model": "base.region", - "fields": { - "rght": 23, - "code": "ETH", - "name": "Ethiopia", - "parent": 12, - "level": 3, - "lft": 22, - "tree_id": 90, - "bbox_x0": 32.99992, - "bbox_x1": 47.986172, - "bbox_y0": 3.40242, - "bbox_y1": 14.89218 - } - }, - { - "pk": 86, - "model": "base.region", - "fields": { - "rght": 352, - "code": "FRO", - "name": "Faeroe Islands", - "parent": 5, - "level": 2, - "lft": 351, - "tree_id": 90, - "bbox_x0": -7.68124, - "bbox_x1": -6.25861, - "bbox_y0": 61.394932, - "bbox_y1": 62.400742 - } - }, - { - "pk": 87, - "model": "base.region", - "fields": { - "rght": 227, - "code": "FLK", - "name": "Falkland Islands (Malvinas)", - "parent": 4, - "level": 3, - "lft": 226, - "tree_id": 90, - "bbox_x0": -61.43404, - "bbox_x1": -57.712479, - "bbox_y0": -52.900581, - "bbox_y1": -50.966221 - } - }, - { - "pk": 88, - "model": "base.region", - "fields": { - "rght": 472, - "code": "FJI", - "name": "Fiji", - "parent": 256, - "level": 2, - "lft": 471, - "tree_id": 90, - "bbox_x0": 174.866196, - "bbox_x1": -178.203156, - "bbox_y0": -21.01712, - "bbox_y1": -12.46622 - } - }, - { - "pk": 89, - "model": "base.region", - "fields": { - "rght": 354, - "code": "FIN", - "name": "Finland", - "parent": 5, - "level": 2, - "lft": 353, - "tree_id": 90, - "bbox_x0": 20.548571, - "bbox_x1": 31.586201, - "bbox_y0": 59.764881, - "bbox_y1": 70.092308 - } - }, - { - "pk": 90, - "model": "base.region", - "fields": { - "rght": 356, - "code": "FRA", - "name": "France", - "parent": 5, - "level": 2, - "lft": 355, - "tree_id": 90, - "bbox_x0": -5.1406, - "bbox_x1": 9.55932, - "bbox_y0": 41.33374, - "bbox_y1": 51.089062 - } - }, - { - "pk": 91, - "model": "base.region", - "fields": { - "rght": 229, - "code": "GUF", - "name": "French Guiana", - "parent": 4, - "level": 3, - "lft": 228, - "tree_id": 90, - "bbox_x0": -54.542511, - "bbox_x1": -51.613941, - "bbox_y0": 2.12709, - "bbox_y1": 5.77649 - } - }, - { - "pk": 92, - "model": "base.region", - "fields": { - "rght": 474, - "code": "PYF", - "name": "French Polynesia", - "parent": 256, - "level": 2, - "lft": 473, - "tree_id": 90, - "bbox_x0": -154.700485, - "bbox_x1": -108.87291, - "bbox_y0": -27.65357, - "bbox_y1": 10.35983 - } - }, - { - "pk": 93, - "model": "base.region", - "fields": { - "rght": 99, - "code": "GAB", - "name": "Gabon", - "parent": 13, - "level": 3, - "lft": 98, - "tree_id": 90, - "bbox_x0": 8.69547, - "bbox_x1": 14.50234, - "bbox_y0": -3.9788, - "bbox_y1": 2.32261 - } - }, - { - "pk": 94, - "model": "base.region", - "fields": { - "rght": 101, - "code": "GMB", - "name": "Gambia", - "parent": 13, - "level": 3, - "lft": 100, - "tree_id": 90, - "bbox_x0": -16.82506, - "bbox_x1": -13.7978, - "bbox_y0": 13.06425, - "bbox_y1": 13.82657 - } - }, - { - "pk": 95, - "model": "base.region", - "fields": { - "rght": 358, - "code": "GEO", - "name": "Georgia", - "parent": 5, - "level": 2, - "lft": 357, - "tree_id": 90, - "bbox_x0": 40.01022, - "bbox_x1": 46.721359, - "bbox_y0": 41.038502, - "bbox_y1": 43.584549 - } - }, - { - "pk": 96, - "model": "base.region", - "fields": { - "rght": 360, - "code": "DEU", - "name": "Germany", - "parent": 5, - "level": 2, - "lft": 359, - "tree_id": 90, - "bbox_x0": 5.86624, - "bbox_x1": 15.04205, - "bbox_y0": 47.27021, - "bbox_y1": 55.05814 - } - }, - { - "pk": 97, - "model": "base.region", - "fields": { - "rght": 103, - "code": "GHA", - "name": "Ghana", - "parent": 13, - "level": 3, - "lft": 102, - "tree_id": 90, - "bbox_x0": -3.25542, - "bbox_x1": 1.19178, - "bbox_y0": 4.73672, - "bbox_y1": 11.1733 - } - }, - { - "pk": 98, - "model": "base.region", - "fields": { - "rght": 362, - "code": "GIB", - "name": "Gibraltar", - "parent": 5, - "level": 2, - "lft": 361, - "tree_id": 90, - "bbox_x0": -5.3579, - "bbox_x1": -5.33867, - "bbox_y0": 36.108219, - "bbox_y1": 36.15593 - } - }, - { - "pk": 99, - "model": "base.region", - "fields": { - "rght": 364, - "code": "GRC", - "name": "Greece", - "parent": 5, - "level": 2, - "lft": 363, - "tree_id": 90, - "bbox_x0": 19.37431, - "bbox_x1": 29.70056, - "bbox_y0": 34.809502, - "bbox_y1": 41.757111 - } - }, - { - "pk": 100, - "model": "base.region", - "fields": { - "rght": 207, - "code": "GRL", - "name": "Greenland", - "parent": 2, - "level": 3, - "lft": 206, - "tree_id": 90, - "bbox_x0": -73.263474, - "bbox_x1": -11.31232, - "bbox_y0": 59.777271, - "bbox_y1": 83.627419 - } - }, - { - "pk": 101, - "model": "base.region", - "fields": { - "rght": 153, - "code": "GRD", - "name": "Grenada", - "parent": 255, - "level": 3, - "lft": 152, - "tree_id": 90, - "bbox_x0": -61.79998, - "bbox_x1": -61.376362, - "bbox_y0": 11.98288, - "bbox_y1": 12.5415 - } - }, - { - "pk": 102, - "model": "base.region", - "fields": { - "rght": 155, - "code": "GLP", - "name": "Guadeloupe", - "parent": 255, - "level": 3, - "lft": 154, - "tree_id": 90, - "bbox_x0": -61.807159, - "bbox_x1": -61, - "bbox_y0": 15.83097, - "bbox_y1": 16.51684 - } - }, - { - "pk": 103, - "model": "base.region", - "fields": { - "rght": 476, - "code": "GUM", - "name": "Guam", - "parent": 256, - "level": 2, - "lft": 475, - "tree_id": 90, - "bbox_x0": 144.619263, - "bbox_x1": 144.953995, - "bbox_y0": 13.24059, - "bbox_y1": 13.65232 - } - }, - { - "pk": 104, - "model": "base.region", - "fields": { - "rght": 195, - "code": "GTM", - "name": "Guatemala", - "parent": 3, - "level": 3, - "lft": 194, - "tree_id": 90, - "bbox_x0": -92.241432, - "bbox_x1": -88.22319, - "bbox_y0": 13.7373, - "bbox_y1": 17.815201 - } - }, - { - "pk": 105, - "model": "base.region", - "fields": { - "rght": 366, - "code": "GGY", - "name": "Guernsey", - "parent": 5, - "level": 2, - "lft": 365, - "tree_id": 90, - "bbox_x0": -2.67545, - "bbox_x1": -2.16382, - "bbox_y0": 49.405762, - "bbox_y1": 49.7393 - } - }, - { - "pk": 106, - "model": "base.region", - "fields": { - "rght": 105, - "code": "GIN", - "name": "Guinea", - "parent": 13, - "level": 3, - "lft": 104, - "tree_id": 90, - "bbox_x0": -15.08625, - "bbox_x1": -7.64106, - "bbox_y0": 7.19355, - "bbox_y1": 12.67621 - } - }, - { - "pk": 107, - "model": "base.region", - "fields": { - "rght": 107, - "code": "GNB", - "name": "Guinea-Bissau", - "parent": 13, - "level": 3, - "lft": 106, - "tree_id": 90, - "bbox_x0": -16.717529, - "bbox_x1": -13.63652, - "bbox_y0": 10.85997, - "bbox_y1": 12.68078 - } - }, - { - "pk": 108, - "model": "base.region", - "fields": { - "rght": 231, - "code": "GUY", - "name": "Guyana", - "parent": 4, - "level": 3, - "lft": 230, - "tree_id": 90, - "bbox_x0": -61.396271, - "bbox_x1": -56.480251, - "bbox_y0": 1.17508, - "bbox_y1": 8.55756 - } - }, - { - "pk": 109, - "model": "base.region", - "fields": { - "rght": 157, - "code": "HTI", - "name": "Haiti", - "parent": 255, - "level": 3, - "lft": 156, - "tree_id": 90, - "bbox_x0": -74.478592, - "bbox_x1": -71.61335, - "bbox_y0": 18.02103, - "bbox_y1": 20.08782 - } - }, - { - "pk": 110, - "model": "base.region", - "fields": { - "rght": 368, - "code": "VAT", - "name": "Holy See (Vatican City)", - "parent": 5, - "level": 2, - "lft": 367, - "tree_id": 90, - "bbox_x0": 12.44584, - "bbox_x1": 12.45842, - "bbox_y0": 41.900211, - "bbox_y1": 41.907459 - } - }, - { - "pk": 111, - "model": "base.region", - "fields": { - "rght": 197, - "code": "HND", - "name": "Honduras", - "parent": 3, - "level": 3, - "lft": 196, - "tree_id": 90, - "bbox_x0": -89.350792, - "bbox_x1": -82.499527, - "bbox_y0": 12.98241, - "bbox_y1": 17.450451 - } - }, - { - "pk": 112, - "model": "base.region", - "fields": { - "rght": 370, - "code": "HUN", - "name": "Hungary", - "parent": 5, - "level": 2, - "lft": 369, - "tree_id": 90, - "bbox_x0": 16.11335, - "bbox_x1": 22.89657, - "bbox_y0": 45.737061, - "bbox_y1": 48.585258 - } - }, - { - "pk": 113, - "model": "base.region", - "fields": { - "rght": 372, - "code": "ISL", - "name": "Iceland", - "parent": 5, - "level": 2, - "lft": 371, - "tree_id": 90, - "bbox_x0": -24.54652, - "bbox_x1": -13.49416, - "bbox_y0": 63.295952, - "bbox_y1": 66.566193 - } - }, - { - "pk": 114, - "model": "base.region", - "fields": { - "rght": 283, - "code": "IND", - "name": "India", - "parent": 9, - "level": 3, - "lft": 282, - "tree_id": 90, - "bbox_x0": 68.032318, - "bbox_x1": 97.403023, - "bbox_y0": 6.7471, - "bbox_y1": 36.261688 - } - }, - { - "pk": 115, - "model": "base.region", - "fields": { - "rght": 299, - "code": "IDN", - "name": "Indonesia", - "parent": 7, - "level": 3, - "lft": 298, - "tree_id": 90, - "bbox_x0": 94.969833, - "bbox_x1": 141.021805, - "bbox_y0": -11.00485, - "bbox_y1": 6.07573 - } - }, - { - "pk": 116, - "model": "base.region", - "fields": { - "rght": 438, - "code": "IRN", - "name": "Iran", - "parent": 15, - "level": 2, - "lft": 437, - "tree_id": 90, - "bbox_x0": 44.047249, - "bbox_x1": 63.317459, - "bbox_y0": 25.064079, - "bbox_y1": 39.777222 - } - }, - { - "pk": 117, - "model": "base.region", - "fields": { - "rght": 440, - "code": "IRQ", - "name": "Iraq", - "parent": 15, - "level": 2, - "lft": 439, - "tree_id": 90, - "bbox_x0": 38.804001, - "bbox_x1": 48.575699, - "bbox_y0": 29.103001, - "bbox_y1": 37.378052 - } - }, - { - "pk": 118, - "model": "base.region", - "fields": { - "rght": 374, - "code": "IRL", - "name": "Ireland", - "parent": 5, - "level": 2, - "lft": 373, - "tree_id": 90, - "bbox_x0": -10.61834, - "bbox_x1": -5.9975, - "bbox_y0": 51.424511, - "bbox_y1": 55.436211 - } - }, - { - "pk": 119, - "model": "base.region", - "fields": { - "rght": 376, - "code": "IMN", - "name": "Isle of Man", - "parent": 5, - "level": 2, - "lft": 375, - "tree_id": 90, - "bbox_x0": -4.83018, - "bbox_x1": -4.31007, - "bbox_y0": 54.04464, - "bbox_y1": 54.418839 - } - }, - { - "pk": 120, - "model": "base.region", - "fields": { - "rght": 442, - "code": "ISR", - "name": "Israel", - "parent": 15, - "level": 2, - "lft": 441, - "tree_id": 90, - "bbox_x0": 34.2677, - "bbox_x1": 35.940941, - "bbox_y0": 29.4965, - "bbox_y1": 33.43338 - } - }, - { - "pk": 121, - "model": "base.region", - "fields": { - "rght": 378, - "code": "ITA", - "name": "Italy", - "parent": 5, - "level": 2, - "lft": 377, - "tree_id": 90, - "bbox_x0": 6.62665, - "bbox_x1": 18.520281, - "bbox_y0": 35.49308, - "bbox_y1": 47.091999 - } - }, - { - "pk": 122, - "model": "base.region", - "fields": { - "rght": 159, - "code": "JAM", - "name": "Jamaica", - "parent": 255, - "level": 3, - "lft": 158, - "tree_id": 90, - "bbox_x0": -78.366638, - "bbox_x1": -75.982857, - "bbox_y0": 16.949551, - "bbox_y1": 18.52697 - } - }, - { - "pk": 123, - "model": "base.region", - "fields": { - "rght": 271, - "code": "JPN", - "name": "Japan", - "parent": 258, - "level": 3, - "lft": 270, - "tree_id": 90, - "bbox_x0": 122.933647, - "bbox_x1": 153.986847, - "bbox_y0": 20.4251, - "bbox_y1": 45.557709 - } - }, - { - "pk": 124, - "model": "base.region", - "fields": { - "rght": 380, - "code": "JEY", - "name": "Jersey", - "parent": 5, - "level": 2, - "lft": 379, - "tree_id": 90, - "bbox_x0": -2.25505, - "bbox_x1": -2.01129, - "bbox_y0": 49.16209, - "bbox_y1": 49.26231 - } - }, - { - "pk": 125, - "model": "base.region", - "fields": { - "rght": 444, - "code": "JOR", - "name": "Jordan", - "parent": 15, - "level": 2, - "lft": 443, - "tree_id": 90, - "bbox_x0": 34.960232, - "bbox_x1": 39.301128, - "bbox_y0": 29.18409, - "bbox_y1": 33.374828 - } - }, - { - "pk": 126, - "model": "base.region", - "fields": { - "rght": 251, - "code": "KAZ", - "name": "Kazakhstan", - "parent": 8, - "level": 3, - "lft": 250, - "tree_id": 90, - "bbox_x0": 46.491859, - "bbox_x1": 87.312737, - "bbox_y0": 40.566689, - "bbox_y1": 55.431808 - } - }, - { - "pk": 127, - "model": "base.region", - "fields": { - "rght": 25, - "code": "KEN", - "name": "Kenya", - "parent": 12, - "level": 3, - "lft": 24, - "tree_id": 90, - "bbox_x0": 33.90884, - "bbox_x1": 41.899059, - "bbox_y0": -4.71712, - "bbox_y1": 4.62933 - } - }, - { - "pk": 128, - "model": "base.region", - "fields": { - "rght": 478, - "code": "KIR", - "name": "Kiribati", - "parent": 256, - "level": 2, - "lft": 477, - "tree_id": 90, - "bbox_x0": 158.418335, - "bbox_x1": -150.208359, - "bbox_y0": -11.43703, - "bbox_y1": 4.71956 - } - }, - { - "pk": 129, - "model": "base.region", - "fields": { - "rght": 446, - "code": "KWT", - "name": "Kuwait", - "parent": 15, - "level": 2, - "lft": 445, - "tree_id": 90, - "bbox_x0": 46.55751, - "bbox_x1": 48.78384, - "bbox_y0": 28.5245, - "bbox_y1": 30.0958 - } - }, - { - "pk": 130, - "model": "base.region", - "fields": { - "rght": 253, - "code": "KGZ", - "name": "Kyrgyzstan", - "parent": 8, - "level": 3, - "lft": 252, - "tree_id": 90, - "bbox_x0": 69.276619, - "bbox_x1": 80.28318, - "bbox_y0": 39.17284, - "bbox_y1": 43.238239 - } - }, - { - "pk": 131, - "model": "base.region", - "fields": { - "rght": 301, - "code": "LAO", - "name": "Lao People's Democratic Republic", - "parent": 7, - "level": 3, - "lft": 300, - "tree_id": 90, - "bbox_x0": 100.093048, - "bbox_x1": 107.697021, - "bbox_y0": 13.91002, - "bbox_y1": 22.500389 - } - }, - { - "pk": 132, - "model": "base.region", - "fields": { - "rght": 382, - "code": "LVA", - "name": "Latvia", - "parent": 5, - "level": 2, - "lft": 381, - "tree_id": 90, - "bbox_x0": 20.966061, - "bbox_x1": 28.244431, - "bbox_y0": 55.67276, - "bbox_y1": 58.087448 - } - }, - { - "pk": 133, - "model": "base.region", - "fields": { - "rght": 448, - "code": "LBN", - "name": "Lebanon", - "parent": 15, - "level": 2, - "lft": 447, - "tree_id": 90, - "bbox_x0": 35.10368, - "bbox_x1": 36.622791, - "bbox_y0": 33.048908, - "bbox_y1": 34.69268 - } - }, - { - "pk": 134, - "model": "base.region", - "fields": { - "rght": 69, - "code": "LSO", - "name": "Lesotho", - "parent": 14, - "level": 3, - "lft": 68, - "tree_id": 90, - "bbox_x0": 27.02906, - "bbox_x1": 29.465771, - "bbox_y0": -30.668961, - "bbox_y1": -28.57205 - } - }, - { - "pk": 135, - "model": "base.region", - "fields": { - "rght": 109, - "code": "LBR", - "name": "Liberia", - "parent": 13, - "level": 3, - "lft": 108, - "tree_id": 90, - "bbox_x0": -11.49208, - "bbox_x1": -7.36511, - "bbox_y0": 4.35305, - "bbox_y1": 8.55179 - } - }, - { - "pk": 136, - "model": "base.region", - "fields": { - "rght": 55, - "code": "LBY", - "name": "Libyan Arab Jamahiriya", - "parent": 11, - "level": 3, - "lft": 54, - "tree_id": 90, - "bbox_x0": 9.38702, - "bbox_x1": 25.15061, - "bbox_y0": 19.508039, - "bbox_y1": 33.168999 - } - }, - { - "pk": 137, - "model": "base.region", - "fields": { - "rght": 384, - "code": "LIE", - "name": "Liechtenstein", - "parent": 5, - "level": 2, - "lft": 383, - "tree_id": 90, - "bbox_x0": 9.47181, - "bbox_x1": 9.63578, - "bbox_y0": 47.04834, - "bbox_y1": 47.270649 - } - }, - { - "pk": 138, - "model": "base.region", - "fields": { - "rght": 386, - "code": "LTU", - "name": "Lithuania", - "parent": 5, - "level": 2, - "lft": 385, - "tree_id": 90, - "bbox_x0": 20.953199, - "bbox_x1": 26.835581, - "bbox_y0": 53.89748, - "bbox_y1": 56.450432 - } - }, - { - "pk": 139, - "model": "base.region", - "fields": { - "rght": 388, - "code": "LUX", - "name": "Luxembourg", - "parent": 5, - "level": 2, - "lft": 387, - "tree_id": 90, - "bbox_x0": 5.73579, - "bbox_x1": 6.53117, - "bbox_y0": 49.447689, - "bbox_y1": 50.182751 - } - }, - { - "pk": 140, - "model": "base.region", - "fields": { - "rght": 390, - "code": "MKD", - "name": "Macedonia", - "parent": 5, - "level": 2, - "lft": 389, - "tree_id": 90, - "bbox_x0": 20.4645, - "bbox_x1": 23.038071, - "bbox_y0": 40.860111, - "bbox_y1": 42.345501 - } - }, - { - "pk": 141, - "model": "base.region", - "fields": { - "rght": 27, - "code": "MDG", - "name": "Madagascar", - "parent": 12, - "level": 3, - "lft": 26, - "tree_id": 90, - "bbox_x0": 43.19138, - "bbox_x1": 50.483799, - "bbox_y0": -25.60894, - "bbox_y1": -11.94543 - } - }, - { - "pk": 142, - "model": "base.region", - "fields": { - "rght": 29, - "code": "MWI", - "name": "Malawi", - "parent": 12, - "level": 3, - "lft": 28, - "tree_id": 90, - "bbox_x0": 32.668991, - "bbox_x1": 35.920441, - "bbox_y0": -17.129459, - "bbox_y1": -9.36468 - } - }, - { - "pk": 143, - "model": "base.region", - "fields": { - "rght": 303, - "code": "MYS", - "name": "Malaysia", - "parent": 7, - "level": 3, - "lft": 302, - "tree_id": 90, - "bbox_x0": 98.935059, - "bbox_x1": 119.448433, - "bbox_y0": 0.66364, - "bbox_y1": 7.58378 - } - }, - { - "pk": 144, - "model": "base.region", - "fields": { - "rght": 285, - "code": "MDV", - "name": "Maldives", - "parent": 9, - "level": 3, - "lft": 284, - "tree_id": 90, - "bbox_x0": 72.616219, - "bbox_x1": 73.76712, - "bbox_y0": -2.90045, - "bbox_y1": 7.11712 - } - }, - { - "pk": 145, - "model": "base.region", - "fields": { - "rght": 111, - "code": "MLI", - "name": "Mali", - "parent": 13, - "level": 3, - "lft": 110, - "tree_id": 90, - "bbox_x0": -12.24261, - "bbox_x1": 4.24495, - "bbox_y0": 10.15951, - "bbox_y1": 25 - } - }, - { - "pk": 146, - "model": "base.region", - "fields": { - "rght": 392, - "code": "MLT", - "name": "Malta", - "parent": 5, - "level": 2, - "lft": 391, - "tree_id": 90, - "bbox_x0": 14.18341, - "bbox_x1": 14.5766, - "bbox_y0": 35.786282, - "bbox_y1": 36.081821 - } - }, - { - "pk": 147, - "model": "base.region", - "fields": { - "rght": 480, - "code": "MHL", - "name": "Marshall Islands", - "parent": 256, - "level": 2, - "lft": 479, - "tree_id": 90, - "bbox_x0": 162.143265, - "bbox_x1": 172.161987, - "bbox_y0": 4.57487, - "bbox_y1": 14.65516 - } - }, - { - "pk": 148, - "model": "base.region", - "fields": { - "rght": 161, - "code": "MTQ", - "name": "Martinique", - "parent": 255, - "level": 3, - "lft": 160, - "tree_id": 90, - "bbox_x0": -61.23011, - "bbox_x1": -60.81551, - "bbox_y0": 14.38244, - "bbox_y1": 14.87881 - } - }, - { - "pk": 149, - "model": "base.region", - "fields": { - "rght": 113, - "code": "MRT", - "name": "Mauritania", - "parent": 13, - "level": 3, - "lft": 112, - "tree_id": 90, - "bbox_x0": -17.066521, - "bbox_x1": -4.8352, - "bbox_y0": 14.71554, - "bbox_y1": 27.298071 - } - }, - { - "pk": 150, - "model": "base.region", - "fields": { - "rght": 31, - "code": "MUS", - "name": "Mauritius", - "parent": 12, - "level": 3, - "lft": 30, - "tree_id": 90, - "bbox_x0": 56.512711, - "bbox_x1": 63.525379, - "bbox_y0": -20.525709, - "bbox_y1": -10.31925 - } - }, - { - "pk": 151, - "model": "base.region", - "fields": { - "rght": 33, - "code": "MYT", - "name": "Mayotte", - "parent": 12, - "level": 3, - "lft": 32, - "tree_id": 90, - "bbox_x0": 45.01461, - "bbox_x1": 45.317131, - "bbox_y0": -13.00045, - "bbox_y1": -12.63383 - } - }, - { - "pk": 152, - "model": "base.region", - "fields": { - "rght": 209, - "code": "MEX", - "name": "Mexico", - "parent": 2, - "level": 3, - "lft": 208, - "tree_id": 90, - "bbox_x0": -118.867172, - "bbox_x1": -86.703392, - "bbox_y0": 14.53285, - "bbox_y1": 32.71862 - } - }, - { - "pk": 153, - "model": "base.region", - "fields": { - "rght": 482, - "code": "FSM", - "name": "Micronesia, Federated States of", - "parent": 256, - "level": 2, - "lft": 481, - "tree_id": 90, - "bbox_x0": 138.052856, - "bbox_x1": 163.034912, - "bbox_y0": 5.25984, - "bbox_y1": 10.02222 - } - }, - { - "pk": 154, - "model": "base.region", - "fields": { - "rght": 394, - "code": "MCO", - "name": "Monaco", - "parent": 5, - "level": 2, - "lft": 393, - "tree_id": 90, - "bbox_x0": 7.4091, - "bbox_x1": 7.43948, - "bbox_y0": 43.724789, - "bbox_y1": 43.7519 - } - }, - { - "pk": 155, - "model": "base.region", - "fields": { - "rght": 273, - "code": "MNG", - "name": "Mongolia", - "parent": 258, - "level": 3, - "lft": 272, - "tree_id": 90, - "bbox_x0": 87.749496, - "bbox_x1": 119.92411, - "bbox_y0": 41.567501, - "bbox_y1": 52.154099 - } - }, - { - "pk": 156, - "model": "base.region", - "fields": { - "rght": 396, - "code": "MNE", - "name": "Montenegro", - "parent": 5, - "level": 2, - "lft": 395, - "tree_id": 90, - "bbox_x0": 18.43705, - "bbox_x1": 20.41608, - "bbox_y0": 41.84808, - "bbox_y1": 43.542912 - } - }, - { - "pk": 157, - "model": "base.region", - "fields": { - "rght": 163, - "code": "MSR", - "name": "Montserrat", - "parent": 255, - "level": 3, - "lft": 162, - "tree_id": 90, - "bbox_x0": -62.24258, - "bbox_x1": -62.14642, - "bbox_y0": 16.671, - "bbox_y1": 16.81732 - } - }, - { - "pk": 158, - "model": "base.region", - "fields": { - "rght": 57, - "code": "MAR", - "name": "Morocco", - "parent": 11, - "level": 3, - "lft": 56, - "tree_id": 90, - "bbox_x0": -11.7805, - "bbox_x1": -1.02441, - "bbox_y0": 26.946489, - "bbox_y1": 35.921909 - } - }, - { - "pk": 159, - "model": "base.region", - "fields": { - "rght": 35, - "code": "MOZ", - "name": "Mozambique", - "parent": 12, - "level": 3, - "lft": 34, - "tree_id": 90, - "bbox_x0": 30.21731, - "bbox_x1": 40.844471, - "bbox_y0": -26.868679, - "bbox_y1": -10.47188 - } - }, - { - "pk": 160, - "model": "base.region", - "fields": { - "rght": 305, - "code": "MMR", - "name": "Myanmar", - "parent": 7, - "level": 3, - "lft": 304, - "tree_id": 90, - "bbox_x0": 92.189209, - "bbox_x1": 101.176788, - "bbox_y0": 9.60035, - "bbox_y1": 28.543249 - } - }, - { - "pk": 161, - "model": "base.region", - "fields": { - "rght": 71, - "code": "NMB", - "name": "Namibia", - "parent": 14, - "level": 3, - "lft": 70, - "tree_id": 90, - "bbox_x0": 11.71563, - "bbox_x1": 25.256701, - "bbox_y0": -28.97142, - "bbox_y1": -16.95989 - } - }, - { - "pk": 162, - "model": "base.region", - "fields": { - "rght": 484, - "code": "NRU", - "name": "Nauru", - "parent": 256, - "level": 2, - "lft": 483, - "tree_id": 90, - "bbox_x0": 166.899017, - "bbox_x1": 166.945267, - "bbox_y0": -0.55232, - "bbox_y1": -0.50429 - } - }, - { - "pk": 163, - "model": "base.region", - "fields": { - "rght": 287, - "code": "NPL", - "name": "Nepal", - "parent": 9, - "level": 3, - "lft": 286, - "tree_id": 90, - "bbox_x0": 80.056221, - "bbox_x1": 88.199318, - "bbox_y0": 26.356501, - "bbox_y1": 30.433001 - } - }, - { - "pk": 164, - "model": "base.region", - "fields": { - "rght": 398, - "code": "NLD", - "name": "Netherlands", - "parent": 5, - "level": 2, - "lft": 397, - "tree_id": 90, - "bbox_x0": 3.35794, - "bbox_x1": 7.2267, - "bbox_y0": 50.750401, - "bbox_y1": 53.554241 - } - }, - { - "pk": 165, - "model": "base.region", - "fields": { - "rght": 165, - "code": "NAN", - "name": "Netherlands Antilles", - "parent": 255, - "level": 3, - "lft": 164, - "tree_id": 90, - "bbox_x0": -69.157188, - "bbox_x1": -62.943661, - "bbox_y0": 11.97318, - "bbox_y1": 18.07024 - } - }, - { - "pk": 166, - "model": "base.region", - "fields": { - "rght": 486, - "code": "NCL", - "name": "New Caledonia", - "parent": 256, - "level": 2, - "lft": 485, - "tree_id": 90, - "bbox_x0": 158.332855, - "bbox_x1": 172.061417, - "bbox_y0": -22.90045, - "bbox_y1": -18.01622 - } - }, - { - "pk": 167, - "model": "base.region", - "fields": { - "rght": 488, - "code": "NZL", - "name": "New Zealand", - "parent": 256, - "level": 2, - "lft": 487, - "tree_id": 90, - "bbox_x0": 165.883804, - "bbox_x1": -175.987198, - "bbox_y0": -52.618591, - "bbox_y1": -29.20997 - } - }, - { - "pk": 168, - "model": "base.region", - "fields": { - "rght": 199, - "code": "NIC", - "name": "Nicaragua", - "parent": 3, - "level": 3, - "lft": 198, - "tree_id": 90, - "bbox_x0": -87.6903, - "bbox_x1": -82.592072, - "bbox_y0": 10.70754, - "bbox_y1": 15.0259 - } - }, - { - "pk": 169, - "model": "base.region", - "fields": { - "rght": 115, - "code": "NER", - "name": "Niger", - "parent": 13, - "level": 3, - "lft": 114, - "tree_id": 90, - "bbox_x0": 0.16625, - "bbox_x1": 15.99564, - "bbox_y0": 11.69697, - "bbox_y1": 23.525021 - } - }, - { - "pk": 170, - "model": "base.region", - "fields": { - "rght": 117, - "code": "NGA", - "name": "Nigeria", - "parent": 13, - "level": 3, - "lft": 116, - "tree_id": 90, - "bbox_x0": 2.66844, - "bbox_x1": 14.68006, - "bbox_y0": 4.27714, - "bbox_y1": 13.892 - } - }, - { - "pk": 171, - "model": "base.region", - "fields": { - "rght": 490, - "code": "NIU", - "name": "Niue", - "parent": 256, - "level": 2, - "lft": 489, - "tree_id": 90, - "bbox_x0": -169.951004, - "bbox_x1": -169.775177, - "bbox_y0": -19.152189, - "bbox_y1": -18.951059 - } - }, - { - "pk": 172, - "model": "base.region", - "fields": { - "rght": 492, - "code": "NFK", - "name": "Norfolk Island", - "parent": 256, - "level": 2, - "lft": 491, - "tree_id": 90, - "bbox_x0": 167.949493, - "bbox_x1": 168.091614, - "bbox_y0": -29.11937, - "bbox_y1": -28.99493 - } - }, - { - "pk": 173, - "model": "base.region", - "fields": { - "rght": 494, - "code": "MNP", - "name": "Northern Mariana Islands", - "parent": 256, - "level": 2, - "lft": 493, - "tree_id": 90, - "bbox_x0": 136.082855, - "bbox_x1": 146.081223, - "bbox_y0": 14.10735, - "bbox_y1": 20.41712 - } - }, - { - "pk": 174, - "model": "base.region", - "fields": { - "rght": 400, - "code": "NOR", - "name": "Norway", - "parent": 5, - "level": 2, - "lft": 399, - "tree_id": 90, - "bbox_x0": 4.43292, - "bbox_x1": 31.168409, - "bbox_y0": 57.962582, - "bbox_y1": 71.185509 - } - }, - { - "pk": 175, - "model": "base.region", - "fields": { - "rght": 450, - "code": "PSE", - "name": "Occupied Palestinian Territory", - "parent": 15, - "level": 2, - "lft": 449, - "tree_id": 90, - "bbox_x0": 34.230461, - "bbox_x1": 35.876499, - "bbox_y0": 31.223499, - "bbox_y1": 33.340099 - } - }, - { - "pk": 176, - "model": "base.region", - "fields": { - "rght": 452, - "code": "OMN", - "name": "Oman", - "parent": 15, - "level": 2, - "lft": 451, - "tree_id": 90, - "bbox_x0": 51.882011, - "bbox_x1": 59.83651, - "bbox_y0": 16.6457, - "bbox_y1": 26.50045 - } - }, - { - "pk": 177, - "model": "base.region", - "fields": { - "rght": 289, - "code": "PAK", - "name": "Pakistan", - "parent": 9, - "level": 3, - "lft": 288, - "tree_id": 90, - "bbox_x0": 60.87859, - "bbox_x1": 77.840813, - "bbox_y0": 23.786699, - "bbox_y1": 37.097 - } - }, - { - "pk": 178, - "model": "base.region", - "fields": { - "rght": 496, - "code": "PLW", - "name": "Palau", - "parent": 256, - "level": 2, - "lft": 495, - "tree_id": 90, - "bbox_x0": 131.169235, - "bbox_x1": 134.723724, - "bbox_y0": 3.00114, - "bbox_y1": 8.09291 - } - }, - { - "pk": 179, - "model": "base.region", - "fields": { - "rght": 201, - "code": "PAN", - "name": "Panama", - "parent": 3, - "level": 3, - "lft": 200, - "tree_id": 90, - "bbox_x0": -83.051453, - "bbox_x1": -77.17411, - "bbox_y0": 7.1979, - "bbox_y1": 9.65045 - } - }, - { - "pk": 180, - "model": "base.region", - "fields": { - "rght": 498, - "code": "PNG", - "name": "Papua New Guinea", - "parent": 256, - "level": 2, - "lft": 497, - "tree_id": 90, - "bbox_x0": 140.842865, - "bbox_x1": 159.48378, - "bbox_y0": -11.65785, - "bbox_y1": -0.86622 - } - }, - { - "pk": 181, - "model": "base.region", - "fields": { - "rght": 233, - "code": "PRY", - "name": "Paraguay", - "parent": 4, - "level": 3, - "lft": 232, - "tree_id": 90, - "bbox_x0": -62.647072, - "bbox_x1": -54.25935, - "bbox_y0": -27.60873, - "bbox_y1": -19.294041 - } - }, - { - "pk": 182, - "model": "base.region", - "fields": { - "rght": 235, - "code": "PER", - "name": "Peru", - "parent": 4, - "level": 3, - "lft": 234, - "tree_id": 90, - "bbox_x0": -81.326736, - "bbox_x1": -68.677979, - "bbox_y0": -18.34972, - "bbox_y1": -0.01297 - } - }, - { - "pk": 183, - "model": "base.region", - "fields": { - "rght": 307, - "code": "PHL", - "name": "Philippines", - "parent": 7, - "level": 3, - "lft": 306, - "tree_id": 90, - "bbox_x0": 116.812721, - "bbox_x1": 126.856628, - "bbox_y0": 4.46811, - "bbox_y1": 21.23415 - } - }, - { - "pk": 184, - "model": "base.region", - "fields": { - "rght": 500, - "code": "PCN", - "name": "Pitcairn", - "parent": 256, - "level": 2, - "lft": 499, - "tree_id": 90, - "bbox_x0": -130.746033, - "bbox_x1": -124.772842, - "bbox_y0": -25.07752, - "bbox_y1": -23.917271 - } - }, - { - "pk": 185, - "model": "base.region", - "fields": { - "rght": 402, - "code": "POL", - "name": "Poland", - "parent": 5, - "level": 2, - "lft": 401, - "tree_id": 90, - "bbox_x0": 14.12281, - "bbox_x1": 24.145781, - "bbox_y0": 49.002022, - "bbox_y1": 54.835812 - } - }, - { - "pk": 186, - "model": "base.region", - "fields": { - "rght": 404, - "code": "PRT", - "name": "Portugal", - "parent": 5, - "level": 2, - "lft": 403, - "tree_id": 90, - "bbox_x0": -31.266001, - "bbox_x1": -6.18931, - "bbox_y0": 30.028061, - "bbox_y1": 42.154121 - } - }, - { - "pk": 187, - "model": "base.region", - "fields": { - "rght": 167, - "code": "PRI", - "name": "Puerto Rico", - "parent": 255, - "level": 3, - "lft": 166, - "tree_id": 90, - "bbox_x0": -67.942719, - "bbox_x1": -65.219978, - "bbox_y0": 17.883039, - "bbox_y1": 18.520161 - } - }, - { - "pk": 188, - "model": "base.region", - "fields": { - "rght": 454, - "code": "QAT", - "name": "Qatar", - "parent": 15, - "level": 2, - "lft": 453, - "tree_id": 90, - "bbox_x0": 50.757011, - "bbox_x1": 52.427509, - "bbox_y0": 24.482901, - "bbox_y1": 26.177509 - } - }, - { - "pk": 189, - "model": "base.region", - "fields": { - "rght": 275, - "code": "KOR", - "name": "Republic of Korea", - "parent": 258, - "level": 3, - "lft": 274, - "tree_id": 90, - "bbox_x0": 124.608147, - "bbox_x1": 130.933899, - "bbox_y0": 33.10611, - "bbox_y1": 38.612301 - } - }, - { - "pk": 190, - "model": "base.region", - "fields": { - "rght": 406, - "code": "MDA", - "name": "Republic of Moldova", - "parent": 5, - "level": 2, - "lft": 405, - "tree_id": 90, - "bbox_x0": 26.618879, - "bbox_x1": 30.16374, - "bbox_y0": 45.468498, - "bbox_y1": 48.490162 - } - }, - { - "pk": 191, - "model": "base.region", - "fields": { - "rght": 37, - "code": "REU", - "name": "Reunion", - "parent": 12, - "level": 3, - "lft": 36, - "tree_id": 90, - "bbox_x0": 55.219082, - "bbox_x1": 55.845039, - "bbox_y0": -21.37221, - "bbox_y1": -20.85685 - } - }, - { - "pk": 192, - "model": "base.region", - "fields": { - "rght": 408, - "code": "ROU", - "name": "Romania", - "parent": 5, - "level": 2, - "lft": 407, - "tree_id": 90, - "bbox_x0": 20.269791, - "bbox_x1": 29.691, - "bbox_y0": 43.626999, - "bbox_y1": 48.266891 - } - }, - { - "pk": 193, - "model": "base.region", - "fields": { - "rght": 410, - "code": "RUS", - "name": "Russian Federation", - "parent": 5, - "level": 2, - "lft": 409, - "tree_id": 90, - "bbox_x0": 19.638861, - "bbox_x1": 180, - "bbox_y0": 41.185902, - "bbox_y1": 81.856903 - } - }, - { - "pk": 194, - "model": "base.region", - "fields": { - "rght": 39, - "code": "RWA", - "name": "Rwanda", - "parent": 12, - "level": 3, - "lft": 38, - "tree_id": 90, - "bbox_x0": 28.8568, - "bbox_x1": 30.89596, - "bbox_y0": -2.84067, - "bbox_y1": -1.05348 - } - }, - { - "pk": 195, - "model": "base.region", - "fields": { - "rght": 73, - "code": "SHN", - "name": "Saint Helena", - "parent": 14, - "level": 3, - "lft": 72, - "tree_id": 90, - "bbox_x0": -14.44153, - "bbox_x1": -5.63286, - "bbox_y0": -40.400452, - "bbox_y1": -7.87757 - } - }, - { - "pk": 196, - "model": "base.region", - "fields": { - "rght": 169, - "code": "KNA", - "name": "Saint Kitts and Nevis", - "parent": 255, - "level": 3, - "lft": 168, - "tree_id": 90, - "bbox_x0": -62.86956, - "bbox_x1": -62.543259, - "bbox_y0": 17.095341, - "bbox_y1": 17.420111 - } - }, - { - "pk": 197, - "model": "base.region", - "fields": { - "rght": 171, - "code": "LCA", - "name": "Saint Lucia", - "parent": 255, - "level": 3, - "lft": 170, - "tree_id": 90, - "bbox_x0": -61.07415, - "bbox_x1": -60.866051, - "bbox_y0": 13.70477, - "bbox_y1": 14.10324 - } - }, - { - "pk": 198, - "model": "base.region", - "fields": { - "rght": 173, - "code": "SPM", - "name": "Saint Pierre and Miquelon", - "parent": 255, - "level": 3, - "lft": 172, - "tree_id": 90, - "bbox_x0": -56.420658, - "bbox_x1": -56.157372, - "bbox_y0": 46.753269, - "bbox_y1": 47.14629 - } - }, - { - "pk": 199, - "model": "base.region", - "fields": { - "rght": 175, - "code": "VCT", - "name": "Saint Vincent and the Grenadines", - "parent": 255, - "level": 3, - "lft": 174, - "tree_id": 90, - "bbox_x0": -61.459251, - "bbox_x1": -61.11388, - "bbox_y0": 12.58101, - "bbox_y1": 13.37783 - } - }, - { - "pk": 200, - "model": "base.region", - "fields": { - "rght": 177, - "code": "BLM", - "name": "Saint-Barthelemy", - "parent": 255, - "level": 3, - "lft": 176, - "tree_id": 90, - "bbox_x0": -62.9338, - "bbox_x1": -62.78286, - "bbox_y0": 17.86622, - "bbox_y1": 17.968599 - } - }, - { - "pk": 201, - "model": "base.region", - "fields": { - "rght": 179, - "code": "MAF", - "name": "Saint-Martin (French part)", - "parent": 255, - "level": 3, - "lft": 178, - "tree_id": 90, - "bbox_x0": -63.15276, - "bbox_x1": -62.972778, - "bbox_y0": 18.052231, - "bbox_y1": 18.13069 - } - }, - { - "pk": 202, - "model": "base.region", - "fields": { - "rght": 502, - "code": "WSM", - "name": "Samoa", - "parent": 256, - "level": 2, - "lft": 501, - "tree_id": 90, - "bbox_x0": -172.798584, - "bbox_x1": -171.33287, - "bbox_y0": -14.06353, - "bbox_y1": -13.4322 - } - }, - { - "pk": 203, - "model": "base.region", - "fields": { - "rght": 412, - "code": "SMR", - "name": "San Marino", - "parent": 5, - "level": 2, - "lft": 411, - "tree_id": 90, - "bbox_x0": 12.40306, - "bbox_x1": 12.51651, - "bbox_y0": 43.893299, - "bbox_y1": 43.992168 - } - }, - { - "pk": 204, - "model": "base.region", - "fields": { - "rght": 119, - "code": "STP", - "name": "Sao Tome and Principe", - "parent": 13, - "level": 3, - "lft": 118, - "tree_id": 90, - "bbox_x0": 5.59955, - "bbox_x1": 7.46637, - "bbox_y0": -0.014, - "bbox_y1": 1.73378 - } - }, - { - "pk": 205, - "model": "base.region", - "fields": { - "rght": 456, - "code": "SAU", - "name": "Saudi Arabia", - "parent": 15, - "level": 2, - "lft": 455, - "tree_id": 90, - "bbox_x0": 34.508282, - "bbox_x1": 55.666672, - "bbox_y0": 16.261169, - "bbox_y1": 32.173481 - } - }, - { - "pk": 206, - "model": "base.region", - "fields": { - "rght": 121, - "code": "SEN", - "name": "Senegal", - "parent": 13, - "level": 3, - "lft": 120, - "tree_id": 90, - "bbox_x0": -17.535231, - "bbox_x1": -11.35588, - "bbox_y0": 12.30727, - "bbox_y1": 16.691629 - } - }, - { - "pk": 207, - "model": "base.region", - "fields": { - "rght": 414, - "code": "SRB", - "name": "Serbia", - "parent": 5, - "level": 2, - "lft": 413, - "tree_id": 90, - "bbox_x0": 18.814581, - "bbox_x1": 23.007, - "bbox_y0": 41.908611, - "bbox_y1": 46.191002 - } - }, - { - "pk": 208, - "model": "base.region", - "fields": { - "rght": 41, - "code": "SYC", - "name": "Seychelles", - "parent": 12, - "level": 3, - "lft": 40, - "tree_id": 90, - "bbox_x0": 46.199211, - "bbox_x1": 56.279499, - "bbox_y0": -10.21712, - "bbox_y1": -3.71151 - } - }, - { - "pk": 209, - "model": "base.region", - "fields": { - "rght": 123, - "code": "SLE", - "name": "Sierra Leone", - "parent": 13, - "level": 3, - "lft": 122, - "tree_id": 90, - "bbox_x0": -13.30763, - "bbox_x1": -10.28423, - "bbox_y0": 6.92868, - "bbox_y1": 10.00043 - } - }, - { - "pk": 210, - "model": "base.region", - "fields": { - "rght": 309, - "code": "SGP", - "name": "Singapore", - "parent": 7, - "level": 3, - "lft": 308, - "tree_id": 90, - "bbox_x0": 103.618248, - "bbox_x1": 104.40847, - "bbox_y0": 1.1158, - "bbox_y1": 1.47062 - } - }, - { - "pk": 211, - "model": "base.region", - "fields": { - "rght": 416, - "code": "SVK", - "name": "Slovakia", - "parent": 5, - "level": 2, - "lft": 415, - "tree_id": 90, - "bbox_x0": 16.833179, - "bbox_x1": 22.570299, - "bbox_y0": 47.728001, - "bbox_y1": 49.603001 - } - }, - { - "pk": 212, - "model": "base.region", - "fields": { - "rght": 418, - "code": "SVN", - "name": "Slovenia", - "parent": 5, - "level": 2, - "lft": 417, - "tree_id": 90, - "bbox_x0": 13.37551, - "bbox_x1": 16.59656, - "bbox_y0": 45.416, - "bbox_y1": 46.87788 - } - }, - { - "pk": 213, - "model": "base.region", - "fields": { - "rght": 504, - "code": "SLB", - "name": "Solomon Islands", - "parent": 256, - "level": 2, - "lft": 503, - "tree_id": 90, - "bbox_x0": 155.508667, - "bbox_x1": 170.200455, - "bbox_y0": -12.2919, - "bbox_y1": -5.16622 - } - }, - { - "pk": 214, - "model": "base.region", - "fields": { - "rght": 43, - "code": "SOM", - "name": "Somalia", - "parent": 12, - "level": 3, - "lft": 42, - "tree_id": 90, - "bbox_x0": 40.988628, - "bbox_x1": 51.413029, - "bbox_y0": -1.66205, - "bbox_y1": 11.9852 - } - }, - { - "pk": 215, - "model": "base.region", - "fields": { - "rght": 75, - "code": "ZAF", - "name": "South Africa", - "parent": 14, - "level": 3, - "lft": 74, - "tree_id": 90, - "bbox_x0": 16.46841, - "bbox_x1": 37.993172, - "bbox_y0": -46.990009, - "bbox_y1": -22.12472 - } - }, - { - "pk": 216, - "model": "base.region", - "fields": { - "rght": 420, - "code": "ESP", - "name": "Spain", - "parent": 5, - "level": 2, - "lft": 419, - "tree_id": 90, - "bbox_x0": -18.160789, - "bbox_x1": 4.32788, - "bbox_y0": 27.63546, - "bbox_y1": 43.789959 - } - }, - { - "pk": 217, - "model": "base.region", - "fields": { - "rght": 291, - "code": "LKA", - "name": "Sri Lanka", - "parent": 9, - "level": 3, - "lft": 290, - "tree_id": 90, - "bbox_x0": 79.516212, - "bbox_x1": 81.88121, - "bbox_y0": 5.9167, - "bbox_y1": 9.8312 - } - }, - { - "pk": 218, - "model": "base.region", - "fields": { - "rght": 59, - "code": "SDN", - "name": "Sudan", - "parent": 11, - "level": 3, - "lft": 58, - "tree_id": 90, - "bbox_x0": 21.83894, - "bbox_x1": 38.833801, - "bbox_y0": 3.48639, - "bbox_y1": 23.146891 - } - }, - { - "pk": 219, - "model": "base.region", - "fields": { - "rght": 237, - "code": "SUR", - "name": "Suriname", - "parent": 4, - "level": 3, - "lft": 236, - "tree_id": 90, - "bbox_x0": -58.086559, - "bbox_x1": -53.977489, - "bbox_y0": 1.83114, - "bbox_y1": 6.00454 - } - }, - { - "pk": 220, - "model": "base.region", - "fields": { - "rght": 422, - "code": "SJM", - "name": "Svalbard and Jan Mayen Islands", - "parent": 5, - "level": 2, - "lft": 421, - "tree_id": 90, - "bbox_x0": -9.07989, - "bbox_x1": 36.815269, - "bbox_y0": 70.82737, - "bbox_y1": 80.834061 - } - }, - { - "pk": 221, - "model": "base.region", - "fields": { - "rght": 77, - "code": "SWZ", - "name": "Swaziland", - "parent": 14, - "level": 3, - "lft": 76, - "tree_id": 90, - "bbox_x0": 30.7941, - "bbox_x1": 32.137272, - "bbox_y0": -27.317101, - "bbox_y1": -25.719641 - } - }, - { - "pk": 222, - "model": "base.region", - "fields": { - "rght": 424, - "code": "SWE", - "name": "Sweden", - "parent": 5, - "level": 2, - "lft": 423, - "tree_id": 90, - "bbox_x0": 10.9661, - "bbox_x1": 24.16634, - "bbox_y0": 55.33696, - "bbox_y1": 69.059937 - } - }, - { - "pk": 223, - "model": "base.region", - "fields": { - "rght": 426, - "code": "CHE", - "name": "Switzerland", - "parent": 5, - "level": 2, - "lft": 425, - "tree_id": 90, - "bbox_x0": 5.95587, - "bbox_x1": 10.49203, - "bbox_y0": 45.81802, - "bbox_y1": 47.80838 - } - }, - { - "pk": 224, - "model": "base.region", - "fields": { - "rght": 458, - "code": "SYR", - "name": "Syrian Arab Republic", - "parent": 15, - "level": 2, - "lft": 457, - "tree_id": 90, - "bbox_x0": 35.727001, - "bbox_x1": 42.384998, - "bbox_y0": 32.3106, - "bbox_y1": 37.319 - } - }, - { - "pk": 225, - "model": "base.region", - "fields": { - "rght": 255, - "code": "TJK", - "name": "Tajikistan", - "parent": 8, - "level": 3, - "lft": 254, - "tree_id": 90, - "bbox_x0": 67.387131, - "bbox_x1": 75.137222, - "bbox_y0": 36.674141, - "bbox_y1": 41.04224 - } - }, - { - "pk": 226, - "model": "base.region", - "fields": { - "rght": 311, - "code": "THA", - "name": "Thailand", - "parent": 7, - "level": 3, - "lft": 310, - "tree_id": 90, - "bbox_x0": 97.343964, - "bbox_x1": 105.636917, - "bbox_y0": 5.61257, - "bbox_y1": 20.464701 - } - }, - { - "pk": 227, - "model": "base.region", - "fields": { - "rght": 313, - "code": "TLS", - "name": "Timor-Leste", - "parent": 7, - "level": 3, - "lft": 312, - "tree_id": 90, - "bbox_x0": 124.075439, - "bbox_x1": 127.345337, - "bbox_y0": -9.51337, - "bbox_y1": -8.13741 - } - }, - { - "pk": 228, - "model": "base.region", - "fields": { - "rght": 125, - "code": "TGO", - "name": "Togo", - "parent": 13, - "level": 3, - "lft": 124, - "tree_id": 90, - "bbox_x0": -0.14731, - "bbox_x1": 1.80669, - "bbox_y0": 6.10441, - "bbox_y1": 11.13897 - } - }, - { - "pk": 229, - "model": "base.region", - "fields": { - "rght": 506, - "code": "TKL", - "name": "Tokelau", - "parent": 256, - "level": 2, - "lft": 505, - "tree_id": 90, - "bbox_x0": -172.517136, - "bbox_x1": -171.182083, - "bbox_y0": -9.43378, - "bbox_y1": -8.53288 - } - }, - { - "pk": 230, - "model": "base.region", - "fields": { - "rght": 508, - "code": "TON", - "name": "Tonga", - "parent": 256, - "level": 2, - "lft": 507, - "tree_id": 90, - "bbox_x0": -176.212646, - "bbox_x1": -173.702438, - "bbox_y0": -22.345711, - "bbox_y1": -15.55326 - } - }, - { - "pk": 231, - "model": "base.region", - "fields": { - "rght": 181, - "code": "TTO", - "name": "Trinidad and Tobago", - "parent": 255, - "level": 3, - "lft": 180, - "tree_id": 90, - "bbox_x0": -61.927391, - "bbox_x1": -60.49144, - "bbox_y0": 10.03648, - "bbox_y1": 11.36118 - } - }, - { - "pk": 232, - "model": "base.region", - "fields": { - "rght": 61, - "code": "TUN", - "name": "Tunisia", - "parent": 11, - "level": 3, - "lft": 60, - "tree_id": 90, - "bbox_x0": 7.52481, - "bbox_x1": 11.59827, - "bbox_y0": 30.240431, - "bbox_y1": 37.56712 - } - }, - { - "pk": 233, - "model": "base.region", - "fields": { - "rght": 428, - "code": "TUR", - "name": "Turkey", - "parent": 5, - "level": 2, - "lft": 427, - "tree_id": 90, - "bbox_x0": 25.664101, - "bbox_x1": 44.8297, - "bbox_y0": 35.809971, - "bbox_y1": 42.105499 - } - }, - { - "pk": 234, - "model": "base.region", - "fields": { - "rght": 257, - "code": "TKM", - "name": "Turkmenistan", - "parent": 8, - "level": 3, - "lft": 256, - "tree_id": 90, - "bbox_x0": 52.441429, - "bbox_x1": 66.684303, - "bbox_y0": 35.14109, - "bbox_y1": 42.795551 - } - }, - { - "pk": 235, - "model": "base.region", - "fields": { - "rght": 183, - "code": "TCA", - "name": "Turks and Caicos Islands", - "parent": 255, - "level": 3, - "lft": 182, - "tree_id": 90, - "bbox_x0": -72.483879, - "bbox_x1": -71.08033, - "bbox_y0": 21.170031, - "bbox_y1": 21.97361 - } - }, - { - "pk": 236, - "model": "base.region", - "fields": { - "rght": 510, - "code": "TUV", - "name": "Tuvalu", - "parent": 256, - "level": 2, - "lft": 509, - "tree_id": 90, - "bbox_x0": 176.06488, - "bbox_x1": 179.883789, - "bbox_y0": -10.75045, - "bbox_y1": -5.64198 - } - }, - { - "pk": 237, - "model": "base.region", - "fields": { - "rght": 45, - "code": "UGA", - "name": "Uganda", - "parent": 12, - "level": 3, - "lft": 44, - "tree_id": 90, - "bbox_x0": 29.573549, - "bbox_x1": 35.001251, - "bbox_y0": -1.47849, - "bbox_y1": 4.23403 - } - }, - { - "pk": 238, - "model": "base.region", - "fields": { - "rght": 430, - "code": "UKR", - "name": "Ukraine", - "parent": 5, - "level": 2, - "lft": 429, - "tree_id": 90, - "bbox_x0": 22.128811, - "bbox_x1": 40.218079, - "bbox_y0": 44.390411, - "bbox_y1": 52.375359 - } - }, - { - "pk": 239, - "model": "base.region", - "fields": { - "rght": 460, - "code": "ARE", - "name": "United Arab Emirates", - "parent": 15, - "level": 2, - "lft": 459, - "tree_id": 90, - "bbox_x0": 51.497978, - "bbox_x1": 56.38343, - "bbox_y0": 22.644409, - "bbox_y1": 26.28219 - } - }, - { - "pk": 240, - "model": "base.region", - "fields": { - "rght": 432, - "code": "GBR", - "name": "United Kingdom", - "parent": 5, - "level": 2, - "lft": 431, - "tree_id": 90, - "bbox_x0": -13.41393, - "bbox_x1": 1.76896, - "bbox_y0": 49.16209, - "bbox_y1": 60.854691 - } - }, - { - "pk": 241, - "model": "base.region", - "fields": { - "rght": 47, - "code": "TZA", - "name": "United Republic of Tanzania", - "parent": 12, - "level": 3, - "lft": 46, - "tree_id": 90, - "bbox_x0": 29.32716, - "bbox_x1": 40.443218, - "bbox_y0": -11.74569, - "bbox_y1": -0.99073 - } - }, - { - "pk": 242, - "model": "base.region", - "fields": { - "rght": 185, - "code": "VIR", - "name": "United States Virgin Islands", - "parent": 255, - "level": 3, - "lft": 184, - "tree_id": 90, - "bbox_x0": -65.086281, - "bbox_x1": -64.56517, - "bbox_y0": 17.681721, - "bbox_y1": 18.458139 - } - }, - { - "pk": 243, - "model": "base.region", - "fields": { - "rght": 211, - "code": "USA", - "name": "United States of America", - "parent": 2, - "level": 3, - "lft": 210, - "tree_id": 90, - "bbox_x0": -179.150558, - "bbox_x1": -66.940643, - "bbox_y0": 18.91172, - "bbox_y1": 71.441048 - } - }, - { - "pk": 244, - "model": "base.region", - "fields": { - "rght": 239, - "code": "URY", - "name": "Uruguay", - "parent": 4, - "level": 3, - "lft": 238, - "tree_id": 90, - "bbox_x0": -58.442719, - "bbox_x1": -53.073929, - "bbox_y0": -35.047939, - "bbox_y1": -30.08222 - } - }, - { - "pk": 245, - "model": "base.region", - "fields": { - "rght": 259, - "code": "UZB", - "name": "Uzbekistan", - "parent": 8, - "level": 3, - "lft": 258, - "tree_id": 90, - "bbox_x0": 55.996632, - "bbox_x1": 73.132271, - "bbox_y0": 37.18433, - "bbox_y1": 45.60519 - } - }, - { - "pk": 246, - "model": "base.region", - "fields": { - "rght": 512, - "code": "VUT", - "name": "Vanuatu", - "parent": 256, - "level": 2, - "lft": 511, - "tree_id": 90, - "bbox_x0": 166.524994, - "bbox_x1": 170.234802, - "bbox_y0": -20.25045, - "bbox_y1": -13.07345 - } - }, - { - "pk": 247, - "model": "base.region", - "fields": { - "rght": 241, - "code": "VEN", - "name": "Venezuela (Bolivarian Republic of)", - "parent": 4, - "level": 3, - "lft": 240, - "tree_id": 90, - "bbox_x0": -73.374313, - "bbox_x1": -59.803768, - "bbox_y0": 0.74368, - "bbox_y1": 12.2019 - } - }, - { - "pk": 248, - "model": "base.region", - "fields": { - "rght": 315, - "code": "VNM", - "name": "Viet Nam", - "parent": 7, - "level": 3, - "lft": 314, - "tree_id": 90, - "bbox_x0": 102.144592, - "bbox_x1": 116.521233, - "bbox_y0": 7.3116, - "bbox_y1": 23.39274 - } - }, - { - "pk": 249, - "model": "base.region", - "fields": { - "rght": 514, - "code": "WLF", - "name": "Wallis and Futuna Islands", - "parent": 256, - "level": 2, - "lft": 513, - "tree_id": 90, - "bbox_x0": -178.206787, - "bbox_x1": -176.08287, - "bbox_y0": -14.38779, - "bbox_y1": -13.17343 - } - }, - { - "pk": 250, - "model": "base.region", - "fields": { - "rght": 63, - "code": "ESH", - "name": "Western Sahara", - "parent": 11, - "level": 3, - "lft": 62, - "tree_id": 90, - "bbox_x0": -17.10317, - "bbox_x1": -8.66942, - "bbox_y0": 20.774151, - "bbox_y1": 28.219179 - } - }, - { - "pk": 251, - "model": "base.region", - "fields": { - "rght": 462, - "code": "YEM", - "name": "Yemen", - "parent": 15, - "level": 2, - "lft": 461, - "tree_id": 90, - "bbox_x0": 41.809608, - "bbox_x1": 54.535992, - "bbox_y0": 12.10717, - "bbox_y1": 19.00276 - } - }, - { - "pk": 252, - "model": "base.region", - "fields": { - "rght": 79, - "code": "ZMB", - "name": "Zambia", - "parent": 14, - "level": 3, - "lft": 78, - "tree_id": 90, - "bbox_x0": 21.99938, - "bbox_x1": 33.705711, - "bbox_y0": -18.07947, - "bbox_y1": -8.22436 - } - }, - { - "pk": 253, - "model": "base.region", - "fields": { - "rght": 81, - "code": "ZWE", - "name": "Zimbabwe", - "parent": 14, - "level": 3, - "lft": 80, - "tree_id": 90, - "bbox_x0": 25.23702, - "bbox_x1": 33.056301, - "bbox_y0": -22.41773, - "bbox_y1": -15.60883 - } - }, - { - "pk": 254, - "model": "base.region", - "fields": { - "rght": 243, - "code": "AME", - "name": "Americas", - "parent": null, - "level": 1, - "lft": 128, - "tree_id": 90, - "bbox_x0": -84.114449, - "bbox_x1": -84.097572, - "bbox_y0": 9.9313, - "bbox_y1": 9.94792 - } - }, - { - "pk": 255, - "model": "base.region", - "fields": { - "rght": 186, - "code": "CRB", - "name": "Caribbean", - "parent": 254, - "level": 2, - "lft": 129, - "tree_id": 90, - "bbox_x0": -85.260178, - "bbox_x1": -59.286541, - "bbox_y0": 10.18548, - "bbox_y1": 27.454559 - } - }, - { - "pk": 256, - "model": "base.region", - "fields": { - "rght": 515, - "code": "PAC", - "name": "Pacific", - "parent": null, - "level": 1, - "lft": 464, - "tree_id": 90, - "bbox_x0": 112.921112, - "bbox_x1": -108.87291, - "bbox_y0": -54.640301, - "bbox_y1": 20.41712 - } - }, - { - "pk": 257, - "model": "base.region", - "fields": { - "rght": 12, - "code": "CFR", - "name": "Central Africa", - "parent": 10, - "level": 2, - "lft": 3, - "tree_id": 90, - "bbox_x0": -25.35874, - "bbox_x1": 63.525379, - "bbox_y0": -46.900452, - "bbox_y1": 37.56712 - } - }, - { - "pk": 258, - "model": "base.region", - "fields": { - "rght": 276, - "code": "EAS", - "name": "East Asia", - "parent": 6, - "level": 2, - "lft": 261, - "tree_id": 90, - "bbox_x0": 19.6381, - "bbox_x1": 180, - "bbox_y0": -12.56111, - "bbox_y1": 82.50045 - } - }, - { - "pk": 259, - "model": "base.region", - "fields": { - "rght": 59, - "code": "SSD", - "name": "South Sudan", - "parent": 11, - "level": 3, - "lft": 58, - "tree_id": 90, - "bbox_x0": 24.15192, - "bbox_x1": 35.947689, - "bbox_y0": 3.48639, - "bbox_y1": 12.21558 - } - } -] +[ + { + "pk": 1, + "model": "base.region", + "fields": { + "rght": 516, + "code": "GLO", + "name": "Global", + "parent": null, + "level": 0, + "lft": 1, + "tree_id": 90, + "bbox_x0": -180, + "bbox_x1": 180, + "bbox_y0": -90, + "bbox_y1": 90 + } + }, + { + "pk": 2, + "model": "base.region", + "fields": { + "rght": 212, + "code": "NAM", + "name": "North America", + "parent": 254, + "level": 2, + "lft": 203, + "tree_id": 90, + "bbox_x0": -167.276413, + "bbox_x1": -52.23304, + "bbox_y0": 5.49955, + "bbox_y1": 83.162102 + } + }, + { + "pk": 3, + "model": "base.region", + "fields": { + "rght": 202, + "code": "CAM", + "name": "Central America", + "parent": 254, + "level": 2, + "lft": 187, + "tree_id": 90, + "bbox_x0": -118.867172, + "bbox_x1": -66.869827, + "bbox_y0": -4.23048, + "bbox_y1": 32.71862 + } + }, + { + "pk": 4, + "model": "base.region", + "fields": { + "rght": 242, + "code": "SAM", + "name": "South America", + "parent": 254, + "level": 2, + "lft": 213, + "tree_id": 90, + "bbox_x0": -109.47493, + "bbox_x1": -26.33247, + "bbox_y0": -59.450451, + "bbox_y1": 13.39029 + } + }, + { + "pk": 5, + "model": "base.region", + "fields": { + "rght": 433, + "code": "EUR", + "name": "Europe", + "parent": null, + "level": 1, + "lft": 318, + "tree_id": 90, + "bbox_x0": -31.266001, + "bbox_x1": 39.869301, + "bbox_y0": 27.636311, + "bbox_y1": 81.008797 + } + }, + { + "pk": 6, + "model": "base.region", + "fields": { + "rght": 317, + "code": "ASI", + "name": "Asia", + "parent": null, + "level": 1, + "lft": 246, + "tree_id": 90, + "bbox_x0": 19.6381, + "bbox_x1": 180, + "bbox_y0": -12.56111, + "bbox_y1": 82.50045 + } + }, + { + "pk": 7, + "model": "base.region", + "fields": { + "rght": 316, + "code": "SEA", + "name": "Southeast Asia", + "parent": 6, + "level": 2, + "lft": 293, + "tree_id": 90, + "bbox_x0": 68.0327, + "bbox_x1": 141.021805, + "bbox_y0": -12.56111, + "bbox_y1": 35.504211 + } + }, + { + "pk": 8, + "model": "base.region", + "fields": { + "rght": 260, + "code": "CTA", + "name": "Central Asia", + "parent": 6, + "level": 2, + "lft": 247, + "tree_id": 90, + "bbox_x0": 44.236641, + "bbox_x1": 90.076767, + "bbox_y0": 33.890511, + "bbox_y1": 54.845139 + } + }, + { + "pk": 9, + "model": "base.region", + "fields": { + "rght": 292, + "code": "SAS", + "name": "South Asia", + "parent": 6, + "level": 2, + "lft": 277, + "tree_id": 90, + "bbox_x0": 19.6381, + "bbox_x1": 180, + "bbox_y0": -12.56111, + "bbox_y1": 82.50045 + } + }, + { + "pk": 10, + "model": "base.region", + "fields": { + "rght": 127, + "code": "AFR", + "name": "Africa", + "parent": null, + "level": 1, + "lft": 2, + "tree_id": 90, + "bbox_x0": -25.35874, + "bbox_x1": 63.525379, + "bbox_y0": -46.900452, + "bbox_y1": 37.56712 + } + }, + { + "pk": 11, + "model": "base.region", + "fields": { + "rght": 64, + "code": "NAF", + "name": "North Africa", + "parent": 10, + "level": 2, + "lft": 49, + "tree_id": 90, + "bbox_x0": -17.10317, + "bbox_x1": 38.833801, + "bbox_y0": 3.48639, + "bbox_y1": 37.56712 + } + }, + { + "pk": 12, + "model": "base.region", + "fields": { + "rght": 48, + "code": "EAF", + "name": "East Africa", + "parent": 10, + "level": 2, + "lft": 13, + "tree_id": 90, + "bbox_x0": 22.855089, + "bbox_x1": 63.94656, + "bbox_y0": -25.84763, + "bbox_y1": 17.467039 + } + }, + { + "pk": 13, + "model": "base.region", + "fields": { + "rght": 126, + "code": "WAF", + "name": "West Africa", + "parent": 10, + "level": 2, + "lft": 83, + "tree_id": 90, + "bbox_x0": -26.758421, + "bbox_x1": 24.002661, + "bbox_y0": -9.29925, + "bbox_y1": 27.702801 + } + }, + { + "pk": 14, + "model": "base.region", + "fields": { + "rght": 82, + "code": "SAF", + "name": "Southern Africa", + "parent": 10, + "level": 2, + "lft": 65, + "tree_id": 90, + "bbox_x0": 8.93107, + "bbox_x1": 42.74847, + "bbox_y0": -35.507481, + "bbox_y1": -13.27553 + } + }, + { + "pk": 15, + "model": "base.region", + "fields": { + "rght": 463, + "code": "MES", + "name": "Middle East", + "parent": null, + "level": 1, + "lft": 434, + "tree_id": 90, + "bbox_x0": 24.698099, + "bbox_x1": 63.317459, + "bbox_y0": 12.111, + "bbox_y1": 42.10751 + } + }, + { + "pk": 16, + "model": "base.region", + "fields": { + "rght": 245, + "code": "ANT", + "name": "Antarctica", + "parent": null, + "level": 1, + "lft": 244, + "tree_id": 90, + "bbox_x0": -180, + "bbox_x1": 180, + "bbox_y0": -90, + "bbox_y1": -73 + } + }, + { + "pk": 17, + "model": "base.region", + "fields": { + "rght": 249, + "code": "AFG", + "name": "Afghanistan", + "parent": 8, + "level": 3, + "lft": 248, + "tree_id": 90, + "bbox_x0": 60.478439, + "bbox_x1": 74.879433, + "bbox_y0": 29.37747, + "bbox_y1": 38.483421 + } + }, + { + "pk": 18, + "model": "base.region", + "fields": { + "rght": 320, + "code": "ALA", + "name": "Aland Islands", + "parent": 5, + "level": 2, + "lft": 319, + "tree_id": 90, + "bbox_x0": 19.262711, + "bbox_x1": 21.324409, + "bbox_y0": 59.736301, + "bbox_y1": 60.665581 + } + }, + { + "pk": 19, + "model": "base.region", + "fields": { + "rght": 322, + "code": "ALB", + "name": "Albania", + "parent": 5, + "level": 2, + "lft": 321, + "tree_id": 90, + "bbox_x0": 19.28219, + "bbox_x1": 21.057819, + "bbox_y0": 39.644489, + "bbox_y1": 42.660801 + } + }, + { + "pk": 20, + "model": "base.region", + "fields": { + "rght": 51, + "code": "DZA", + "name": "Algeria", + "parent": 11, + "level": 3, + "lft": 50, + "tree_id": 90, + "bbox_x0": -8.67386, + "bbox_x1": 11.97955, + "bbox_y0": 18.96002, + "bbox_y1": 37.093731 + } + }, + { + "pk": 21, + "model": "base.region", + "fields": { + "rght": 466, + "code": "ASM", + "name": "American Samoa", + "parent": 256, + "level": 2, + "lft": 465, + "tree_id": 90, + "bbox_x0": -171.091873, + "bbox_x1": -169.416077, + "bbox_y0": -14.38247, + "bbox_y1": -11.04969 + } + }, + { + "pk": 22, + "model": "base.region", + "fields": { + "rght": 324, + "code": "AND", + "name": "Andorra", + "parent": 5, + "level": 2, + "lft": 323, + "tree_id": 90, + "bbox_x0": 1.41382, + "bbox_x1": 1.78659, + "bbox_y0": 42.42873, + "bbox_y1": 42.65601 + } + }, + { + "pk": 23, + "model": "base.region", + "fields": { + "rght": 85, + "code": "AGO", + "name": "Angola", + "parent": 13, + "level": 3, + "lft": 84, + "tree_id": 90, + "bbox_x0": 11.6792, + "bbox_x1": 24.082109, + "bbox_y0": -18.04207, + "bbox_y1": -4.37259 + } + }, + { + "pk": 24, + "model": "base.region", + "fields": { + "rght": 131, + "code": "AIA", + "name": "Anguilla", + "parent": 255, + "level": 3, + "lft": 130, + "tree_id": 90, + "bbox_x0": -63.434872, + "bbox_x1": -62.916199, + "bbox_y0": 18.149549, + "bbox_y1": 18.61278 + } + }, + { + "pk": 25, + "model": "base.region", + "fields": { + "rght": 133, + "code": "ATG", + "name": "Antigua and Barbuda", + "parent": 255, + "level": 3, + "lft": 132, + "tree_id": 90, + "bbox_x0": -62.352402, + "bbox_x1": -61.659081, + "bbox_y0": 16.927219, + "bbox_y1": 17.72938 + } + }, + { + "pk": 26, + "model": "base.region", + "fields": { + "rght": 215, + "code": "ARG", + "name": "Argentina", + "parent": 4, + "level": 3, + "lft": 214, + "tree_id": 90, + "bbox_x0": -73.577782, + "bbox_x1": -53.637539, + "bbox_y0": -55.057362, + "bbox_y1": -21.78126 + } + }, + { + "pk": 27, + "model": "base.region", + "fields": { + "rght": 326, + "code": "ARM", + "name": "Armenia", + "parent": 5, + "level": 2, + "lft": 325, + "tree_id": 90, + "bbox_x0": 43.449749, + "bbox_x1": 46.630039, + "bbox_y0": 38.830521, + "bbox_y1": 41.30183 + } + }, + { + "pk": 28, + "model": "base.region", + "fields": { + "rght": 135, + "code": "ABW", + "name": "Aruba", + "parent": 255, + "level": 3, + "lft": 134, + "tree_id": 90, + "bbox_x0": -70.0611, + "bbox_x1": -69.8669, + "bbox_y0": 12.4061, + "bbox_y1": 12.6306 + } + }, + { + "pk": 29, + "model": "base.region", + "fields": { + "rght": 468, + "code": "AUS", + "name": "Australia", + "parent": 256, + "level": 2, + "lft": 467, + "tree_id": 90, + "bbox_x0": 112.921112, + "bbox_x1": 159.278717, + "bbox_y0": -54.640301, + "bbox_y1": -9.22882 + } + }, + { + "pk": 30, + "model": "base.region", + "fields": { + "rght": 328, + "code": "AUT", + "name": "Austria", + "parent": 5, + "level": 2, + "lft": 327, + "tree_id": 90, + "bbox_x0": 9.53079, + "bbox_x1": 17.160749, + "bbox_y0": 46.372299, + "bbox_y1": 49.02071 + } + }, + { + "pk": 31, + "model": "base.region", + "fields": { + "rght": 330, + "code": "AZE", + "name": "Azerbaijan", + "parent": 5, + "level": 2, + "lft": 329, + "tree_id": 90, + "bbox_x0": 44.7719, + "bbox_x1": 50.6078, + "bbox_y0": 38.3970, + "bbox_y1": 41.9056 + } + }, + { + "pk": 32, + "model": "base.region", + "fields": { + "rght": 137, + "code": "BHS", + "name": "Bahamas", + "parent": 255, + "level": 3, + "lft": 136, + "tree_id": 90, + "bbox_x0": -80.499229, + "bbox_x1": -72.649513, + "bbox_y0": 20.916059, + "bbox_y1": 27.933781 + } + }, + { + "pk": 33, + "model": "base.region", + "fields": { + "rght": 436, + "code": "BHR", + "name": "Bahrain", + "parent": 15, + "level": 2, + "lft": 435, + "tree_id": 90, + "bbox_x0": 50.385799, + "bbox_x1": 50.828499, + "bbox_y0": 25.5422, + "bbox_y1": 26.292391 + } + }, + { + "pk": 34, + "model": "base.region", + "fields": { + "rght": 279, + "code": "BGD", + "name": "Bangladesh", + "parent": 9, + "level": 3, + "lft": 278, + "tree_id": 90, + "bbox_x0": 88.028198, + "bbox_x1": 92.673599, + "bbox_y0": 20.585199, + "bbox_y1": 26.631701 + } + }, + { + "pk": 35, + "model": "base.region", + "fields": { + "rght": 139, + "code": "BRB", + "name": "Barbados", + "parent": 255, + "level": 3, + "lft": 138, + "tree_id": 90, + "bbox_x0": -59.648918, + "bbox_x1": -59.420368, + "bbox_y0": 13.03984, + "bbox_y1": 13.32725 + } + }, + { + "pk": 36, + "model": "base.region", + "fields": { + "rght": 332, + "code": "BLR", + "name": "Belarus", + "parent": 5, + "level": 2, + "lft": 331, + "tree_id": 90, + "bbox_x0": 23.17679, + "bbox_x1": 32.77071, + "bbox_y0": 51.256401, + "bbox_y1": 56.16571 + } + }, + { + "pk": 37, + "model": "base.region", + "fields": { + "rght": 334, + "code": "BEL", + "name": "Belgium", + "parent": 5, + "level": 2, + "lft": 333, + "tree_id": 90, + "bbox_x0": 2.54563, + "bbox_x1": 6.40791, + "bbox_y0": 49.496899, + "bbox_y1": 51.505081 + } + }, + { + "pk": 38, + "model": "base.region", + "fields": { + "rght": 189, + "code": "BLZ", + "name": "Belize", + "parent": 3, + "level": 3, + "lft": 188, + "tree_id": 90, + "bbox_x0": -89.224823, + "bbox_x1": -87.468132, + "bbox_y0": 15.8893, + "bbox_y1": 18.49655 + } + }, + { + "pk": 39, + "model": "base.region", + "fields": { + "rght": 87, + "code": "BEN", + "name": "Benin", + "parent": 13, + "level": 3, + "lft": 86, + "tree_id": 90, + "bbox_x0": 0.77456, + "bbox_x1": 3.8517, + "bbox_y0": 6.22574, + "bbox_y1": 12.41834 + } + }, + { + "pk": 40, + "model": "base.region", + "fields": { + "rght": 141, + "code": "BMU", + "name": "Bermuda", + "parent": 255, + "level": 3, + "lft": 140, + "tree_id": 90, + "bbox_x0": -64.896042, + "bbox_x1": -64.642952, + "bbox_y0": 32.230709, + "bbox_y1": 32.393829 + } + }, + { + "pk": 41, + "model": "base.region", + "fields": { + "rght": 281, + "code": "BTN", + "name": "Bhutan", + "parent": 9, + "level": 3, + "lft": 280, + "tree_id": 90, + "bbox_x0": 88.759521, + "bbox_x1": 92.125023, + "bbox_y0": 26.7075, + "bbox_y1": 28.3235 + } + }, + { + "pk": 42, + "model": "base.region", + "fields": { + "rght": 217, + "code": "BOL", + "name": "Bolivia", + "parent": 4, + "level": 3, + "lft": 216, + "tree_id": 90, + "bbox_x0": -69.640762, + "bbox_x1": -57.458092, + "bbox_y0": -22.89613, + "bbox_y1": -9.68056 + } + }, + { + "pk": 43, + "model": "base.region", + "fields": { + "rght": 336, + "code": "BIH", + "name": "Bosnia and Herzegovina", + "parent": 5, + "level": 2, + "lft": 335, + "tree_id": 90, + "bbox_x0": 15.74909, + "bbox_x1": 19.62907, + "bbox_y0": 42.56451, + "bbox_y1": 45.276001 + } + }, + { + "pk": 44, + "model": "base.region", + "fields": { + "rght": 67, + "code": "BWA", + "name": "Botswana", + "parent": 14, + "level": 3, + "lft": 66, + "tree_id": 90, + "bbox_x0": 19.999531, + "bbox_x1": 29.360781, + "bbox_y0": -26.90724, + "bbox_y1": -17.780809 + } + }, + { + "pk": 45, + "model": "base.region", + "fields": { + "rght": 219, + "code": "BRA", + "name": "Brazil", + "parent": 4, + "level": 3, + "lft": 218, + "tree_id": 90, + "bbox_x0": -73.985527, + "bbox_x1": -28.839041, + "bbox_y0": -33.750702, + "bbox_y1": 5.26486 + } + }, + { + "pk": 46, + "model": "base.region", + "fields": { + "rght": 143, + "code": "VGB", + "name": "British Virgin Islands", + "parent": 255, + "level": 3, + "lft": 142, + "tree_id": 90, + "bbox_x0": -64.783012, + "bbox_x1": -64.268761, + "bbox_y0": 18.312731, + "bbox_y1": 18.757219 + } + }, + { + "pk": 47, + "model": "base.region", + "fields": { + "rght": 295, + "code": "BRN", + "name": "Brunei Darussalam", + "parent": 7, + "level": 3, + "lft": 294, + "tree_id": 90, + "bbox_x0": 114.071457, + "bbox_x1": 115.359451, + "bbox_y0": 4.00309, + "bbox_y1": 5.04717 + } + }, + { + "pk": 48, + "model": "base.region", + "fields": { + "rght": 338, + "code": "BGR", + "name": "Bulgaria", + "parent": 5, + "level": 2, + "lft": 337, + "tree_id": 90, + "bbox_x0": 22.35741, + "bbox_x1": 28.60882, + "bbox_y0": 41.235931, + "bbox_y1": 44.227261 + } + }, + { + "pk": 49, + "model": "base.region", + "fields": { + "rght": 89, + "code": "BFA", + "name": "Burkina Faso", + "parent": 13, + "level": 3, + "lft": 88, + "tree_id": 90, + "bbox_x0": -5.51891, + "bbox_x1": 2.40539, + "bbox_y0": 9.4011, + "bbox_y1": 15.08259 + } + }, + { + "pk": 50, + "model": "base.region", + "fields": { + "rght": 15, + "code": "BDI", + "name": "Burundi", + "parent": 12, + "level": 3, + "lft": 14, + "tree_id": 90, + "bbox_x0": 28.993071, + "bbox_x1": 30.847719, + "bbox_y0": -4.46571, + "bbox_y1": -2.31012 + } + }, + { + "pk": 51, + "model": "base.region", + "fields": { + "rght": 297, + "code": "KHM", + "name": "Cambodia", + "parent": 7, + "level": 3, + "lft": 296, + "tree_id": 90, + "bbox_x0": 102.340012, + "bbox_x1": 107.627724, + "bbox_y0": 9.28325, + "bbox_y1": 14.6864 + } + }, + { + "pk": 52, + "model": "base.region", + "fields": { + "rght": 91, + "code": "CMR", + "name": "Cameroon", + "parent": 13, + "level": 3, + "lft": 90, + "tree_id": 90, + "bbox_x0": 8.49477, + "bbox_x1": 16.19211, + "bbox_y0": 1.65254, + "bbox_y1": 13.07805 + } + }, + { + "pk": 53, + "model": "base.region", + "fields": { + "rght": 205, + "code": "CAN", + "name": "Canada", + "parent": 2, + "level": 3, + "lft": 204, + "tree_id": 90, + "bbox_x0": -141.002701, + "bbox_x1": -52.620201, + "bbox_y0": 41.681019, + "bbox_y1": 83.110619 + } + }, + { + "pk": 54, + "model": "base.region", + "fields": { + "rght": 93, + "code": "CPV", + "name": "Cape Verde", + "parent": 13, + "level": 3, + "lft": 92, + "tree_id": 90, + "bbox_x0": -25.35874, + "bbox_x1": -22.666201, + "bbox_y0": 14.80221, + "bbox_y1": 17.19717 + } + }, + { + "pk": 55, + "model": "base.region", + "fields": { + "rght": 145, + "code": "CYM", + "name": "Cayman Islands", + "parent": 255, + "level": 3, + "lft": 144, + "tree_id": 90, + "bbox_x0": -81.420593, + "bbox_x1": -79.722321, + "bbox_y0": 19.262659, + "bbox_y1": 19.75738 + } + }, + { + "pk": 56, + "model": "base.region", + "fields": { + "rght": 5, + "code": "CAF", + "name": "Central African Republic", + "parent": 257, + "level": 3, + "lft": 4, + "tree_id": 90, + "bbox_x0": 14.42009, + "bbox_x1": 27.463421, + "bbox_y0": 2.22051, + "bbox_y1": 11.00756 + } + }, + { + "pk": 57, + "model": "base.region", + "fields": { + "rght": 7, + "code": "TCD", + "name": "Chad", + "parent": 257, + "level": 3, + "lft": 6, + "tree_id": 90, + "bbox_x0": 13.47592, + "bbox_x1": 24.00161, + "bbox_y0": 7.44237, + "bbox_y1": 23.478239 + } + }, + { + "pk": 58, + "model": "base.region", + "fields": { + "rght": 340, + "code": "CIL", + "name": "Channel Islands", + "parent": 5, + "level": 2, + "lft": 339, + "tree_id": 90, + "bbox_x0": -2.67545, + "bbox_x1": -2.01129, + "bbox_y0": 49.16209, + "bbox_y1": 49.7393 + } + }, + { + "pk": 59, + "model": "base.region", + "fields": { + "rght": 221, + "code": "CHL", + "name": "Chile", + "parent": 4, + "level": 3, + "lft": 220, + "tree_id": 90, + "bbox_x0": -109.47493, + "bbox_x1": -66.417549, + "bbox_y0": -56.533779, + "bbox_y1": -17.507549 + } + }, + { + "pk": 60, + "model": "base.region", + "fields": { + "rght": 263, + "code": "CHN", + "name": "China", + "parent": 258, + "level": 3, + "lft": 262, + "tree_id": 90, + "bbox_x0": 73.557701, + "bbox_x1": 134.773605, + "bbox_y0": 15.77539, + "bbox_y1": 53.5606 + } + }, + { + "pk": 61, + "model": "base.region", + "fields": { + "rght": 265, + "code": "HKG", + "name": "China - Hong Kong", + "parent": 258, + "level": 3, + "lft": 264, + "tree_id": 90, + "bbox_x0": 113.835083, + "bbox_x1": 114.441788, + "bbox_y0": 22.153549, + "bbox_y1": 22.56204 + } + }, + { + "pk": 62, + "model": "base.region", + "fields": { + "rght": 267, + "code": "MAC", + "name": "China - Macao", + "parent": 258, + "level": 3, + "lft": 266, + "tree_id": 90, + "bbox_x0": 113.528351, + "bbox_x1": 113.598297, + "bbox_y0": 22.10977, + "bbox_y1": 22.21697 + } + }, + { + "pk": 63, + "model": "base.region", + "fields": { + "rght": 223, + "code": "COL", + "name": "Colombia", + "parent": 4, + "level": 3, + "lft": 222, + "tree_id": 90, + "bbox_x0": -81.728111, + "bbox_x1": -66.869827, + "bbox_y0": -4.23048, + "bbox_y1": 13.39029 + } + }, + { + "pk": 64, + "model": "base.region", + "fields": { + "rght": 17, + "code": "COM", + "name": "Comoros", + "parent": 12, + "level": 3, + "lft": 16, + "tree_id": 90, + "bbox_x0": 43.215778, + "bbox_x1": 44.538219, + "bbox_y0": -12.41382, + "bbox_y1": -11.36238 + } + }, + { + "pk": 65, + "model": "base.region", + "fields": { + "rght": 9, + "code": "COG", + "name": "Congo", + "parent": 257, + "level": 3, + "lft": 8, + "tree_id": 90, + "bbox_x0": 11.205, + "bbox_x1": 18.64983, + "bbox_y0": -5.02831, + "bbox_y1": 3.70308 + } + }, + { + "pk": 66, + "model": "base.region", + "fields": { + "rght": 470, + "code": "COK", + "name": "Cook Islands", + "parent": 256, + "level": 2, + "lft": 469, + "tree_id": 90, + "bbox_x0": -165.858093, + "bbox_x1": -157.312119, + "bbox_y0": -21.94416, + "bbox_y1": -8.94402 + } + }, + { + "pk": 67, + "model": "base.region", + "fields": { + "rght": 191, + "code": "CRI", + "name": "Costa Rica", + "parent": 3, + "level": 3, + "lft": 190, + "tree_id": 90, + "bbox_x0": -87.083778, + "bbox_x1": -82.556, + "bbox_y0": 5.49955, + "bbox_y1": 11.21681 + } + }, + { + "pk": 68, + "model": "base.region", + "fields": { + "rght": 95, + "code": "CIV", + "name": "Cote d'Ivoire", + "parent": 13, + "level": 3, + "lft": 94, + "tree_id": 90, + "bbox_x0": -8.6017249, + "bbox_x1": -2.4930309, + "bbox_y0": 4.1642077, + "bbox_y1": 10.740015 + } + }, + { + "pk": 69, + "model": "base.region", + "fields": { + "rght": 342, + "code": "HRV", + "name": "Croatia", + "parent": 5, + "level": 2, + "lft": 341, + "tree_id": 90, + "bbox_x0": 13.48972, + "bbox_x1": 19.44722, + "bbox_y0": 42.392208, + "bbox_y1": 46.554981 + } + }, + { + "pk": 70, + "model": "base.region", + "fields": { + "rght": 147, + "code": "CUB", + "name": "Cuba", + "parent": 255, + "level": 3, + "lft": 146, + "tree_id": 90, + "bbox_x0": -84.957428, + "bbox_x1": -74.131783, + "bbox_y0": 19.828079, + "bbox_y1": 23.283779 + } + }, + { + "pk": 71, + "model": "base.region", + "fields": { + "rght": 344, + "code": "CYP", + "name": "Cyprus", + "parent": 5, + "level": 2, + "lft": 343, + "tree_id": 90, + "bbox_x0": 32.27309, + "bbox_x1": 34.597919, + "bbox_y0": 34.563511, + "bbox_y1": 35.701542 + } + }, + { + "pk": 72, + "model": "base.region", + "fields": { + "rght": 346, + "code": "CZE", + "name": "Czech Republic", + "parent": 5, + "level": 2, + "lft": 345, + "tree_id": 90, + "bbox_x0": 12.0905901, + "bbox_x1": 18.859216, + "bbox_y0": 48.5518144, + "bbox_y1": 51.0557036 + } + }, + { + "pk": 73, + "model": "base.region", + "fields": { + "rght": 269, + "code": "PRK", + "name": "Democratic People's Republic of Korea", + "parent": 258, + "level": 3, + "lft": 268, + "tree_id": 90, + "bbox_x0": 124.182739, + "bbox_x1": 130.674713, + "bbox_y0": 37.632881, + "bbox_y1": 43.006001 + } + }, + { + "pk": 74, + "model": "base.region", + "fields": { + "rght": 11, + "code": "COD", + "name": "Democratic Republic of the Congo", + "parent": 257, + "level": 3, + "lft": 10, + "tree_id": 90, + "bbox_x0": 12.20663, + "bbox_x1": 31.30591, + "bbox_y0": -13.45567, + "bbox_y1": 5.38609 + } + }, + { + "pk": 75, + "model": "base.region", + "fields": { + "rght": 348, + "code": "DNK", + "name": "Denmark", + "parent": 5, + "level": 2, + "lft": 347, + "tree_id": 90, + "bbox_x0": 8.07472, + "bbox_x1": 15.19324, + "bbox_y0": 54.559132, + "bbox_y1": 57.751949 + } + }, + { + "pk": 76, + "model": "base.region", + "fields": { + "rght": 19, + "code": "DJI", + "name": "Djibouti", + "parent": 12, + "level": 3, + "lft": 18, + "tree_id": 90, + "bbox_x0": 41.773441, + "bbox_x1": 43.450459, + "bbox_y0": 10.90991, + "bbox_y1": 12.70683 + } + }, + { + "pk": 77, + "model": "base.region", + "fields": { + "rght": 149, + "code": "DMA", + "name": "Dominica", + "parent": 255, + "level": 3, + "lft": 148, + "tree_id": 90, + "bbox_x0": -61.4841, + "bbox_x1": -61.244148, + "bbox_y0": 15.20168, + "bbox_y1": 15.6318 + } + }, + { + "pk": 78, + "model": "base.region", + "fields": { + "rght": 151, + "code": "DOM", + "name": "Dominican Republic", + "parent": 255, + "level": 3, + "lft": 150, + "tree_id": 90, + "bbox_x0": -72.003479, + "bbox_x1": -68.319992, + "bbox_y0": 17.469299, + "bbox_y1": 19.92985 + } + }, + { + "pk": 79, + "model": "base.region", + "fields": { + "rght": 225, + "code": "ECU", + "name": "Ecuador", + "parent": 4, + "level": 3, + "lft": 224, + "tree_id": 90, + "bbox_x0": -91.66124, + "bbox_x1": -75.200073, + "bbox_y0": -5.01734, + "bbox_y1": 1.45421 + } + }, + { + "pk": 80, + "model": "base.region", + "fields": { + "rght": 53, + "code": "EGY", + "name": "Egypt", + "parent": 11, + "level": 3, + "lft": 52, + "tree_id": 90, + "bbox_x0": 24.698099, + "bbox_x1": 36.89468, + "bbox_y0": 22, + "bbox_y1": 31.674179 + } + }, + { + "pk": 81, + "model": "base.region", + "fields": { + "rght": 193, + "code": "SLV", + "name": "El Salvador", + "parent": 3, + "level": 3, + "lft": 192, + "tree_id": 90, + "bbox_x0": -90.12867, + "bbox_x1": -87.682869, + "bbox_y0": 13.14867, + "bbox_y1": 14.44506 + } + }, + { + "pk": 82, + "model": "base.region", + "fields": { + "rght": 97, + "code": "GNQ", + "name": "Equatorial Guinea", + "parent": 13, + "level": 3, + "lft": 96, + "tree_id": 90, + "bbox_x0": 5.60236, + "bbox_x1": 11.33572, + "bbox_y0": -1.48378, + "bbox_y1": 3.78597 + } + }, + { + "pk": 83, + "model": "base.region", + "fields": { + "rght": 21, + "code": "ERI", + "name": "Eritrea", + "parent": 12, + "level": 3, + "lft": 20, + "tree_id": 90, + "bbox_x0": 36.43877, + "bbox_x1": 43.14864, + "bbox_y0": 12.35956, + "bbox_y1": 18.00308 + } + }, + { + "pk": 84, + "model": "base.region", + "fields": { + "rght": 350, + "code": "EST", + "name": "Estonia", + "parent": 5, + "level": 2, + "lft": 349, + "tree_id": 90, + "bbox_x0": 21.771851, + "bbox_x1": 28.20989, + "bbox_y0": 57.509312, + "bbox_y1": 59.685749 + } + }, + { + "pk": 85, + "model": "base.region", + "fields": { + "rght": 23, + "code": "ETH", + "name": "Ethiopia", + "parent": 12, + "level": 3, + "lft": 22, + "tree_id": 90, + "bbox_x0": 32.99992, + "bbox_x1": 47.986172, + "bbox_y0": 3.40242, + "bbox_y1": 14.89218 + } + }, + { + "pk": 86, + "model": "base.region", + "fields": { + "rght": 352, + "code": "FRO", + "name": "Faeroe Islands", + "parent": 5, + "level": 2, + "lft": 351, + "tree_id": 90, + "bbox_x0": -7.68124, + "bbox_x1": -6.25861, + "bbox_y0": 61.394932, + "bbox_y1": 62.400742 + } + }, + { + "pk": 87, + "model": "base.region", + "fields": { + "rght": 227, + "code": "FLK", + "name": "Falkland Islands (Malvinas)", + "parent": 4, + "level": 3, + "lft": 226, + "tree_id": 90, + "bbox_x0": -61.43404, + "bbox_x1": -57.712479, + "bbox_y0": -52.900581, + "bbox_y1": -50.966221 + } + }, + { + "pk": 88, + "model": "base.region", + "fields": { + "rght": 472, + "code": "FJI", + "name": "Fiji", + "parent": 256, + "level": 2, + "lft": 471, + "tree_id": 90, + "bbox_x0": 174.866196, + "bbox_x1": -178.203156, + "bbox_y0": -21.01712, + "bbox_y1": -12.46622 + } + }, + { + "pk": 89, + "model": "base.region", + "fields": { + "rght": 354, + "code": "FIN", + "name": "Finland", + "parent": 5, + "level": 2, + "lft": 353, + "tree_id": 90, + "bbox_x0": 20.548571, + "bbox_x1": 31.586201, + "bbox_y0": 59.764881, + "bbox_y1": 70.092308 + } + }, + { + "pk": 90, + "model": "base.region", + "fields": { + "rght": 356, + "code": "FRA", + "name": "France", + "parent": 5, + "level": 2, + "lft": 355, + "tree_id": 90, + "bbox_x0": -5.1406, + "bbox_x1": 9.55932, + "bbox_y0": 41.33374, + "bbox_y1": 51.089062 + } + }, + { + "pk": 91, + "model": "base.region", + "fields": { + "rght": 229, + "code": "GUF", + "name": "French Guiana", + "parent": 4, + "level": 3, + "lft": 228, + "tree_id": 90, + "bbox_x0": -54.542511, + "bbox_x1": -51.613941, + "bbox_y0": 2.12709, + "bbox_y1": 5.77649 + } + }, + { + "pk": 92, + "model": "base.region", + "fields": { + "rght": 474, + "code": "PYF", + "name": "French Polynesia", + "parent": 256, + "level": 2, + "lft": 473, + "tree_id": 90, + "bbox_x0": -154.700485, + "bbox_x1": -108.87291, + "bbox_y0": -27.65357, + "bbox_y1": 10.35983 + } + }, + { + "pk": 93, + "model": "base.region", + "fields": { + "rght": 99, + "code": "GAB", + "name": "Gabon", + "parent": 13, + "level": 3, + "lft": 98, + "tree_id": 90, + "bbox_x0": 8.69547, + "bbox_x1": 14.50234, + "bbox_y0": -3.9788, + "bbox_y1": 2.32261 + } + }, + { + "pk": 94, + "model": "base.region", + "fields": { + "rght": 101, + "code": "GMB", + "name": "Gambia", + "parent": 13, + "level": 3, + "lft": 100, + "tree_id": 90, + "bbox_x0": -16.82506, + "bbox_x1": -13.7978, + "bbox_y0": 13.06425, + "bbox_y1": 13.82657 + } + }, + { + "pk": 95, + "model": "base.region", + "fields": { + "rght": 358, + "code": "GEO", + "name": "Georgia", + "parent": 5, + "level": 2, + "lft": 357, + "tree_id": 90, + "bbox_x0": 40.01022, + "bbox_x1": 46.721359, + "bbox_y0": 41.038502, + "bbox_y1": 43.584549 + } + }, + { + "pk": 96, + "model": "base.region", + "fields": { + "rght": 360, + "code": "DEU", + "name": "Germany", + "parent": 5, + "level": 2, + "lft": 359, + "tree_id": 90, + "bbox_x0": 5.86624, + "bbox_x1": 15.04205, + "bbox_y0": 47.27021, + "bbox_y1": 55.05814 + } + }, + { + "pk": 97, + "model": "base.region", + "fields": { + "rght": 103, + "code": "GHA", + "name": "Ghana", + "parent": 13, + "level": 3, + "lft": 102, + "tree_id": 90, + "bbox_x0": -3.25542, + "bbox_x1": 1.19178, + "bbox_y0": 4.73672, + "bbox_y1": 11.1733 + } + }, + { + "pk": 98, + "model": "base.region", + "fields": { + "rght": 362, + "code": "GIB", + "name": "Gibraltar", + "parent": 5, + "level": 2, + "lft": 361, + "tree_id": 90, + "bbox_x0": -5.3579, + "bbox_x1": -5.33867, + "bbox_y0": 36.108219, + "bbox_y1": 36.15593 + } + }, + { + "pk": 99, + "model": "base.region", + "fields": { + "rght": 364, + "code": "GRC", + "name": "Greece", + "parent": 5, + "level": 2, + "lft": 363, + "tree_id": 90, + "bbox_x0": 19.37431, + "bbox_x1": 29.70056, + "bbox_y0": 34.809502, + "bbox_y1": 41.757111 + } + }, + { + "pk": 100, + "model": "base.region", + "fields": { + "rght": 207, + "code": "GRL", + "name": "Greenland", + "parent": 2, + "level": 3, + "lft": 206, + "tree_id": 90, + "bbox_x0": -73.263474, + "bbox_x1": -11.31232, + "bbox_y0": 59.777271, + "bbox_y1": 83.627419 + } + }, + { + "pk": 101, + "model": "base.region", + "fields": { + "rght": 153, + "code": "GRD", + "name": "Grenada", + "parent": 255, + "level": 3, + "lft": 152, + "tree_id": 90, + "bbox_x0": -61.79998, + "bbox_x1": -61.376362, + "bbox_y0": 11.98288, + "bbox_y1": 12.5415 + } + }, + { + "pk": 102, + "model": "base.region", + "fields": { + "rght": 155, + "code": "GLP", + "name": "Guadeloupe", + "parent": 255, + "level": 3, + "lft": 154, + "tree_id": 90, + "bbox_x0": -61.807159, + "bbox_x1": -61, + "bbox_y0": 15.83097, + "bbox_y1": 16.51684 + } + }, + { + "pk": 103, + "model": "base.region", + "fields": { + "rght": 476, + "code": "GUM", + "name": "Guam", + "parent": 256, + "level": 2, + "lft": 475, + "tree_id": 90, + "bbox_x0": 144.619263, + "bbox_x1": 144.953995, + "bbox_y0": 13.24059, + "bbox_y1": 13.65232 + } + }, + { + "pk": 104, + "model": "base.region", + "fields": { + "rght": 195, + "code": "GTM", + "name": "Guatemala", + "parent": 3, + "level": 3, + "lft": 194, + "tree_id": 90, + "bbox_x0": -92.241432, + "bbox_x1": -88.22319, + "bbox_y0": 13.7373, + "bbox_y1": 17.815201 + } + }, + { + "pk": 105, + "model": "base.region", + "fields": { + "rght": 366, + "code": "GGY", + "name": "Guernsey", + "parent": 5, + "level": 2, + "lft": 365, + "tree_id": 90, + "bbox_x0": -2.67545, + "bbox_x1": -2.16382, + "bbox_y0": 49.405762, + "bbox_y1": 49.7393 + } + }, + { + "pk": 106, + "model": "base.region", + "fields": { + "rght": 105, + "code": "GIN", + "name": "Guinea", + "parent": 13, + "level": 3, + "lft": 104, + "tree_id": 90, + "bbox_x0": -15.08625, + "bbox_x1": -7.64106, + "bbox_y0": 7.19355, + "bbox_y1": 12.67621 + } + }, + { + "pk": 107, + "model": "base.region", + "fields": { + "rght": 107, + "code": "GNB", + "name": "Guinea-Bissau", + "parent": 13, + "level": 3, + "lft": 106, + "tree_id": 90, + "bbox_x0": -16.717529, + "bbox_x1": -13.63652, + "bbox_y0": 10.85997, + "bbox_y1": 12.68078 + } + }, + { + "pk": 108, + "model": "base.region", + "fields": { + "rght": 231, + "code": "GUY", + "name": "Guyana", + "parent": 4, + "level": 3, + "lft": 230, + "tree_id": 90, + "bbox_x0": -61.396271, + "bbox_x1": -56.480251, + "bbox_y0": 1.17508, + "bbox_y1": 8.55756 + } + }, + { + "pk": 109, + "model": "base.region", + "fields": { + "rght": 157, + "code": "HTI", + "name": "Haiti", + "parent": 255, + "level": 3, + "lft": 156, + "tree_id": 90, + "bbox_x0": -74.478592, + "bbox_x1": -71.61335, + "bbox_y0": 18.02103, + "bbox_y1": 20.08782 + } + }, + { + "pk": 110, + "model": "base.region", + "fields": { + "rght": 368, + "code": "VAT", + "name": "Holy See (Vatican City)", + "parent": 5, + "level": 2, + "lft": 367, + "tree_id": 90, + "bbox_x0": 12.44584, + "bbox_x1": 12.45842, + "bbox_y0": 41.900211, + "bbox_y1": 41.907459 + } + }, + { + "pk": 111, + "model": "base.region", + "fields": { + "rght": 197, + "code": "HND", + "name": "Honduras", + "parent": 3, + "level": 3, + "lft": 196, + "tree_id": 90, + "bbox_x0": -89.350792, + "bbox_x1": -82.499527, + "bbox_y0": 12.98241, + "bbox_y1": 17.450451 + } + }, + { + "pk": 112, + "model": "base.region", + "fields": { + "rght": 370, + "code": "HUN", + "name": "Hungary", + "parent": 5, + "level": 2, + "lft": 369, + "tree_id": 90, + "bbox_x0": 16.11335, + "bbox_x1": 22.89657, + "bbox_y0": 45.737061, + "bbox_y1": 48.585258 + } + }, + { + "pk": 113, + "model": "base.region", + "fields": { + "rght": 372, + "code": "ISL", + "name": "Iceland", + "parent": 5, + "level": 2, + "lft": 371, + "tree_id": 90, + "bbox_x0": -24.54652, + "bbox_x1": -13.49416, + "bbox_y0": 63.295952, + "bbox_y1": 66.566193 + } + }, + { + "pk": 114, + "model": "base.region", + "fields": { + "rght": 283, + "code": "IND", + "name": "India", + "parent": 9, + "level": 3, + "lft": 282, + "tree_id": 90, + "bbox_x0": 68.032318, + "bbox_x1": 97.403023, + "bbox_y0": 6.7471, + "bbox_y1": 36.261688 + } + }, + { + "pk": 115, + "model": "base.region", + "fields": { + "rght": 299, + "code": "IDN", + "name": "Indonesia", + "parent": 7, + "level": 3, + "lft": 298, + "tree_id": 90, + "bbox_x0": 94.969833, + "bbox_x1": 141.021805, + "bbox_y0": -11.00485, + "bbox_y1": 6.07573 + } + }, + { + "pk": 116, + "model": "base.region", + "fields": { + "rght": 438, + "code": "IRN", + "name": "Iran", + "parent": 15, + "level": 2, + "lft": 437, + "tree_id": 90, + "bbox_x0": 44.047249, + "bbox_x1": 63.317459, + "bbox_y0": 25.064079, + "bbox_y1": 39.777222 + } + }, + { + "pk": 117, + "model": "base.region", + "fields": { + "rght": 440, + "code": "IRQ", + "name": "Iraq", + "parent": 15, + "level": 2, + "lft": 439, + "tree_id": 90, + "bbox_x0": 38.804001, + "bbox_x1": 48.575699, + "bbox_y0": 29.103001, + "bbox_y1": 37.378052 + } + }, + { + "pk": 118, + "model": "base.region", + "fields": { + "rght": 374, + "code": "IRL", + "name": "Ireland", + "parent": 5, + "level": 2, + "lft": 373, + "tree_id": 90, + "bbox_x0": -10.61834, + "bbox_x1": -5.9975, + "bbox_y0": 51.424511, + "bbox_y1": 55.436211 + } + }, + { + "pk": 119, + "model": "base.region", + "fields": { + "rght": 376, + "code": "IMN", + "name": "Isle of Man", + "parent": 5, + "level": 2, + "lft": 375, + "tree_id": 90, + "bbox_x0": -4.83018, + "bbox_x1": -4.31007, + "bbox_y0": 54.04464, + "bbox_y1": 54.418839 + } + }, + { + "pk": 120, + "model": "base.region", + "fields": { + "rght": 442, + "code": "ISR", + "name": "Israel", + "parent": 15, + "level": 2, + "lft": 441, + "tree_id": 90, + "bbox_x0": 34.2677, + "bbox_x1": 35.940941, + "bbox_y0": 29.4965, + "bbox_y1": 33.43338 + } + }, + { + "pk": 121, + "model": "base.region", + "fields": { + "rght": 378, + "code": "ITA", + "name": "Italy", + "parent": 5, + "level": 2, + "lft": 377, + "tree_id": 90, + "bbox_x0": 6.62665, + "bbox_x1": 18.520281, + "bbox_y0": 35.49308, + "bbox_y1": 47.091999 + } + }, + { + "pk": 122, + "model": "base.region", + "fields": { + "rght": 159, + "code": "JAM", + "name": "Jamaica", + "parent": 255, + "level": 3, + "lft": 158, + "tree_id": 90, + "bbox_x0": -78.366638, + "bbox_x1": -75.982857, + "bbox_y0": 16.949551, + "bbox_y1": 18.52697 + } + }, + { + "pk": 123, + "model": "base.region", + "fields": { + "rght": 271, + "code": "JPN", + "name": "Japan", + "parent": 258, + "level": 3, + "lft": 270, + "tree_id": 90, + "bbox_x0": 122.933647, + "bbox_x1": 153.986847, + "bbox_y0": 20.4251, + "bbox_y1": 45.557709 + } + }, + { + "pk": 124, + "model": "base.region", + "fields": { + "rght": 380, + "code": "JEY", + "name": "Jersey", + "parent": 5, + "level": 2, + "lft": 379, + "tree_id": 90, + "bbox_x0": -2.25505, + "bbox_x1": -2.01129, + "bbox_y0": 49.16209, + "bbox_y1": 49.26231 + } + }, + { + "pk": 125, + "model": "base.region", + "fields": { + "rght": 444, + "code": "JOR", + "name": "Jordan", + "parent": 15, + "level": 2, + "lft": 443, + "tree_id": 90, + "bbox_x0": 34.960232, + "bbox_x1": 39.301128, + "bbox_y0": 29.18409, + "bbox_y1": 33.374828 + } + }, + { + "pk": 126, + "model": "base.region", + "fields": { + "rght": 251, + "code": "KAZ", + "name": "Kazakhstan", + "parent": 8, + "level": 3, + "lft": 250, + "tree_id": 90, + "bbox_x0": 46.491859, + "bbox_x1": 87.312737, + "bbox_y0": 40.566689, + "bbox_y1": 55.431808 + } + }, + { + "pk": 127, + "model": "base.region", + "fields": { + "rght": 25, + "code": "KEN", + "name": "Kenya", + "parent": 12, + "level": 3, + "lft": 24, + "tree_id": 90, + "bbox_x0": 33.90884, + "bbox_x1": 41.899059, + "bbox_y0": -4.71712, + "bbox_y1": 4.62933 + } + }, + { + "pk": 128, + "model": "base.region", + "fields": { + "rght": 478, + "code": "KIR", + "name": "Kiribati", + "parent": 256, + "level": 2, + "lft": 477, + "tree_id": 90, + "bbox_x0": 158.418335, + "bbox_x1": -150.208359, + "bbox_y0": -11.43703, + "bbox_y1": 4.71956 + } + }, + { + "pk": 129, + "model": "base.region", + "fields": { + "rght": 446, + "code": "KWT", + "name": "Kuwait", + "parent": 15, + "level": 2, + "lft": 445, + "tree_id": 90, + "bbox_x0": 46.55751, + "bbox_x1": 48.78384, + "bbox_y0": 28.5245, + "bbox_y1": 30.0958 + } + }, + { + "pk": 130, + "model": "base.region", + "fields": { + "rght": 253, + "code": "KGZ", + "name": "Kyrgyzstan", + "parent": 8, + "level": 3, + "lft": 252, + "tree_id": 90, + "bbox_x0": 69.276619, + "bbox_x1": 80.28318, + "bbox_y0": 39.17284, + "bbox_y1": 43.238239 + } + }, + { + "pk": 131, + "model": "base.region", + "fields": { + "rght": 301, + "code": "LAO", + "name": "Lao People's Democratic Republic", + "parent": 7, + "level": 3, + "lft": 300, + "tree_id": 90, + "bbox_x0": 100.093048, + "bbox_x1": 107.697021, + "bbox_y0": 13.91002, + "bbox_y1": 22.500389 + } + }, + { + "pk": 132, + "model": "base.region", + "fields": { + "rght": 382, + "code": "LVA", + "name": "Latvia", + "parent": 5, + "level": 2, + "lft": 381, + "tree_id": 90, + "bbox_x0": 20.966061, + "bbox_x1": 28.244431, + "bbox_y0": 55.67276, + "bbox_y1": 58.087448 + } + }, + { + "pk": 133, + "model": "base.region", + "fields": { + "rght": 448, + "code": "LBN", + "name": "Lebanon", + "parent": 15, + "level": 2, + "lft": 447, + "tree_id": 90, + "bbox_x0": 35.10368, + "bbox_x1": 36.622791, + "bbox_y0": 33.048908, + "bbox_y1": 34.69268 + } + }, + { + "pk": 134, + "model": "base.region", + "fields": { + "rght": 69, + "code": "LSO", + "name": "Lesotho", + "parent": 14, + "level": 3, + "lft": 68, + "tree_id": 90, + "bbox_x0": 27.02906, + "bbox_x1": 29.465771, + "bbox_y0": -30.668961, + "bbox_y1": -28.57205 + } + }, + { + "pk": 135, + "model": "base.region", + "fields": { + "rght": 109, + "code": "LBR", + "name": "Liberia", + "parent": 13, + "level": 3, + "lft": 108, + "tree_id": 90, + "bbox_x0": -11.49208, + "bbox_x1": -7.36511, + "bbox_y0": 4.35305, + "bbox_y1": 8.55179 + } + }, + { + "pk": 136, + "model": "base.region", + "fields": { + "rght": 55, + "code": "LBY", + "name": "Libyan Arab Jamahiriya", + "parent": 11, + "level": 3, + "lft": 54, + "tree_id": 90, + "bbox_x0": 9.38702, + "bbox_x1": 25.15061, + "bbox_y0": 19.508039, + "bbox_y1": 33.168999 + } + }, + { + "pk": 137, + "model": "base.region", + "fields": { + "rght": 384, + "code": "LIE", + "name": "Liechtenstein", + "parent": 5, + "level": 2, + "lft": 383, + "tree_id": 90, + "bbox_x0": 9.47181, + "bbox_x1": 9.63578, + "bbox_y0": 47.04834, + "bbox_y1": 47.270649 + } + }, + { + "pk": 138, + "model": "base.region", + "fields": { + "rght": 386, + "code": "LTU", + "name": "Lithuania", + "parent": 5, + "level": 2, + "lft": 385, + "tree_id": 90, + "bbox_x0": 20.953199, + "bbox_x1": 26.835581, + "bbox_y0": 53.89748, + "bbox_y1": 56.450432 + } + }, + { + "pk": 139, + "model": "base.region", + "fields": { + "rght": 388, + "code": "LUX", + "name": "Luxembourg", + "parent": 5, + "level": 2, + "lft": 387, + "tree_id": 90, + "bbox_x0": 5.73579, + "bbox_x1": 6.53117, + "bbox_y0": 49.447689, + "bbox_y1": 50.182751 + } + }, + { + "pk": 140, + "model": "base.region", + "fields": { + "rght": 390, + "code": "MKD", + "name": "Macedonia", + "parent": 5, + "level": 2, + "lft": 389, + "tree_id": 90, + "bbox_x0": 20.4645, + "bbox_x1": 23.038071, + "bbox_y0": 40.860111, + "bbox_y1": 42.345501 + } + }, + { + "pk": 141, + "model": "base.region", + "fields": { + "rght": 27, + "code": "MDG", + "name": "Madagascar", + "parent": 12, + "level": 3, + "lft": 26, + "tree_id": 90, + "bbox_x0": 43.19138, + "bbox_x1": 50.483799, + "bbox_y0": -25.60894, + "bbox_y1": -11.94543 + } + }, + { + "pk": 142, + "model": "base.region", + "fields": { + "rght": 29, + "code": "MWI", + "name": "Malawi", + "parent": 12, + "level": 3, + "lft": 28, + "tree_id": 90, + "bbox_x0": 32.668991, + "bbox_x1": 35.920441, + "bbox_y0": -17.129459, + "bbox_y1": -9.36468 + } + }, + { + "pk": 143, + "model": "base.region", + "fields": { + "rght": 303, + "code": "MYS", + "name": "Malaysia", + "parent": 7, + "level": 3, + "lft": 302, + "tree_id": 90, + "bbox_x0": 98.935059, + "bbox_x1": 119.448433, + "bbox_y0": 0.66364, + "bbox_y1": 7.58378 + } + }, + { + "pk": 144, + "model": "base.region", + "fields": { + "rght": 285, + "code": "MDV", + "name": "Maldives", + "parent": 9, + "level": 3, + "lft": 284, + "tree_id": 90, + "bbox_x0": 72.616219, + "bbox_x1": 73.76712, + "bbox_y0": -2.90045, + "bbox_y1": 7.11712 + } + }, + { + "pk": 145, + "model": "base.region", + "fields": { + "rght": 111, + "code": "MLI", + "name": "Mali", + "parent": 13, + "level": 3, + "lft": 110, + "tree_id": 90, + "bbox_x0": -12.24261, + "bbox_x1": 4.24495, + "bbox_y0": 10.15951, + "bbox_y1": 25 + } + }, + { + "pk": 146, + "model": "base.region", + "fields": { + "rght": 392, + "code": "MLT", + "name": "Malta", + "parent": 5, + "level": 2, + "lft": 391, + "tree_id": 90, + "bbox_x0": 14.18341, + "bbox_x1": 14.5766, + "bbox_y0": 35.786282, + "bbox_y1": 36.081821 + } + }, + { + "pk": 147, + "model": "base.region", + "fields": { + "rght": 480, + "code": "MHL", + "name": "Marshall Islands", + "parent": 256, + "level": 2, + "lft": 479, + "tree_id": 90, + "bbox_x0": 162.143265, + "bbox_x1": 172.161987, + "bbox_y0": 4.57487, + "bbox_y1": 14.65516 + } + }, + { + "pk": 148, + "model": "base.region", + "fields": { + "rght": 161, + "code": "MTQ", + "name": "Martinique", + "parent": 255, + "level": 3, + "lft": 160, + "tree_id": 90, + "bbox_x0": -61.23011, + "bbox_x1": -60.81551, + "bbox_y0": 14.38244, + "bbox_y1": 14.87881 + } + }, + { + "pk": 149, + "model": "base.region", + "fields": { + "rght": 113, + "code": "MRT", + "name": "Mauritania", + "parent": 13, + "level": 3, + "lft": 112, + "tree_id": 90, + "bbox_x0": -17.066521, + "bbox_x1": -4.8352, + "bbox_y0": 14.71554, + "bbox_y1": 27.298071 + } + }, + { + "pk": 150, + "model": "base.region", + "fields": { + "rght": 31, + "code": "MUS", + "name": "Mauritius", + "parent": 12, + "level": 3, + "lft": 30, + "tree_id": 90, + "bbox_x0": 56.512711, + "bbox_x1": 63.525379, + "bbox_y0": -20.525709, + "bbox_y1": -10.31925 + } + }, + { + "pk": 151, + "model": "base.region", + "fields": { + "rght": 33, + "code": "MYT", + "name": "Mayotte", + "parent": 12, + "level": 3, + "lft": 32, + "tree_id": 90, + "bbox_x0": 45.01461, + "bbox_x1": 45.317131, + "bbox_y0": -13.00045, + "bbox_y1": -12.63383 + } + }, + { + "pk": 152, + "model": "base.region", + "fields": { + "rght": 209, + "code": "MEX", + "name": "Mexico", + "parent": 2, + "level": 3, + "lft": 208, + "tree_id": 90, + "bbox_x0": -118.867172, + "bbox_x1": -86.703392, + "bbox_y0": 14.53285, + "bbox_y1": 32.71862 + } + }, + { + "pk": 153, + "model": "base.region", + "fields": { + "rght": 482, + "code": "FSM", + "name": "Micronesia, Federated States of", + "parent": 256, + "level": 2, + "lft": 481, + "tree_id": 90, + "bbox_x0": 138.052856, + "bbox_x1": 163.034912, + "bbox_y0": 5.25984, + "bbox_y1": 10.02222 + } + }, + { + "pk": 154, + "model": "base.region", + "fields": { + "rght": 394, + "code": "MCO", + "name": "Monaco", + "parent": 5, + "level": 2, + "lft": 393, + "tree_id": 90, + "bbox_x0": 7.4091, + "bbox_x1": 7.43948, + "bbox_y0": 43.724789, + "bbox_y1": 43.7519 + } + }, + { + "pk": 155, + "model": "base.region", + "fields": { + "rght": 273, + "code": "MNG", + "name": "Mongolia", + "parent": 258, + "level": 3, + "lft": 272, + "tree_id": 90, + "bbox_x0": 87.749496, + "bbox_x1": 119.92411, + "bbox_y0": 41.567501, + "bbox_y1": 52.154099 + } + }, + { + "pk": 156, + "model": "base.region", + "fields": { + "rght": 396, + "code": "MNE", + "name": "Montenegro", + "parent": 5, + "level": 2, + "lft": 395, + "tree_id": 90, + "bbox_x0": 18.43705, + "bbox_x1": 20.41608, + "bbox_y0": 41.84808, + "bbox_y1": 43.542912 + } + }, + { + "pk": 157, + "model": "base.region", + "fields": { + "rght": 163, + "code": "MSR", + "name": "Montserrat", + "parent": 255, + "level": 3, + "lft": 162, + "tree_id": 90, + "bbox_x0": -62.24258, + "bbox_x1": -62.14642, + "bbox_y0": 16.671, + "bbox_y1": 16.81732 + } + }, + { + "pk": 158, + "model": "base.region", + "fields": { + "rght": 57, + "code": "MAR", + "name": "Morocco", + "parent": 11, + "level": 3, + "lft": 56, + "tree_id": 90, + "bbox_x0": -11.7805, + "bbox_x1": -1.02441, + "bbox_y0": 26.946489, + "bbox_y1": 35.921909 + } + }, + { + "pk": 159, + "model": "base.region", + "fields": { + "rght": 35, + "code": "MOZ", + "name": "Mozambique", + "parent": 12, + "level": 3, + "lft": 34, + "tree_id": 90, + "bbox_x0": 30.21731, + "bbox_x1": 40.844471, + "bbox_y0": -26.868679, + "bbox_y1": -10.47188 + } + }, + { + "pk": 160, + "model": "base.region", + "fields": { + "rght": 305, + "code": "MMR", + "name": "Myanmar", + "parent": 7, + "level": 3, + "lft": 304, + "tree_id": 90, + "bbox_x0": 92.189209, + "bbox_x1": 101.176788, + "bbox_y0": 9.60035, + "bbox_y1": 28.543249 + } + }, + { + "pk": 161, + "model": "base.region", + "fields": { + "rght": 71, + "code": "NMB", + "name": "Namibia", + "parent": 14, + "level": 3, + "lft": 70, + "tree_id": 90, + "bbox_x0": 11.71563, + "bbox_x1": 25.256701, + "bbox_y0": -28.97142, + "bbox_y1": -16.95989 + } + }, + { + "pk": 162, + "model": "base.region", + "fields": { + "rght": 484, + "code": "NRU", + "name": "Nauru", + "parent": 256, + "level": 2, + "lft": 483, + "tree_id": 90, + "bbox_x0": 166.899017, + "bbox_x1": 166.945267, + "bbox_y0": -0.55232, + "bbox_y1": -0.50429 + } + }, + { + "pk": 163, + "model": "base.region", + "fields": { + "rght": 287, + "code": "NPL", + "name": "Nepal", + "parent": 9, + "level": 3, + "lft": 286, + "tree_id": 90, + "bbox_x0": 80.056221, + "bbox_x1": 88.199318, + "bbox_y0": 26.356501, + "bbox_y1": 30.433001 + } + }, + { + "pk": 164, + "model": "base.region", + "fields": { + "rght": 398, + "code": "NLD", + "name": "Netherlands", + "parent": 5, + "level": 2, + "lft": 397, + "tree_id": 90, + "bbox_x0": 3.35794, + "bbox_x1": 7.2267, + "bbox_y0": 50.750401, + "bbox_y1": 53.554241 + } + }, + { + "pk": 165, + "model": "base.region", + "fields": { + "rght": 165, + "code": "NAN", + "name": "Netherlands Antilles", + "parent": 255, + "level": 3, + "lft": 164, + "tree_id": 90, + "bbox_x0": -69.157188, + "bbox_x1": -62.943661, + "bbox_y0": 11.97318, + "bbox_y1": 18.07024 + } + }, + { + "pk": 166, + "model": "base.region", + "fields": { + "rght": 486, + "code": "NCL", + "name": "New Caledonia", + "parent": 256, + "level": 2, + "lft": 485, + "tree_id": 90, + "bbox_x0": 158.332855, + "bbox_x1": 172.061417, + "bbox_y0": -22.90045, + "bbox_y1": -18.01622 + } + }, + { + "pk": 167, + "model": "base.region", + "fields": { + "rght": 488, + "code": "NZL", + "name": "New Zealand", + "parent": 256, + "level": 2, + "lft": 487, + "tree_id": 90, + "bbox_x0": 165.883804, + "bbox_x1": -175.987198, + "bbox_y0": -52.618591, + "bbox_y1": -29.20997 + } + }, + { + "pk": 168, + "model": "base.region", + "fields": { + "rght": 199, + "code": "NIC", + "name": "Nicaragua", + "parent": 3, + "level": 3, + "lft": 198, + "tree_id": 90, + "bbox_x0": -87.6903, + "bbox_x1": -82.592072, + "bbox_y0": 10.70754, + "bbox_y1": 15.0259 + } + }, + { + "pk": 169, + "model": "base.region", + "fields": { + "rght": 115, + "code": "NER", + "name": "Niger", + "parent": 13, + "level": 3, + "lft": 114, + "tree_id": 90, + "bbox_x0": 0.16625, + "bbox_x1": 15.99564, + "bbox_y0": 11.69697, + "bbox_y1": 23.525021 + } + }, + { + "pk": 170, + "model": "base.region", + "fields": { + "rght": 117, + "code": "NGA", + "name": "Nigeria", + "parent": 13, + "level": 3, + "lft": 116, + "tree_id": 90, + "bbox_x0": 2.66844, + "bbox_x1": 14.68006, + "bbox_y0": 4.27714, + "bbox_y1": 13.892 + } + }, + { + "pk": 171, + "model": "base.region", + "fields": { + "rght": 490, + "code": "NIU", + "name": "Niue", + "parent": 256, + "level": 2, + "lft": 489, + "tree_id": 90, + "bbox_x0": -169.951004, + "bbox_x1": -169.775177, + "bbox_y0": -19.152189, + "bbox_y1": -18.951059 + } + }, + { + "pk": 172, + "model": "base.region", + "fields": { + "rght": 492, + "code": "NFK", + "name": "Norfolk Island", + "parent": 256, + "level": 2, + "lft": 491, + "tree_id": 90, + "bbox_x0": 167.949493, + "bbox_x1": 168.091614, + "bbox_y0": -29.11937, + "bbox_y1": -28.99493 + } + }, + { + "pk": 173, + "model": "base.region", + "fields": { + "rght": 494, + "code": "MNP", + "name": "Northern Mariana Islands", + "parent": 256, + "level": 2, + "lft": 493, + "tree_id": 90, + "bbox_x0": 136.082855, + "bbox_x1": 146.081223, + "bbox_y0": 14.10735, + "bbox_y1": 20.41712 + } + }, + { + "pk": 174, + "model": "base.region", + "fields": { + "rght": 400, + "code": "NOR", + "name": "Norway", + "parent": 5, + "level": 2, + "lft": 399, + "tree_id": 90, + "bbox_x0": 4.43292, + "bbox_x1": 31.168409, + "bbox_y0": 57.962582, + "bbox_y1": 71.185509 + } + }, + { + "pk": 175, + "model": "base.region", + "fields": { + "rght": 450, + "code": "PSE", + "name": "Occupied Palestinian Territory", + "parent": 15, + "level": 2, + "lft": 449, + "tree_id": 90, + "bbox_x0": 34.230461, + "bbox_x1": 35.876499, + "bbox_y0": 31.223499, + "bbox_y1": 33.340099 + } + }, + { + "pk": 176, + "model": "base.region", + "fields": { + "rght": 452, + "code": "OMN", + "name": "Oman", + "parent": 15, + "level": 2, + "lft": 451, + "tree_id": 90, + "bbox_x0": 51.882011, + "bbox_x1": 59.83651, + "bbox_y0": 16.6457, + "bbox_y1": 26.50045 + } + }, + { + "pk": 177, + "model": "base.region", + "fields": { + "rght": 289, + "code": "PAK", + "name": "Pakistan", + "parent": 9, + "level": 3, + "lft": 288, + "tree_id": 90, + "bbox_x0": 60.87859, + "bbox_x1": 77.840813, + "bbox_y0": 23.786699, + "bbox_y1": 37.097 + } + }, + { + "pk": 178, + "model": "base.region", + "fields": { + "rght": 496, + "code": "PLW", + "name": "Palau", + "parent": 256, + "level": 2, + "lft": 495, + "tree_id": 90, + "bbox_x0": 131.169235, + "bbox_x1": 134.723724, + "bbox_y0": 3.00114, + "bbox_y1": 8.09291 + } + }, + { + "pk": 179, + "model": "base.region", + "fields": { + "rght": 201, + "code": "PAN", + "name": "Panama", + "parent": 3, + "level": 3, + "lft": 200, + "tree_id": 90, + "bbox_x0": -83.051453, + "bbox_x1": -77.17411, + "bbox_y0": 7.1979, + "bbox_y1": 9.65045 + } + }, + { + "pk": 180, + "model": "base.region", + "fields": { + "rght": 498, + "code": "PNG", + "name": "Papua New Guinea", + "parent": 256, + "level": 2, + "lft": 497, + "tree_id": 90, + "bbox_x0": 140.842865, + "bbox_x1": 159.48378, + "bbox_y0": -11.65785, + "bbox_y1": -0.86622 + } + }, + { + "pk": 181, + "model": "base.region", + "fields": { + "rght": 233, + "code": "PRY", + "name": "Paraguay", + "parent": 4, + "level": 3, + "lft": 232, + "tree_id": 90, + "bbox_x0": -62.647072, + "bbox_x1": -54.25935, + "bbox_y0": -27.60873, + "bbox_y1": -19.294041 + } + }, + { + "pk": 182, + "model": "base.region", + "fields": { + "rght": 235, + "code": "PER", + "name": "Peru", + "parent": 4, + "level": 3, + "lft": 234, + "tree_id": 90, + "bbox_x0": -81.326736, + "bbox_x1": -68.677979, + "bbox_y0": -18.34972, + "bbox_y1": -0.01297 + } + }, + { + "pk": 183, + "model": "base.region", + "fields": { + "rght": 307, + "code": "PHL", + "name": "Philippines", + "parent": 7, + "level": 3, + "lft": 306, + "tree_id": 90, + "bbox_x0": 116.812721, + "bbox_x1": 126.856628, + "bbox_y0": 4.46811, + "bbox_y1": 21.23415 + } + }, + { + "pk": 184, + "model": "base.region", + "fields": { + "rght": 500, + "code": "PCN", + "name": "Pitcairn", + "parent": 256, + "level": 2, + "lft": 499, + "tree_id": 90, + "bbox_x0": -130.746033, + "bbox_x1": -124.772842, + "bbox_y0": -25.07752, + "bbox_y1": -23.917271 + } + }, + { + "pk": 185, + "model": "base.region", + "fields": { + "rght": 402, + "code": "POL", + "name": "Poland", + "parent": 5, + "level": 2, + "lft": 401, + "tree_id": 90, + "bbox_x0": 14.12281, + "bbox_x1": 24.145781, + "bbox_y0": 49.002022, + "bbox_y1": 54.835812 + } + }, + { + "pk": 186, + "model": "base.region", + "fields": { + "rght": 404, + "code": "PRT", + "name": "Portugal", + "parent": 5, + "level": 2, + "lft": 403, + "tree_id": 90, + "bbox_x0": -31.266001, + "bbox_x1": -6.18931, + "bbox_y0": 30.028061, + "bbox_y1": 42.154121 + } + }, + { + "pk": 187, + "model": "base.region", + "fields": { + "rght": 167, + "code": "PRI", + "name": "Puerto Rico", + "parent": 255, + "level": 3, + "lft": 166, + "tree_id": 90, + "bbox_x0": -67.942719, + "bbox_x1": -65.219978, + "bbox_y0": 17.883039, + "bbox_y1": 18.520161 + } + }, + { + "pk": 188, + "model": "base.region", + "fields": { + "rght": 454, + "code": "QAT", + "name": "Qatar", + "parent": 15, + "level": 2, + "lft": 453, + "tree_id": 90, + "bbox_x0": 50.757011, + "bbox_x1": 52.427509, + "bbox_y0": 24.482901, + "bbox_y1": 26.177509 + } + }, + { + "pk": 189, + "model": "base.region", + "fields": { + "rght": 275, + "code": "KOR", + "name": "Republic of Korea", + "parent": 258, + "level": 3, + "lft": 274, + "tree_id": 90, + "bbox_x0": 124.608147, + "bbox_x1": 130.933899, + "bbox_y0": 33.10611, + "bbox_y1": 38.612301 + } + }, + { + "pk": 190, + "model": "base.region", + "fields": { + "rght": 406, + "code": "MDA", + "name": "Republic of Moldova", + "parent": 5, + "level": 2, + "lft": 405, + "tree_id": 90, + "bbox_x0": 26.618879, + "bbox_x1": 30.16374, + "bbox_y0": 45.468498, + "bbox_y1": 48.490162 + } + }, + { + "pk": 191, + "model": "base.region", + "fields": { + "rght": 37, + "code": "REU", + "name": "Reunion", + "parent": 12, + "level": 3, + "lft": 36, + "tree_id": 90, + "bbox_x0": 55.219082, + "bbox_x1": 55.845039, + "bbox_y0": -21.37221, + "bbox_y1": -20.85685 + } + }, + { + "pk": 192, + "model": "base.region", + "fields": { + "rght": 408, + "code": "ROU", + "name": "Romania", + "parent": 5, + "level": 2, + "lft": 407, + "tree_id": 90, + "bbox_x0": 20.269791, + "bbox_x1": 29.691, + "bbox_y0": 43.626999, + "bbox_y1": 48.266891 + } + }, + { + "pk": 193, + "model": "base.region", + "fields": { + "rght": 410, + "code": "RUS", + "name": "Russian Federation", + "parent": 5, + "level": 2, + "lft": 409, + "tree_id": 90, + "bbox_x0": 19.638861, + "bbox_x1": 180, + "bbox_y0": 41.185902, + "bbox_y1": 81.856903 + } + }, + { + "pk": 194, + "model": "base.region", + "fields": { + "rght": 39, + "code": "RWA", + "name": "Rwanda", + "parent": 12, + "level": 3, + "lft": 38, + "tree_id": 90, + "bbox_x0": 28.8568, + "bbox_x1": 30.89596, + "bbox_y0": -2.84067, + "bbox_y1": -1.05348 + } + }, + { + "pk": 195, + "model": "base.region", + "fields": { + "rght": 73, + "code": "SHN", + "name": "Saint Helena", + "parent": 14, + "level": 3, + "lft": 72, + "tree_id": 90, + "bbox_x0": -14.44153, + "bbox_x1": -5.63286, + "bbox_y0": -40.400452, + "bbox_y1": -7.87757 + } + }, + { + "pk": 196, + "model": "base.region", + "fields": { + "rght": 169, + "code": "KNA", + "name": "Saint Kitts and Nevis", + "parent": 255, + "level": 3, + "lft": 168, + "tree_id": 90, + "bbox_x0": -62.86956, + "bbox_x1": -62.543259, + "bbox_y0": 17.095341, + "bbox_y1": 17.420111 + } + }, + { + "pk": 197, + "model": "base.region", + "fields": { + "rght": 171, + "code": "LCA", + "name": "Saint Lucia", + "parent": 255, + "level": 3, + "lft": 170, + "tree_id": 90, + "bbox_x0": -61.07415, + "bbox_x1": -60.866051, + "bbox_y0": 13.70477, + "bbox_y1": 14.10324 + } + }, + { + "pk": 198, + "model": "base.region", + "fields": { + "rght": 173, + "code": "SPM", + "name": "Saint Pierre and Miquelon", + "parent": 255, + "level": 3, + "lft": 172, + "tree_id": 90, + "bbox_x0": -56.420658, + "bbox_x1": -56.157372, + "bbox_y0": 46.753269, + "bbox_y1": 47.14629 + } + }, + { + "pk": 199, + "model": "base.region", + "fields": { + "rght": 175, + "code": "VCT", + "name": "Saint Vincent and the Grenadines", + "parent": 255, + "level": 3, + "lft": 174, + "tree_id": 90, + "bbox_x0": -61.459251, + "bbox_x1": -61.11388, + "bbox_y0": 12.58101, + "bbox_y1": 13.37783 + } + }, + { + "pk": 200, + "model": "base.region", + "fields": { + "rght": 177, + "code": "BLM", + "name": "Saint-Barthelemy", + "parent": 255, + "level": 3, + "lft": 176, + "tree_id": 90, + "bbox_x0": -62.9338, + "bbox_x1": -62.78286, + "bbox_y0": 17.86622, + "bbox_y1": 17.968599 + } + }, + { + "pk": 201, + "model": "base.region", + "fields": { + "rght": 179, + "code": "MAF", + "name": "Saint-Martin (French part)", + "parent": 255, + "level": 3, + "lft": 178, + "tree_id": 90, + "bbox_x0": -63.15276, + "bbox_x1": -62.972778, + "bbox_y0": 18.052231, + "bbox_y1": 18.13069 + } + }, + { + "pk": 202, + "model": "base.region", + "fields": { + "rght": 502, + "code": "WSM", + "name": "Samoa", + "parent": 256, + "level": 2, + "lft": 501, + "tree_id": 90, + "bbox_x0": -172.798584, + "bbox_x1": -171.33287, + "bbox_y0": -14.06353, + "bbox_y1": -13.4322 + } + }, + { + "pk": 203, + "model": "base.region", + "fields": { + "rght": 412, + "code": "SMR", + "name": "San Marino", + "parent": 5, + "level": 2, + "lft": 411, + "tree_id": 90, + "bbox_x0": 12.40306, + "bbox_x1": 12.51651, + "bbox_y0": 43.893299, + "bbox_y1": 43.992168 + } + }, + { + "pk": 204, + "model": "base.region", + "fields": { + "rght": 119, + "code": "STP", + "name": "Sao Tome and Principe", + "parent": 13, + "level": 3, + "lft": 118, + "tree_id": 90, + "bbox_x0": 5.59955, + "bbox_x1": 7.46637, + "bbox_y0": -0.014, + "bbox_y1": 1.73378 + } + }, + { + "pk": 205, + "model": "base.region", + "fields": { + "rght": 456, + "code": "SAU", + "name": "Saudi Arabia", + "parent": 15, + "level": 2, + "lft": 455, + "tree_id": 90, + "bbox_x0": 34.508282, + "bbox_x1": 55.666672, + "bbox_y0": 16.261169, + "bbox_y1": 32.173481 + } + }, + { + "pk": 206, + "model": "base.region", + "fields": { + "rght": 121, + "code": "SEN", + "name": "Senegal", + "parent": 13, + "level": 3, + "lft": 120, + "tree_id": 90, + "bbox_x0": -17.535231, + "bbox_x1": -11.35588, + "bbox_y0": 12.30727, + "bbox_y1": 16.691629 + } + }, + { + "pk": 207, + "model": "base.region", + "fields": { + "rght": 414, + "code": "SRB", + "name": "Serbia", + "parent": 5, + "level": 2, + "lft": 413, + "tree_id": 90, + "bbox_x0": 18.814581, + "bbox_x1": 23.007, + "bbox_y0": 41.908611, + "bbox_y1": 46.191002 + } + }, + { + "pk": 208, + "model": "base.region", + "fields": { + "rght": 41, + "code": "SYC", + "name": "Seychelles", + "parent": 12, + "level": 3, + "lft": 40, + "tree_id": 90, + "bbox_x0": 46.199211, + "bbox_x1": 56.279499, + "bbox_y0": -10.21712, + "bbox_y1": -3.71151 + } + }, + { + "pk": 209, + "model": "base.region", + "fields": { + "rght": 123, + "code": "SLE", + "name": "Sierra Leone", + "parent": 13, + "level": 3, + "lft": 122, + "tree_id": 90, + "bbox_x0": -13.30763, + "bbox_x1": -10.28423, + "bbox_y0": 6.92868, + "bbox_y1": 10.00043 + } + }, + { + "pk": 210, + "model": "base.region", + "fields": { + "rght": 309, + "code": "SGP", + "name": "Singapore", + "parent": 7, + "level": 3, + "lft": 308, + "tree_id": 90, + "bbox_x0": 103.618248, + "bbox_x1": 104.40847, + "bbox_y0": 1.1158, + "bbox_y1": 1.47062 + } + }, + { + "pk": 211, + "model": "base.region", + "fields": { + "rght": 416, + "code": "SVK", + "name": "Slovakia", + "parent": 5, + "level": 2, + "lft": 415, + "tree_id": 90, + "bbox_x0": 16.833179, + "bbox_x1": 22.570299, + "bbox_y0": 47.728001, + "bbox_y1": 49.603001 + } + }, + { + "pk": 212, + "model": "base.region", + "fields": { + "rght": 418, + "code": "SVN", + "name": "Slovenia", + "parent": 5, + "level": 2, + "lft": 417, + "tree_id": 90, + "bbox_x0": 13.37551, + "bbox_x1": 16.59656, + "bbox_y0": 45.416, + "bbox_y1": 46.87788 + } + }, + { + "pk": 213, + "model": "base.region", + "fields": { + "rght": 504, + "code": "SLB", + "name": "Solomon Islands", + "parent": 256, + "level": 2, + "lft": 503, + "tree_id": 90, + "bbox_x0": 155.508667, + "bbox_x1": 170.200455, + "bbox_y0": -12.2919, + "bbox_y1": -5.16622 + } + }, + { + "pk": 214, + "model": "base.region", + "fields": { + "rght": 43, + "code": "SOM", + "name": "Somalia", + "parent": 12, + "level": 3, + "lft": 42, + "tree_id": 90, + "bbox_x0": 40.988628, + "bbox_x1": 51.413029, + "bbox_y0": -1.66205, + "bbox_y1": 11.9852 + } + }, + { + "pk": 215, + "model": "base.region", + "fields": { + "rght": 75, + "code": "ZAF", + "name": "South Africa", + "parent": 14, + "level": 3, + "lft": 74, + "tree_id": 90, + "bbox_x0": 16.46841, + "bbox_x1": 37.993172, + "bbox_y0": -46.990009, + "bbox_y1": -22.12472 + } + }, + { + "pk": 216, + "model": "base.region", + "fields": { + "rght": 420, + "code": "ESP", + "name": "Spain", + "parent": 5, + "level": 2, + "lft": 419, + "tree_id": 90, + "bbox_x0": -18.160789, + "bbox_x1": 4.32788, + "bbox_y0": 27.63546, + "bbox_y1": 43.789959 + } + }, + { + "pk": 217, + "model": "base.region", + "fields": { + "rght": 291, + "code": "LKA", + "name": "Sri Lanka", + "parent": 9, + "level": 3, + "lft": 290, + "tree_id": 90, + "bbox_x0": 79.516212, + "bbox_x1": 81.88121, + "bbox_y0": 5.9167, + "bbox_y1": 9.8312 + } + }, + { + "pk": 218, + "model": "base.region", + "fields": { + "rght": 59, + "code": "SDN", + "name": "Sudan", + "parent": 11, + "level": 3, + "lft": 58, + "tree_id": 90, + "bbox_x0": 21.83894, + "bbox_x1": 38.833801, + "bbox_y0": 3.48639, + "bbox_y1": 23.146891 + } + }, + { + "pk": 219, + "model": "base.region", + "fields": { + "rght": 237, + "code": "SUR", + "name": "Suriname", + "parent": 4, + "level": 3, + "lft": 236, + "tree_id": 90, + "bbox_x0": -58.086559, + "bbox_x1": -53.977489, + "bbox_y0": 1.83114, + "bbox_y1": 6.00454 + } + }, + { + "pk": 220, + "model": "base.region", + "fields": { + "rght": 422, + "code": "SJM", + "name": "Svalbard and Jan Mayen Islands", + "parent": 5, + "level": 2, + "lft": 421, + "tree_id": 90, + "bbox_x0": -9.07989, + "bbox_x1": 36.815269, + "bbox_y0": 70.82737, + "bbox_y1": 80.834061 + } + }, + { + "pk": 221, + "model": "base.region", + "fields": { + "rght": 77, + "code": "SWZ", + "name": "Swaziland", + "parent": 14, + "level": 3, + "lft": 76, + "tree_id": 90, + "bbox_x0": 30.7941, + "bbox_x1": 32.137272, + "bbox_y0": -27.317101, + "bbox_y1": -25.719641 + } + }, + { + "pk": 222, + "model": "base.region", + "fields": { + "rght": 424, + "code": "SWE", + "name": "Sweden", + "parent": 5, + "level": 2, + "lft": 423, + "tree_id": 90, + "bbox_x0": 10.9661, + "bbox_x1": 24.16634, + "bbox_y0": 55.33696, + "bbox_y1": 69.059937 + } + }, + { + "pk": 223, + "model": "base.region", + "fields": { + "rght": 426, + "code": "CHE", + "name": "Switzerland", + "parent": 5, + "level": 2, + "lft": 425, + "tree_id": 90, + "bbox_x0": 5.95587, + "bbox_x1": 10.49203, + "bbox_y0": 45.81802, + "bbox_y1": 47.80838 + } + }, + { + "pk": 224, + "model": "base.region", + "fields": { + "rght": 458, + "code": "SYR", + "name": "Syrian Arab Republic", + "parent": 15, + "level": 2, + "lft": 457, + "tree_id": 90, + "bbox_x0": 35.727001, + "bbox_x1": 42.384998, + "bbox_y0": 32.3106, + "bbox_y1": 37.319 + } + }, + { + "pk": 225, + "model": "base.region", + "fields": { + "rght": 255, + "code": "TJK", + "name": "Tajikistan", + "parent": 8, + "level": 3, + "lft": 254, + "tree_id": 90, + "bbox_x0": 67.387131, + "bbox_x1": 75.137222, + "bbox_y0": 36.674141, + "bbox_y1": 41.04224 + } + }, + { + "pk": 226, + "model": "base.region", + "fields": { + "rght": 311, + "code": "THA", + "name": "Thailand", + "parent": 7, + "level": 3, + "lft": 310, + "tree_id": 90, + "bbox_x0": 97.343964, + "bbox_x1": 105.636917, + "bbox_y0": 5.61257, + "bbox_y1": 20.464701 + } + }, + { + "pk": 227, + "model": "base.region", + "fields": { + "rght": 313, + "code": "TLS", + "name": "Timor-Leste", + "parent": 7, + "level": 3, + "lft": 312, + "tree_id": 90, + "bbox_x0": 124.075439, + "bbox_x1": 127.345337, + "bbox_y0": -9.51337, + "bbox_y1": -8.13741 + } + }, + { + "pk": 228, + "model": "base.region", + "fields": { + "rght": 125, + "code": "TGO", + "name": "Togo", + "parent": 13, + "level": 3, + "lft": 124, + "tree_id": 90, + "bbox_x0": -0.14731, + "bbox_x1": 1.80669, + "bbox_y0": 6.10441, + "bbox_y1": 11.13897 + } + }, + { + "pk": 229, + "model": "base.region", + "fields": { + "rght": 506, + "code": "TKL", + "name": "Tokelau", + "parent": 256, + "level": 2, + "lft": 505, + "tree_id": 90, + "bbox_x0": -172.517136, + "bbox_x1": -171.182083, + "bbox_y0": -9.43378, + "bbox_y1": -8.53288 + } + }, + { + "pk": 230, + "model": "base.region", + "fields": { + "rght": 508, + "code": "TON", + "name": "Tonga", + "parent": 256, + "level": 2, + "lft": 507, + "tree_id": 90, + "bbox_x0": -176.212646, + "bbox_x1": -173.702438, + "bbox_y0": -22.345711, + "bbox_y1": -15.55326 + } + }, + { + "pk": 231, + "model": "base.region", + "fields": { + "rght": 181, + "code": "TTO", + "name": "Trinidad and Tobago", + "parent": 255, + "level": 3, + "lft": 180, + "tree_id": 90, + "bbox_x0": -61.927391, + "bbox_x1": -60.49144, + "bbox_y0": 10.03648, + "bbox_y1": 11.36118 + } + }, + { + "pk": 232, + "model": "base.region", + "fields": { + "rght": 61, + "code": "TUN", + "name": "Tunisia", + "parent": 11, + "level": 3, + "lft": 60, + "tree_id": 90, + "bbox_x0": 7.52481, + "bbox_x1": 11.59827, + "bbox_y0": 30.240431, + "bbox_y1": 37.56712 + } + }, + { + "pk": 233, + "model": "base.region", + "fields": { + "rght": 428, + "code": "TUR", + "name": "Turkey", + "parent": 5, + "level": 2, + "lft": 427, + "tree_id": 90, + "bbox_x0": 25.664101, + "bbox_x1": 44.8297, + "bbox_y0": 35.809971, + "bbox_y1": 42.105499 + } + }, + { + "pk": 234, + "model": "base.region", + "fields": { + "rght": 257, + "code": "TKM", + "name": "Turkmenistan", + "parent": 8, + "level": 3, + "lft": 256, + "tree_id": 90, + "bbox_x0": 52.441429, + "bbox_x1": 66.684303, + "bbox_y0": 35.14109, + "bbox_y1": 42.795551 + } + }, + { + "pk": 235, + "model": "base.region", + "fields": { + "rght": 183, + "code": "TCA", + "name": "Turks and Caicos Islands", + "parent": 255, + "level": 3, + "lft": 182, + "tree_id": 90, + "bbox_x0": -72.483879, + "bbox_x1": -71.08033, + "bbox_y0": 21.170031, + "bbox_y1": 21.97361 + } + }, + { + "pk": 236, + "model": "base.region", + "fields": { + "rght": 510, + "code": "TUV", + "name": "Tuvalu", + "parent": 256, + "level": 2, + "lft": 509, + "tree_id": 90, + "bbox_x0": 176.06488, + "bbox_x1": 179.883789, + "bbox_y0": -10.75045, + "bbox_y1": -5.64198 + } + }, + { + "pk": 237, + "model": "base.region", + "fields": { + "rght": 45, + "code": "UGA", + "name": "Uganda", + "parent": 12, + "level": 3, + "lft": 44, + "tree_id": 90, + "bbox_x0": 29.573549, + "bbox_x1": 35.001251, + "bbox_y0": -1.47849, + "bbox_y1": 4.23403 + } + }, + { + "pk": 238, + "model": "base.region", + "fields": { + "rght": 430, + "code": "UKR", + "name": "Ukraine", + "parent": 5, + "level": 2, + "lft": 429, + "tree_id": 90, + "bbox_x0": 22.128811, + "bbox_x1": 40.218079, + "bbox_y0": 44.390411, + "bbox_y1": 52.375359 + } + }, + { + "pk": 239, + "model": "base.region", + "fields": { + "rght": 460, + "code": "ARE", + "name": "United Arab Emirates", + "parent": 15, + "level": 2, + "lft": 459, + "tree_id": 90, + "bbox_x0": 51.497978, + "bbox_x1": 56.38343, + "bbox_y0": 22.644409, + "bbox_y1": 26.28219 + } + }, + { + "pk": 240, + "model": "base.region", + "fields": { + "rght": 432, + "code": "GBR", + "name": "United Kingdom", + "parent": 5, + "level": 2, + "lft": 431, + "tree_id": 90, + "bbox_x0": -13.41393, + "bbox_x1": 1.76896, + "bbox_y0": 49.16209, + "bbox_y1": 60.854691 + } + }, + { + "pk": 241, + "model": "base.region", + "fields": { + "rght": 47, + "code": "TZA", + "name": "United Republic of Tanzania", + "parent": 12, + "level": 3, + "lft": 46, + "tree_id": 90, + "bbox_x0": 29.32716, + "bbox_x1": 40.443218, + "bbox_y0": -11.74569, + "bbox_y1": -0.99073 + } + }, + { + "pk": 242, + "model": "base.region", + "fields": { + "rght": 185, + "code": "VIR", + "name": "United States Virgin Islands", + "parent": 255, + "level": 3, + "lft": 184, + "tree_id": 90, + "bbox_x0": -65.086281, + "bbox_x1": -64.56517, + "bbox_y0": 17.681721, + "bbox_y1": 18.458139 + } + }, + { + "pk": 243, + "model": "base.region", + "fields": { + "rght": 211, + "code": "USA", + "name": "United States of America", + "parent": 2, + "level": 3, + "lft": 210, + "tree_id": 90, + "bbox_x0": -179.150558, + "bbox_x1": -66.940643, + "bbox_y0": 18.91172, + "bbox_y1": 71.441048 + } + }, + { + "pk": 244, + "model": "base.region", + "fields": { + "rght": 239, + "code": "URY", + "name": "Uruguay", + "parent": 4, + "level": 3, + "lft": 238, + "tree_id": 90, + "bbox_x0": -58.442719, + "bbox_x1": -53.073929, + "bbox_y0": -35.047939, + "bbox_y1": -30.08222 + } + }, + { + "pk": 245, + "model": "base.region", + "fields": { + "rght": 259, + "code": "UZB", + "name": "Uzbekistan", + "parent": 8, + "level": 3, + "lft": 258, + "tree_id": 90, + "bbox_x0": 55.996632, + "bbox_x1": 73.132271, + "bbox_y0": 37.18433, + "bbox_y1": 45.60519 + } + }, + { + "pk": 246, + "model": "base.region", + "fields": { + "rght": 512, + "code": "VUT", + "name": "Vanuatu", + "parent": 256, + "level": 2, + "lft": 511, + "tree_id": 90, + "bbox_x0": 166.524994, + "bbox_x1": 170.234802, + "bbox_y0": -20.25045, + "bbox_y1": -13.07345 + } + }, + { + "pk": 247, + "model": "base.region", + "fields": { + "rght": 241, + "code": "VEN", + "name": "Venezuela (Bolivarian Republic of)", + "parent": 4, + "level": 3, + "lft": 240, + "tree_id": 90, + "bbox_x0": -73.374313, + "bbox_x1": -59.803768, + "bbox_y0": 0.74368, + "bbox_y1": 12.2019 + } + }, + { + "pk": 248, + "model": "base.region", + "fields": { + "rght": 315, + "code": "VNM", + "name": "Viet Nam", + "parent": 7, + "level": 3, + "lft": 314, + "tree_id": 90, + "bbox_x0": 102.144592, + "bbox_x1": 116.521233, + "bbox_y0": 7.3116, + "bbox_y1": 23.39274 + } + }, + { + "pk": 249, + "model": "base.region", + "fields": { + "rght": 514, + "code": "WLF", + "name": "Wallis and Futuna Islands", + "parent": 256, + "level": 2, + "lft": 513, + "tree_id": 90, + "bbox_x0": -178.206787, + "bbox_x1": -176.08287, + "bbox_y0": -14.38779, + "bbox_y1": -13.17343 + } + }, + { + "pk": 250, + "model": "base.region", + "fields": { + "rght": 63, + "code": "ESH", + "name": "Western Sahara", + "parent": 11, + "level": 3, + "lft": 62, + "tree_id": 90, + "bbox_x0": -17.10317, + "bbox_x1": -8.66942, + "bbox_y0": 20.774151, + "bbox_y1": 28.219179 + } + }, + { + "pk": 251, + "model": "base.region", + "fields": { + "rght": 462, + "code": "YEM", + "name": "Yemen", + "parent": 15, + "level": 2, + "lft": 461, + "tree_id": 90, + "bbox_x0": 41.809608, + "bbox_x1": 54.535992, + "bbox_y0": 12.10717, + "bbox_y1": 19.00276 + } + }, + { + "pk": 252, + "model": "base.region", + "fields": { + "rght": 79, + "code": "ZMB", + "name": "Zambia", + "parent": 14, + "level": 3, + "lft": 78, + "tree_id": 90, + "bbox_x0": 21.99938, + "bbox_x1": 33.705711, + "bbox_y0": -18.07947, + "bbox_y1": -8.22436 + } + }, + { + "pk": 253, + "model": "base.region", + "fields": { + "rght": 81, + "code": "ZWE", + "name": "Zimbabwe", + "parent": 14, + "level": 3, + "lft": 80, + "tree_id": 90, + "bbox_x0": 25.23702, + "bbox_x1": 33.056301, + "bbox_y0": -22.41773, + "bbox_y1": -15.60883 + } + }, + { + "pk": 254, + "model": "base.region", + "fields": { + "rght": 243, + "code": "AME", + "name": "Americas", + "parent": null, + "level": 1, + "lft": 128, + "tree_id": 90, + "bbox_x0": -84.114449, + "bbox_x1": -84.097572, + "bbox_y0": 9.9313, + "bbox_y1": 9.94792 + } + }, + { + "pk": 255, + "model": "base.region", + "fields": { + "rght": 186, + "code": "CRB", + "name": "Caribbean", + "parent": 254, + "level": 2, + "lft": 129, + "tree_id": 90, + "bbox_x0": -85.260178, + "bbox_x1": -59.286541, + "bbox_y0": 10.18548, + "bbox_y1": 27.454559 + } + }, + { + "pk": 256, + "model": "base.region", + "fields": { + "rght": 515, + "code": "PAC", + "name": "Pacific", + "parent": null, + "level": 1, + "lft": 464, + "tree_id": 90, + "bbox_x0": 112.921112, + "bbox_x1": -108.87291, + "bbox_y0": -54.640301, + "bbox_y1": 20.41712 + } + }, + { + "pk": 257, + "model": "base.region", + "fields": { + "rght": 12, + "code": "CFR", + "name": "Central Africa", + "parent": 10, + "level": 2, + "lft": 3, + "tree_id": 90, + "bbox_x0": -25.35874, + "bbox_x1": 63.525379, + "bbox_y0": -46.900452, + "bbox_y1": 37.56712 + } + }, + { + "pk": 258, + "model": "base.region", + "fields": { + "rght": 276, + "code": "EAS", + "name": "East Asia", + "parent": 6, + "level": 2, + "lft": 261, + "tree_id": 90, + "bbox_x0": 19.6381, + "bbox_x1": 180, + "bbox_y0": -12.56111, + "bbox_y1": 82.50045 + } + }, + { + "pk": 259, + "model": "base.region", + "fields": { + "rght": 59, + "code": "SSD", + "name": "South Sudan", + "parent": 11, + "level": 3, + "lft": 58, + "tree_id": 90, + "bbox_x0": 24.15192, + "bbox_x1": 35.947689, + "bbox_y0": 3.48639, + "bbox_y1": 12.21558 + } + } +] diff --git a/geonode/base/fixtures/test_sld.sld b/geonode/base/fixtures/test_sld.sld index 7d59c34c30a..d3211e6b22d 100644 --- a/geonode/base/fixtures/test_sld.sld +++ b/geonode/base/fixtures/test_sld.sld @@ -1,29 +1,29 @@ - - - - Simple Point - - SLD Cook Book: Simple Point - - - - - - circle - - #FF0000 - - - 6 - - - - - - - + + + + Simple Point + + SLD Cook Book: Simple Point + + + + + + circle + + #FF0000 + + + 6 + + + + + + + diff --git a/geonode/catalogue/metadataxsl/static/metadataxsl/metadata.css b/geonode/catalogue/metadataxsl/static/metadataxsl/metadata.css index 1cce53d0a7c..7701ad3fdd4 100644 --- a/geonode/catalogue/metadataxsl/static/metadataxsl/metadata.css +++ b/geonode/catalogue/metadataxsl/static/metadataxsl/metadata.css @@ -1,185 +1,185 @@ -table a:link { - color: #666; - font-weight: bold; - text-decoration:none; -} -table a:visited { - color: #999999; - font-weight:bold; - text-decoration:none; -} -table a:active, -table a:hover { - color: #bd5a35; - text-decoration:underline; -} -table { - font-family:Arial, sans-serif; - color:#666; - font-size:12px; - text-shadow: 1px 1px 0px #fff; - background:#eaebec; - margin:10px; - border:#ccc 1px solid; - width:98%; - -moz-border-radius:3px; - -webkit-border-radius:3px; - border-radius:3px; - -moz-box-shadow: 0 1px 2px #d1d1d1; - -webkit-box-shadow: 0 1px 2px #d1d1d1; - box-shadow: 0 1px 2px #d1d1d1; -} -table th { - padding:10px 10px 10px 10px; - border-top:1px solid #fafafa; - border-bottom:1px solid #e0e0e0; - background: #ededed; - background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#ebebeb)); - background: -moz-linear-gradient(top, #ededed, #ebebeb); -} -table th:first-child { - text-align: left; - padding-left:10px; -} -table tr:first-child th:first-child { - -moz-border-radius-topleft:3px; - -webkit-border-top-left-radius:3px; - border-top-left-radius:3px; -} -table tr:first-child th:last-child { - -moz-border-radius-topright:3px; - -webkit-border-top-right-radius:3px; - border-top-right-radius:3px; -} -table tr { - padding-left:10px; -} -table td:first-child { - text-align: left; - padding-left:10px; - border-left: 0; -} -table td { - padding:10px; - border-top: 1px solid #ffffff; - border-bottom:1px solid #e0e0e0; - border-left: 1px solid #e0e0e0; - - background: #fafafa; - background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa)); - background: -moz-linear-gradient(top, #fbfbfb, #fafafa); -} -table tr.even td { - background: #f6f6f6; - background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6f6)); - background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6); -} -table tr:last-child td { - border-bottom:0; -} -table tr:last-child td:first-child { - -moz-border-radius-bottomleft:3px; - -webkit-border-bottom-left-radius:3px; - border-bottom-left-radius:3px; -} -table tr:last-child td:last-child { - -moz-border-radius-bottomright:3px; - -webkit-border-bottom-right-radius:3px; - border-bottom-right-radius:3px; -} -table td img { - vertical-align: middle; - margin-right:10px; -} - -// General styles -body { - padding: 0 2em; - font-family: Arial, sans-serif; - color: #0B85C3; - background : #f2f2f2; -} - -h1, h2, h3 { - font-family: Arial, sans-serif; - font-weight: bold; - color: #0B85C3; - span {color: #167F92;}; -} - -p, table { - font-family: Arial, sans-serif; - font-weight: normal; - font-size:95%; - span {color: #167F92;} -} - -p { - margin:0; padding:0; - text-align:justify; -} - -.header { - background: #efefef; -} - -.title { - color: #0B85C3; - font-weight: bold; -} - -.nowrap { - white-space: nowrap; -} - -.logos { - width:99%; - display:float; - vertical-align:bottom; - clear:both; -} - -.fleft { - float:left; - padding:5px; -} - -.fright { - float:right; - margin:15px 10px; -} - -.pad { - padding-left:25px; -} - - -.fixedcol { - width:300px; -} - -.geonodelogo { - background-color: #1177A3; -} - -@media print { - body { - font-size:90%; - } - .fleft { - width: 30% !important; - height: 30% !important; - margin:0px; - } - .fright { - width: 10% !important; - height: 10% !important; - margin:0px; - } - .pad { - padding-left:20px; - } - .fixedcol { - width:100px; - } -} +table a:link { + color: #666; + font-weight: bold; + text-decoration:none; +} +table a:visited { + color: #999999; + font-weight:bold; + text-decoration:none; +} +table a:active, +table a:hover { + color: #bd5a35; + text-decoration:underline; +} +table { + font-family:Arial, sans-serif; + color:#666; + font-size:12px; + text-shadow: 1px 1px 0px #fff; + background:#eaebec; + margin:10px; + border:#ccc 1px solid; + width:98%; + -moz-border-radius:3px; + -webkit-border-radius:3px; + border-radius:3px; + -moz-box-shadow: 0 1px 2px #d1d1d1; + -webkit-box-shadow: 0 1px 2px #d1d1d1; + box-shadow: 0 1px 2px #d1d1d1; +} +table th { + padding:10px 10px 10px 10px; + border-top:1px solid #fafafa; + border-bottom:1px solid #e0e0e0; + background: #ededed; + background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#ebebeb)); + background: -moz-linear-gradient(top, #ededed, #ebebeb); +} +table th:first-child { + text-align: left; + padding-left:10px; +} +table tr:first-child th:first-child { + -moz-border-radius-topleft:3px; + -webkit-border-top-left-radius:3px; + border-top-left-radius:3px; +} +table tr:first-child th:last-child { + -moz-border-radius-topright:3px; + -webkit-border-top-right-radius:3px; + border-top-right-radius:3px; +} +table tr { + padding-left:10px; +} +table td:first-child { + text-align: left; + padding-left:10px; + border-left: 0; +} +table td { + padding:10px; + border-top: 1px solid #ffffff; + border-bottom:1px solid #e0e0e0; + border-left: 1px solid #e0e0e0; + + background: #fafafa; + background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa)); + background: -moz-linear-gradient(top, #fbfbfb, #fafafa); +} +table tr.even td { + background: #f6f6f6; + background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6f6)); + background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6); +} +table tr:last-child td { + border-bottom:0; +} +table tr:last-child td:first-child { + -moz-border-radius-bottomleft:3px; + -webkit-border-bottom-left-radius:3px; + border-bottom-left-radius:3px; +} +table tr:last-child td:last-child { + -moz-border-radius-bottomright:3px; + -webkit-border-bottom-right-radius:3px; + border-bottom-right-radius:3px; +} +table td img { + vertical-align: middle; + margin-right:10px; +} + +// General styles +body { + padding: 0 2em; + font-family: Arial, sans-serif; + color: #0B85C3; + background : #f2f2f2; +} + +h1, h2, h3 { + font-family: Arial, sans-serif; + font-weight: bold; + color: #0B85C3; + span {color: #167F92;}; +} + +p, table { + font-family: Arial, sans-serif; + font-weight: normal; + font-size:95%; + span {color: #167F92;} +} + +p { + margin:0; padding:0; + text-align:justify; +} + +.header { + background: #efefef; +} + +.title { + color: #0B85C3; + font-weight: bold; +} + +.nowrap { + white-space: nowrap; +} + +.logos { + width:99%; + display:float; + vertical-align:bottom; + clear:both; +} + +.fleft { + float:left; + padding:5px; +} + +.fright { + float:right; + margin:15px 10px; +} + +.pad { + padding-left:25px; +} + + +.fixedcol { + width:300px; +} + +.geonodelogo { + background-color: #1177A3; +} + +@media print { + body { + font-size:90%; + } + .fleft { + width: 30% !important; + height: 30% !important; + margin:0px; + } + .fright { + width: 10% !important; + height: 10% !important; + margin:0px; + } + .pad { + padding-left:20px; + } + .fixedcol { + width:100px; + } +} diff --git a/geonode/catalogue/templates/geonode_metadata_full.html b/geonode/catalogue/templates/geonode_metadata_full.html index 6e1a679b179..e08c7cccb64 100644 --- a/geonode/catalogue/templates/geonode_metadata_full.html +++ b/geonode/catalogue/templates/geonode_metadata_full.html @@ -1,171 +1,171 @@ -{% load i18n %} -{% load static %} - - - - - - - {{ resource.title }} - {% block head %} - - - - - {% endblock %} - - - {% block body_outer %} - {% block body %}{% endblock body %} - {% block sidebar %}{% endblock sidebar %} - {% endblock body_outer %} -
-
- - -
-
-
-
{% trans "Thumbnail" %}
-
{{ resource.title }}
- -
{% trans "Resource ID" %}
-
{{resource.uuid}}
- -
{% trans "Title" %}
-
{{resource.title}}
- -
{% trans "Date" %}
-
{{resource.date}}, {% trans resource.date_type|title %}
- -
{% trans "Abstract" %}
-
{{resource.raw_abstract}}
- -
{% trans "Edition" %}
- {% if resource.edition %} -
{{resource.edition}}
- {% else %} -
--
- {% endif %} - - -
{% trans "Responsible" %}
-
{{resource.owner}}
- - {% for role in extra_res_md.roles %} -
{% trans role.label %}
- - {% for user in role.users %} -
{{user.last_name}}
-
{{ user.email}}
- {% endfor %} - {% endfor %} - -
{% trans "Purpose" %}
- {% if resource.purpose %} -
{{resource.raw_purpose}}
- {% else %} -
--
- {% endif %} - - -
{% trans "Maintenance Frequency" %}
-
{{resource.maintenance_frequency}}
- -
{% trans "Type" %}
-
{{extra_res_md.sprt_identifier}}
- -
{% trans "Restrictions" %}
-
{{resource.restriction_code_type}}
-
{{resource.raw_constraints_other}}
- -
{% trans "License" %}
-
{{resource.license}}
- -
{% trans "Language" %}
-
{{resource.language}}
- -
{% trans "Temporal Extent" %}
-
{% trans "Start" %}
- {% if resource.temporal_extent_start %} -
{{resource.temporal_extent_start}}
- {% else %} -
--
- {% endif %} -
{% trans "End" %}
- {% if resource.temporal_extent_end %} -
{{resource.temporal_extent_end}}
- {% else %} -
--
- {% endif %} - - -
{% trans "Supplemental Information" %}
-
{{resource.raw_supplemental_information}}
- -
{% trans "Data Quality" %}
- {% if resource.data_quality_statement %} -
{{resource.raw_data_quality_statement}}
- {% else %} -
--
- {% endif %} - -
{% trans "Extent" %}
-
-
    -
  • x0: {{resource.bbox_helper.xmin}}
  • -
  • x1: {{resource.bbox_helper.xmax}}
  • -
  • y0: {{resource.bbox_helper.ymin}}
  • -
  • y1: {{resource.bbox_helper.ymax}}
  • -
-
- -
{% trans "Spatial Reference System Identifier" %}
-
{{resource.srid}}
- -
{% trans "Keywords" %}
-
{{extra_res_md.keywords}}
- -
{% trans "Category" %}
-
{{resource.category}}
- - {% if resource.regions.all %} -
{% trans "Regions" %}
-
- {% for region in resource.regions.all %} - {{ region.name }} - {% if not forloop.last %},{% endif %} - {% endfor %} -
- {% endif %} - - {% if "dataset" in request.META.HTTP_REFERER|stringformat:"s" %} -
{% trans "Attributes" %}
-
- -
-
- - {% endif %} -
-
-
-
- - +{% load i18n %} +{% load static %} + + + + + + + {{ resource.title }} + {% block head %} + + + + + {% endblock %} + + + {% block body_outer %} + {% block body %}{% endblock body %} + {% block sidebar %}{% endblock sidebar %} + {% endblock body_outer %} +
+
+ + +
+
+
+
{% trans "Thumbnail" %}
+
{{ resource.title }}
+ +
{% trans "Resource ID" %}
+
{{resource.uuid}}
+ +
{% trans "Title" %}
+
{{resource.title}}
+ +
{% trans "Date" %}
+
{{resource.date}}, {% trans resource.date_type|title %}
+ +
{% trans "Abstract" %}
+
{{resource.raw_abstract}}
+ +
{% trans "Edition" %}
+ {% if resource.edition %} +
{{resource.edition}}
+ {% else %} +
--
+ {% endif %} + + +
{% trans "Responsible" %}
+
{{resource.owner}}
+ + {% for role in extra_res_md.roles %} +
{% trans role.label %}
+ + {% for user in role.users %} +
{{user.last_name}}
+
{{ user.email}}
+ {% endfor %} + {% endfor %} + +
{% trans "Purpose" %}
+ {% if resource.purpose %} +
{{resource.raw_purpose}}
+ {% else %} +
--
+ {% endif %} + + +
{% trans "Maintenance Frequency" %}
+
{{resource.maintenance_frequency}}
+ +
{% trans "Type" %}
+
{{extra_res_md.sprt_identifier}}
+ +
{% trans "Restrictions" %}
+
{{resource.restriction_code_type}}
+
{{resource.raw_constraints_other}}
+ +
{% trans "License" %}
+
{{resource.license}}
+ +
{% trans "Language" %}
+
{{resource.language}}
+ +
{% trans "Temporal Extent" %}
+
{% trans "Start" %}
+ {% if resource.temporal_extent_start %} +
{{resource.temporal_extent_start}}
+ {% else %} +
--
+ {% endif %} +
{% trans "End" %}
+ {% if resource.temporal_extent_end %} +
{{resource.temporal_extent_end}}
+ {% else %} +
--
+ {% endif %} + + +
{% trans "Supplemental Information" %}
+
{{resource.raw_supplemental_information}}
+ +
{% trans "Data Quality" %}
+ {% if resource.data_quality_statement %} +
{{resource.raw_data_quality_statement}}
+ {% else %} +
--
+ {% endif %} + +
{% trans "Extent" %}
+
+
    +
  • x0: {{resource.bbox_helper.xmin}}
  • +
  • x1: {{resource.bbox_helper.xmax}}
  • +
  • y0: {{resource.bbox_helper.ymin}}
  • +
  • y1: {{resource.bbox_helper.ymax}}
  • +
+
+ +
{% trans "Spatial Reference System Identifier" %}
+
{{resource.srid}}
+ +
{% trans "Keywords" %}
+
{{extra_res_md.keywords}}
+ +
{% trans "Category" %}
+
{{resource.category}}
+ + {% if resource.regions.all %} +
{% trans "Regions" %}
+
+ {% for region in resource.regions.all %} + {{ region.name }} + {% if not forloop.last %},{% endif %} + {% endfor %} +
+ {% endif %} + + {% if "dataset" in request.META.HTTP_REFERER|stringformat:"s" %} +
{% trans "Attributes" %}
+
+ +
+
+ + {% endif %} +
+
+
+
+ + diff --git a/geonode/client/apps.py b/geonode/client/apps.py index 55202b4f72f..f24a330758b 100644 --- a/geonode/client/apps.py +++ b/geonode/client/apps.py @@ -1,26 +1,26 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from django.apps import AppConfig as BaseAppConfig -from django.utils.translation import gettext_lazy as _ - - -class AppConfig(BaseAppConfig): - name = "geonode.client" - label = "geonode_client" - verbose_name = _("GeoNode Client Library") +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from django.apps import AppConfig as BaseAppConfig +from django.utils.translation import gettext_lazy as _ + + +class AppConfig(BaseAppConfig): + name = "geonode.client" + label = "geonode_client" + verbose_name = _("GeoNode Client Library") diff --git a/geonode/client/conf.py b/geonode/client/conf.py index 3d9982890db..8d997cc0dc7 100644 --- a/geonode/client/conf.py +++ b/geonode/client/conf.py @@ -1,49 +1,49 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -import importlib - -from django.conf import settings # noqa -from django.core.exceptions import ImproperlyConfigured - -from appconf import AppConf - - -def load_path_attr(path): - i = path.rfind(".") - module, attr = path[:i], path[i + 1 :] - try: - mod = importlib.import_module(module) - except ImportError as e: - raise ImproperlyConfigured(f"Error importing {module}: '{e}'") - try: - attr = getattr(mod, attr) - except AttributeError: - raise ImproperlyConfigured(f"Module '{module}' does not define a '{attr}'") - return attr - - -class GeoNodeClientAppConf(AppConf): - LAYER_PREVIEW_LIBRARY = "geonode" - HOOKSET = "geonode.client.hooksets.BaseHookSet" - - def configure_hookset(self, value): - return load_path_attr(value)() - - class Meta: - prefix = "geonode_client" +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +import importlib + +from django.conf import settings # noqa +from django.core.exceptions import ImproperlyConfigured + +from appconf import AppConf + + +def load_path_attr(path): + i = path.rfind(".") + module, attr = path[:i], path[i + 1 :] + try: + mod = importlib.import_module(module) + except ImportError as e: + raise ImproperlyConfigured(f"Error importing {module}: '{e}'") + try: + attr = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured(f"Module '{module}' does not define a '{attr}'") + return attr + + +class GeoNodeClientAppConf(AppConf): + LAYER_PREVIEW_LIBRARY = "geonode" + HOOKSET = "geonode.client.hooksets.BaseHookSet" + + def configure_hookset(self, value): + return load_path_attr(value)() + + class Meta: + prefix = "geonode_client" diff --git a/geonode/client/hooks.py b/geonode/client/hooks.py index f595a1ffc9c..686bc142436 100644 --- a/geonode/client/hooks.py +++ b/geonode/client/hooks.py @@ -1,36 +1,36 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from .conf import settings - - -class HookProxy: - def __getattr__(self, attr): - if not isinstance(settings.GEONODE_CLIENT_HOOKSET, str): - return getattr(settings.GEONODE_CLIENT_HOOKSET, attr) - else: - import importlib - - cls = settings.GEONODE_CLIENT_HOOKSET.split(".") - module_name, class_name = (".".join(cls[:-1]), cls[-1]) - i = importlib.import_module(module_name) - hook = getattr(i, class_name)() - return getattr(hook, attr) - - -hookset = HookProxy() +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from .conf import settings + + +class HookProxy: + def __getattr__(self, attr): + if not isinstance(settings.GEONODE_CLIENT_HOOKSET, str): + return getattr(settings.GEONODE_CLIENT_HOOKSET, attr) + else: + import importlib + + cls = settings.GEONODE_CLIENT_HOOKSET.split(".") + module_name, class_name = (".".join(cls[:-1]), cls[-1]) + i = importlib.import_module(module_name) + hook = getattr(i, class_name)() + return getattr(hook, attr) + + +hookset = HookProxy() diff --git a/geonode/client/models.py b/geonode/client/models.py index 5c3ac917f78..68c7b7d1937 100644 --- a/geonode/client/models.py +++ b/geonode/client/models.py @@ -1,18 +1,18 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### diff --git a/geonode/client/static/crossdomain.xml b/geonode/client/static/crossdomain.xml index 71449d9f34b..981d5f63726 100644 --- a/geonode/client/static/crossdomain.xml +++ b/geonode/client/static/crossdomain.xml @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/geonode/documents/manager.py b/geonode/documents/manager.py index 4d97877bbd9..763e0855d02 100644 --- a/geonode/documents/manager.py +++ b/geonode/documents/manager.py @@ -1,68 +1,68 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### - -import copy -import typing -import logging - -from geonode.base.models import ResourceBase -from geonode.resource.manager import BaseResourceManager -from geonode.documents.models import Document - - -logger = logging.getLogger(__name__) - - -class DocumentResourceManager(BaseResourceManager): - handled_model = Document - - def create( - self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs - ) -> ResourceBase: - from geonode.storage.manager import StorageManager - - file = kwargs.pop("file", None) - request_user = kwargs.get("user") - storage = None - resource_type = resource_type or Document - defaults = copy.deepcopy(defaults or {}) - extent = defaults.pop("extent", None) - try: - if file: - if isinstance(file, str): - defaults["files"] = [file] - else: - storage = StorageManager(remote_files={"base_file": file}) - storage.clone_remote_files() - defaults["files"] = [storage.get_retrieved_paths().get("base_file")] - resource = super().create(uuid, resource_type=resource_type, defaults=defaults) - if extent or request_user: - # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, - # but it’s kept here to centralize manager behavior. - self._apply_extent_and_role_defaults(resource, extent=extent, user=request_user) - resource.handle_moderated_uploads() - # Only trigger thumbnailing for local documents, not for remote URLs - if resource.is_local: - self.set_thumbnail(resource.uuid, instance=resource, overwrite=False) - else: - logger.info(f"Skipping thumbnail generation for remote document: {resource.doc_url}") - return resource - finally: - if storage: - storage.delete_retrieved_paths(force=True) +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### + +import copy +import typing +import logging + +from geonode.base.models import ResourceBase +from geonode.resource.manager import BaseResourceManager +from geonode.documents.models import Document + + +logger = logging.getLogger(__name__) + + +class DocumentResourceManager(BaseResourceManager): + handled_model = Document + + def create( + self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs + ) -> ResourceBase: + from geonode.storage.manager import StorageManager + + file = kwargs.pop("file", None) + request_user = kwargs.get("user") + storage = None + resource_type = resource_type or Document + defaults = copy.deepcopy(defaults or {}) + extent = defaults.pop("extent", None) + try: + if file: + if isinstance(file, str): + defaults["files"] = [file] + else: + storage = StorageManager(remote_files={"base_file": file}) + storage.clone_remote_files() + defaults["files"] = [storage.get_retrieved_paths().get("base_file")] + resource = super().create(uuid, resource_type=resource_type, defaults=defaults) + if extent or request_user: + # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, + # but it’s kept here to centralize manager behavior. + self._apply_extent_and_role_defaults(resource, extent=extent, user=request_user) + resource.handle_moderated_uploads() + # Only trigger thumbnailing for local documents, not for remote URLs + if resource.is_local: + self.set_thumbnail(resource.uuid, instance=resource, overwrite=False) + else: + logger.info(f"Skipping thumbnail generation for remote document: {resource.doc_url}") + return resource + finally: + if storage: + storage.delete_retrieved_paths(force=True) diff --git a/geonode/documents/tests/data/test.CSV b/geonode/documents/tests/data/test.CSV index c3053f40546..8c039d7e48a 100755 --- a/geonode/documents/tests/data/test.CSV +++ b/geonode/documents/tests/data/test.CSV @@ -1,6 +1,6 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins +Username; Identifier;First name;Last name +booker12;9012;Rachel;Booker +grey07;2070;Laura;Grey +johnson81;4081;Craig;Johnson +jenkins46;9346;Mary;Jenkins smith79;5079;Jamie;Smith \ No newline at end of file diff --git a/geonode/geoapps/manager.py b/geonode/geoapps/manager.py index a6186c61177..85bb4bcd7a3 100644 --- a/geonode/geoapps/manager.py +++ b/geonode/geoapps/manager.py @@ -1,78 +1,78 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### - -import copy -import typing -import logging - -from geonode.base.models import ResourceBase -from geonode.resource.manager import BaseResourceManager -from geonode.geoapps.models import GeoApp - -logger = logging.getLogger(__name__) - - -class GeoAppResourceManager(BaseResourceManager): - handled_model = GeoApp - - def _create_and_update(self, payload, instance=None, notify: bool = True, request_user=None): - from geonode.geoapps.api.exceptions import GeneralGeoAppException - - payload = copy.deepcopy(payload) - extent = payload.pop("extent", None) - blob = payload.pop("blob", {}) - - created = False - if not instance: - instance = super().create(None, resource_type=GeoApp, defaults=payload) - created = True - - if created and "owner" in payload: - payload["owner"] = instance.owner - - try: - GeoApp.objects.filter(pk=instance.id).update(**payload) - instance.refresh_from_db() - except Exception as e: - logger.exception(f"Error while creating or updating GeoApp instance with exception {e}") - raise GeneralGeoAppException("An error occurred while saving the GeoApp.") - - payload["blob"] = blob - instance = super().update(instance.uuid, instance=instance, vals=payload, notify=notify) - if extent or request_user: - # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, - # but it’s kept here to centralize manager behavior. - self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) - return instance - - def create( - self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs - ) -> ResourceBase: - notify = kwargs.pop("notify", True) - request_user = kwargs.get("user") - payload = copy.deepcopy(defaults or {}) - return self._create_and_update(payload, notify=notify, request_user=request_user) - - def update(self, uuid: str, /, instance: ResourceBase = None, vals: dict = {}, **kwargs) -> ResourceBase: - notify = kwargs.pop("notify", True) - request_user = kwargs.get("user") - payload = vals or {} - if payload: - return self._create_and_update(payload, instance=instance, notify=notify, request_user=request_user) - return super().update(uuid, instance=instance, vals=vals, notify=notify, **kwargs) +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### + +import copy +import typing +import logging + +from geonode.base.models import ResourceBase +from geonode.resource.manager import BaseResourceManager +from geonode.geoapps.models import GeoApp + +logger = logging.getLogger(__name__) + + +class GeoAppResourceManager(BaseResourceManager): + handled_model = GeoApp + + def _create_and_update(self, payload, instance=None, notify: bool = True, request_user=None): + from geonode.geoapps.api.exceptions import GeneralGeoAppException + + payload = copy.deepcopy(payload) + extent = payload.pop("extent", None) + blob = payload.pop("blob", {}) + + created = False + if not instance: + instance = super().create(None, resource_type=GeoApp, defaults=payload) + created = True + + if created and "owner" in payload: + payload["owner"] = instance.owner + + try: + GeoApp.objects.filter(pk=instance.id).update(**payload) + instance.refresh_from_db() + except Exception as e: + logger.exception(f"Error while creating or updating GeoApp instance with exception {e}") + raise GeneralGeoAppException("An error occurred while saving the GeoApp.") + + payload["blob"] = blob + instance = super().update(instance.uuid, instance=instance, vals=payload, notify=notify) + if extent or request_user: + # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, + # but it’s kept here to centralize manager behavior. + self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) + return instance + + def create( + self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs + ) -> ResourceBase: + notify = kwargs.pop("notify", True) + request_user = kwargs.get("user") + payload = copy.deepcopy(defaults or {}) + return self._create_and_update(payload, notify=notify, request_user=request_user) + + def update(self, uuid: str, /, instance: ResourceBase = None, vals: dict = {}, **kwargs) -> ResourceBase: + notify = kwargs.pop("notify", True) + request_user = kwargs.get("user") + payload = vals or {} + if payload: + return self._create_and_update(payload, instance=instance, notify=notify, request_user=request_user) + return super().update(uuid, instance=instance, vals=vals, notify=notify, **kwargs) diff --git a/geonode/geoserver/createlayer/__init__.py b/geonode/geoserver/createlayer/__init__.py index 3d54b02dfef..f3b257d5e12 100644 --- a/geonode/geoserver/createlayer/__init__.py +++ b/geonode/geoserver/createlayer/__init__.py @@ -1,18 +1,18 @@ -######################################################################### -# -# Copyright (C) 2017 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 . -# -######################################################################### +######################################################################### +# +# Copyright (C) 2017 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 . +# +######################################################################### diff --git a/geonode/geoserver/migrations/__init__.py b/geonode/geoserver/migrations/__init__.py index 5c3ac917f78..68c7b7d1937 100644 --- a/geonode/geoserver/migrations/__init__.py +++ b/geonode/geoserver/migrations/__init__.py @@ -1,18 +1,18 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### diff --git a/geonode/invitations/forms.py b/geonode/invitations/forms.py index 16f748c894f..2bdda2a2352 100644 --- a/geonode/invitations/forms.py +++ b/geonode/invitations/forms.py @@ -1,74 +1,74 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### - -from django import forms -from django.utils.translation import gettext_lazy as _ -from django.contrib.auth import get_user_model - -from invitations.adapters import get_invitations_adapter -from invitations.exceptions import AlreadyInvited, AlreadyAccepted, UserRegisteredEmail -from invitations.utils import get_invitation_model - -Invitation = get_invitation_model() - - -class CleanEmailMixin: - def validate_invitation(self, email): - if Invitation.objects.all_valid().filter(email__iexact=email, accepted=False): - raise AlreadyInvited - elif Invitation.objects.filter(email__iexact=email, accepted=True): - raise AlreadyAccepted - elif get_user_model().objects.filter(email__iexact=email): - raise UserRegisteredEmail - else: - return True - - def clean_email(self): - emails = self.cleaned_data["email"] - emails = emails.replace(";", ",").split(",") - for em in emails: - email = get_invitations_adapter().clean_email(em.strip()) - - errors = { - "already_invited": _(f"The e-mail address '{email}' has already been invited."), - "already_accepted": _(f"The e-mail address '{email}' has already accepted an invite."), - "email_in_use": _(f"An active user is already using the e-mail address '{email}'"), - } - try: - self.validate_invitation(email) - except AlreadyInvited: - raise forms.ValidationError(errors["already_invited"]) - except AlreadyAccepted: - raise forms.ValidationError(errors["already_accepted"]) - except UserRegisteredEmail: - raise forms.ValidationError(errors["email_in_use"]) - - return emails - - -class GeoNodeInviteForm(forms.Form, CleanEmailMixin): - email = forms.CharField( - label=_("E-mail"), required=True, widget=forms.TextInput(attrs={"type": "text", "size": "1200"}), initial="" - ) - - def save(self, emails): - invitations = [] - for em in emails: - invitations.append(Invitation.create(email=em.strip())) - return invitations +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### + +from django import forms +from django.utils.translation import gettext_lazy as _ +from django.contrib.auth import get_user_model + +from invitations.adapters import get_invitations_adapter +from invitations.exceptions import AlreadyInvited, AlreadyAccepted, UserRegisteredEmail +from invitations.utils import get_invitation_model + +Invitation = get_invitation_model() + + +class CleanEmailMixin: + def validate_invitation(self, email): + if Invitation.objects.all_valid().filter(email__iexact=email, accepted=False): + raise AlreadyInvited + elif Invitation.objects.filter(email__iexact=email, accepted=True): + raise AlreadyAccepted + elif get_user_model().objects.filter(email__iexact=email): + raise UserRegisteredEmail + else: + return True + + def clean_email(self): + emails = self.cleaned_data["email"] + emails = emails.replace(";", ",").split(",") + for em in emails: + email = get_invitations_adapter().clean_email(em.strip()) + + errors = { + "already_invited": _(f"The e-mail address '{email}' has already been invited."), + "already_accepted": _(f"The e-mail address '{email}' has already accepted an invite."), + "email_in_use": _(f"An active user is already using the e-mail address '{email}'"), + } + try: + self.validate_invitation(email) + except AlreadyInvited: + raise forms.ValidationError(errors["already_invited"]) + except AlreadyAccepted: + raise forms.ValidationError(errors["already_accepted"]) + except UserRegisteredEmail: + raise forms.ValidationError(errors["email_in_use"]) + + return emails + + +class GeoNodeInviteForm(forms.Form, CleanEmailMixin): + email = forms.CharField( + label=_("E-mail"), required=True, widget=forms.TextInput(attrs={"type": "text", "size": "1200"}), initial="" + ) + + def save(self, emails): + invitations = [] + for em in emails: + invitations.append(Invitation.create(email=em.strip())) + return invitations diff --git a/geonode/invitations/urls.py b/geonode/invitations/urls.py index 91c4bdd0551..5995eeeb2e0 100644 --- a/geonode/invitations/urls.py +++ b/geonode/invitations/urls.py @@ -1,30 +1,30 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### - -from django.urls import re_path - -import invitations -from . import views - -app_name = "geonode.invitations" -urlpatterns = [ - re_path(r"^geonode-send-invite/$", views.GeoNodeSendInvite.as_view(), name="geonode-send-invite"), - re_path(r"^send-json-invite/$", invitations.views.SendJSONInvite.as_view(), name="send-json-invite"), - re_path(r"^accept-invite/(?P\w+)/?$", invitations.views.AcceptInvite.as_view(), name="accept-invite"), -] +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### + +from django.urls import re_path + +import invitations +from . import views + +app_name = "geonode.invitations" +urlpatterns = [ + re_path(r"^geonode-send-invite/$", views.GeoNodeSendInvite.as_view(), name="geonode-send-invite"), + re_path(r"^send-json-invite/$", invitations.views.SendJSONInvite.as_view(), name="send-json-invite"), + re_path(r"^accept-invite/(?P\w+)/?$", invitations.views.AcceptInvite.as_view(), name="accept-invite"), +] diff --git a/geonode/layers/manager.py b/geonode/layers/manager.py index 63557dd96c5..a32d9587ff5 100644 --- a/geonode/layers/manager.py +++ b/geonode/layers/manager.py @@ -1,30 +1,30 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### - -from geonode.resource.manager import BaseResourceManager -from geonode.layers.models import Dataset - - -class DatasetResourceManager(BaseResourceManager): - """Dataset manager. - Inherits BaseResourceManager behavior. - Override dataset-specific hooks from BaseResourceManager here if custom needs to be done. - """ - - handled_model = Dataset +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### + +from geonode.resource.manager import BaseResourceManager +from geonode.layers.models import Dataset + + +class DatasetResourceManager(BaseResourceManager): + """Dataset manager. + Inherits BaseResourceManager behavior. + Override dataset-specific hooks from BaseResourceManager here if custom needs to be done. + """ + + handled_model = Dataset diff --git a/geonode/maps/manager.py b/geonode/maps/manager.py index df2d4073162..1b614a861ff 100644 --- a/geonode/maps/manager.py +++ b/geonode/maps/manager.py @@ -1,103 +1,103 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### - -import copy -import typing - -from geonode.base.models import ResourceBase -from geonode.resource.manager import BaseResourceManager -from geonode.maps.models import Map - - -class MapResourceManager(BaseResourceManager): - handled_model = Map - - def _post_change_routines( - self, instance: Map, create_action_perfomed: bool, additional_data: dict = None, notify: bool = True - ): - additional_data = additional_data or {} - - if not create_action_perfomed: - from geonode.maps.signals import map_changed_signal - - dataset_names_before_changes = additional_data.pop("dataset_names_before_changes", []) - dataset_names_after_changes = [lyr.alternate for lyr in instance.datasets] - if dataset_names_before_changes != dataset_names_after_changes: - map_changed_signal.send_robust(sender=instance, what_changed="datasets") - - return super().update(instance.uuid, instance=instance, notify=notify) - - def create( - self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs - ) -> ResourceBase: - notify = kwargs.pop("notify", True) - request_user = kwargs.get("user") - payload = copy.deepcopy(defaults or {}) - extent = payload.pop("extent", None) - post_creation_data = {"thumbnail": payload.pop("thumbnail_url", "")} - maplayers = payload.pop("maplayers", None) - instance = super().create(uuid, resource_type=resource_type or Map, defaults=payload) - - if maplayers is not None: - instance.maplayers.set(maplayers) - instance.refresh_from_db() - - if extent is not None or request_user: - self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) - - instance = self._post_change_routines( - instance=instance, - create_action_perfomed=True, - additional_data=post_creation_data, - notify=notify, - ) - self.set_thumbnail(instance.uuid, instance=instance, overwrite=False) - return instance - - def update(self, uuid: str, /, instance: ResourceBase = None, vals: dict = {}, **kwargs) -> ResourceBase: - dataset_names_before_changes = kwargs.pop("dataset_names_before_changes", None) - notify = kwargs.pop("notify", True) - - payload = copy.deepcopy(vals or {}) - extent = payload.pop("extent", None) - request_user = kwargs.get("user") - post_change_data = { - "thumbnail": payload.pop("thumbnail_url", ""), - "dataset_names_before_changes": dataset_names_before_changes or [], - } - maplayers = payload.pop("maplayers", None) - - instance = super().update(uuid, instance=instance, vals=payload, notify=False, **kwargs) - - if maplayers is not None: - instance.maplayers.set(maplayers) - instance.refresh_from_db() - - if extent or request_user: - # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, - # but it’s kept here to centralize manager behavior. - self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) - - instance = self._post_change_routines( - instance=instance, - create_action_perfomed=False, - additional_data=post_change_data, - notify=notify, - ) - return instance +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### + +import copy +import typing + +from geonode.base.models import ResourceBase +from geonode.resource.manager import BaseResourceManager +from geonode.maps.models import Map + + +class MapResourceManager(BaseResourceManager): + handled_model = Map + + def _post_change_routines( + self, instance: Map, create_action_perfomed: bool, additional_data: dict = None, notify: bool = True + ): + additional_data = additional_data or {} + + if not create_action_perfomed: + from geonode.maps.signals import map_changed_signal + + dataset_names_before_changes = additional_data.pop("dataset_names_before_changes", []) + dataset_names_after_changes = [lyr.alternate for lyr in instance.datasets] + if dataset_names_before_changes != dataset_names_after_changes: + map_changed_signal.send_robust(sender=instance, what_changed="datasets") + + return super().update(instance.uuid, instance=instance, notify=notify) + + def create( + self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, **kwargs + ) -> ResourceBase: + notify = kwargs.pop("notify", True) + request_user = kwargs.get("user") + payload = copy.deepcopy(defaults or {}) + extent = payload.pop("extent", None) + post_creation_data = {"thumbnail": payload.pop("thumbnail_url", "")} + maplayers = payload.pop("maplayers", None) + instance = super().create(uuid, resource_type=resource_type or Map, defaults=payload) + + if maplayers is not None: + instance.maplayers.set(maplayers) + instance.refresh_from_db() + + if extent is not None or request_user: + self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) + + instance = self._post_change_routines( + instance=instance, + create_action_perfomed=True, + additional_data=post_creation_data, + notify=notify, + ) + self.set_thumbnail(instance.uuid, instance=instance, overwrite=False) + return instance + + def update(self, uuid: str, /, instance: ResourceBase = None, vals: dict = {}, **kwargs) -> ResourceBase: + dataset_names_before_changes = kwargs.pop("dataset_names_before_changes", None) + notify = kwargs.pop("notify", True) + + payload = copy.deepcopy(vals or {}) + extent = payload.pop("extent", None) + request_user = kwargs.get("user") + post_change_data = { + "thumbnail": payload.pop("thumbnail_url", ""), + "dataset_names_before_changes": dataset_names_before_changes or [], + } + maplayers = payload.pop("maplayers", None) + + instance = super().update(uuid, instance=instance, vals=payload, notify=False, **kwargs) + + if maplayers is not None: + instance.maplayers.set(maplayers) + instance.refresh_from_db() + + if extent or request_user: + # Mirrors ResourceBaseSerializer.save() (extent + role defaults); could be moved to the API, + # but it’s kept here to centralize manager behavior. + self._apply_extent_and_role_defaults(instance, extent=extent, user=request_user) + + instance = self._post_change_routines( + instance=instance, + create_action_perfomed=False, + additional_data=post_change_data, + notify=notify, + ) + return instance diff --git a/geonode/resource/apps.py b/geonode/resource/apps.py index 026ebcd838d..189fb0a6811 100644 --- a/geonode/resource/apps.py +++ b/geonode/resource/apps.py @@ -34,4 +34,4 @@ def ready(self): def run_setup_hooks(*args, **kwargs): from geonode.resource.registry import resource_manager_registry - resource_manager_registry.init_registry() + resource_manager_registry.init_registry() diff --git a/geonode/services/serviceprocessors/__init__.py b/geonode/services/serviceprocessors/__init__.py index a8601d05d5c..8a79fce4611 100644 --- a/geonode/services/serviceprocessors/__init__.py +++ b/geonode/services/serviceprocessors/__init__.py @@ -1,80 +1,80 @@ -######################################################################### -# -# Copyright (C) 2017 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 . -# -######################################################################### -import logging - -from collections import OrderedDict -from django.utils.translation import gettext_lazy as _ -from django.conf import settings -from geonode.services import enumerations -from geonode.services.utils import parse_services_types -from django.core.cache import caches - -service_cache = caches["services"] -logger = logging.getLogger(__name__) - - -def get_available_service_types(): - # LGTM: Fixes - Module uses member of cyclically imported module, which can lead to failure at import time. - from geonode.services.serviceprocessors.wms import GeoNodeServiceHandler, WmsServiceHandler - from geonode.services.serviceprocessors.arcgis import ArcImageServiceHandler, ArcMapServiceHandler - - default = OrderedDict( - { - enumerations.WMS: {"OWS": True, "handler": WmsServiceHandler, "label": _("Web Map Service")}, - enumerations.GN_WMS: { - "OWS": True, - "handler": GeoNodeServiceHandler, - "label": _("GeoNode (Web Map Service)"), - }, - # enumerations.WFS: {"OWS": True, "handler": ServiceHandlerBase, "label": _('Paired WMS/WFS/WCS'}, - # enumerations.TMS: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Paired WMS/WFS/WCS'}, - enumerations.REST_MAP: {"OWS": False, "handler": ArcMapServiceHandler, "label": _("ArcGIS REST MapServer")}, - enumerations.REST_IMG: { - "OWS": False, - "handler": ArcImageServiceHandler, - "label": _("ArcGIS REST ImageServer"), - }, - # enumerations.CSW: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Catalogue Service')}, - # enumerations.OGP: {"OWS": True, "handler": ServiceHandlerBase, "label": _('OpenGeoPortal')}, # TODO: verify this - # enumerations.HGL: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Harvard Geospatial Library')}, # TODO: verify this - } - ) - - return OrderedDict({**default, **parse_services_types()}) - - -def get_service_handler(base_url, service_type=enumerations.AUTO, service_id=None, *args, **kwargs): - """Return the appropriate remote service handler for the input URL. - If the service type is not explicitly passed in it will be guessed from - """ - - if entry := service_cache.get(base_url): - return entry - - handlers = get_available_service_types() - - handler = handlers.get(service_type, {}).get("handler") - try: - service_handler = handler(base_url, service_id, *args, **kwargs) - service_cache.set(service_handler.url, service_handler, settings.SERVICE_CACHE_EXPIRATION_TIME) - except Exception as e: - logger.exception(e) - logger.exception(msg=f"Could not parse service {base_url}") - raise - return service_handler +######################################################################### +# +# Copyright (C) 2017 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 . +# +######################################################################### +import logging + +from collections import OrderedDict +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from geonode.services import enumerations +from geonode.services.utils import parse_services_types +from django.core.cache import caches + +service_cache = caches["services"] +logger = logging.getLogger(__name__) + + +def get_available_service_types(): + # LGTM: Fixes - Module uses member of cyclically imported module, which can lead to failure at import time. + from geonode.services.serviceprocessors.wms import GeoNodeServiceHandler, WmsServiceHandler + from geonode.services.serviceprocessors.arcgis import ArcImageServiceHandler, ArcMapServiceHandler + + default = OrderedDict( + { + enumerations.WMS: {"OWS": True, "handler": WmsServiceHandler, "label": _("Web Map Service")}, + enumerations.GN_WMS: { + "OWS": True, + "handler": GeoNodeServiceHandler, + "label": _("GeoNode (Web Map Service)"), + }, + # enumerations.WFS: {"OWS": True, "handler": ServiceHandlerBase, "label": _('Paired WMS/WFS/WCS'}, + # enumerations.TMS: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Paired WMS/WFS/WCS'}, + enumerations.REST_MAP: {"OWS": False, "handler": ArcMapServiceHandler, "label": _("ArcGIS REST MapServer")}, + enumerations.REST_IMG: { + "OWS": False, + "handler": ArcImageServiceHandler, + "label": _("ArcGIS REST ImageServer"), + }, + # enumerations.CSW: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Catalogue Service')}, + # enumerations.OGP: {"OWS": True, "handler": ServiceHandlerBase, "label": _('OpenGeoPortal')}, # TODO: verify this + # enumerations.HGL: {"OWS": False, "handler": ServiceHandlerBase, "label": _('Harvard Geospatial Library')}, # TODO: verify this + } + ) + + return OrderedDict({**default, **parse_services_types()}) + + +def get_service_handler(base_url, service_type=enumerations.AUTO, service_id=None, *args, **kwargs): + """Return the appropriate remote service handler for the input URL. + If the service type is not explicitly passed in it will be guessed from + """ + + if entry := service_cache.get(base_url): + return entry + + handlers = get_available_service_types() + + handler = handlers.get(service_type, {}).get("handler") + try: + service_handler = handler(base_url, service_id, *args, **kwargs) + service_cache.set(service_handler.url, service_handler, settings.SERVICE_CACHE_EXPIRATION_TIME) + except Exception as e: + logger.exception(e) + logger.exception(msg=f"Could not parse service {base_url}") + raise + return service_handler diff --git a/geonode/settings.py b/geonode/settings.py index 84a17ca31b7..573c0872a3e 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -1751,7 +1751,19 @@ def get_geonode_catalogue_service(): # }, CELERY_BEAT_SCHEDULER = os.environ.get("CELERY_BEAT_SCHEDULER", "celery.beat:PersistentScheduler") -CELERY_BEAT_SCHEDULE = {} +CELERY_BEAT_SCHEDULE = { + "sync-geoserver-layers": { + "task": "geonode.geoserver.tasks.geoserver_update_datasets", + "schedule": int(os.environ.get("GEOSERVER_SYNC_INTERVAL", "120")), + "kwargs": { + "workspace": "geonode", + "store": "db_geo_prd", + "owner": "admin", + "skip_geonode_registered": True, + "execute_signals": True, + }, + }, +} DELAYED_SECURITY_SIGNALS = ast.literal_eval(os.environ.get("DELAYED_SECURITY_SIGNALS", "False")) CELERY_ENABLE_UTC = ast.literal_eval(os.environ.get("CELERY_ENABLE_UTC", "True")) diff --git a/geonode/static/geonode/css/cookie-law-info/cookie-law-info-gdpr.css b/geonode/static/geonode/css/cookie-law-info/cookie-law-info-gdpr.css index d7deae3774a..5608b8b28e5 100644 --- a/geonode/static/geonode/css/cookie-law-info/cookie-law-info-gdpr.css +++ b/geonode/static/geonode/css/cookie-law-info/cookie-law-info-gdpr.css @@ -1,604 +1,604 @@ -.gdpr-container-fluid { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -.gdpr-row { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -15px; - margin-left: -15px; -} -.gdpr-col-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; -} -.gdpr-col-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; -} -.gdpr-align-items-stretch { - -ms-flex-align: stretch!important; - align-items: stretch!important; -} -.gdpr-d-flex { - display: -ms-flexbox!important; - display: flex!important; -} -.gdpr-px-0 { - padding-left: 0; - padding-right: 0; -} -.modal-backdrop.show { - opacity: .8; -} -.modal-open { - overflow: hidden -} - -.modal-open .gdpr-modal { - overflow-x: hidden; - overflow-y: auto -} - -.gdpr-modal.fade .gdpr-modal-dialog { - transition: -webkit-transform .3s ease-out; - transition: transform .3s ease-out; - transition: transform .3s ease-out,-webkit-transform .3s ease-out; - -webkit-transform: translate(0,-25%); - transform: translate(0,-25%) -} - -.gdpr-modal.show .gdpr-modal-dialog { - -webkit-transform: translate(0,0); - transform: translate(0,0) -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1039; - background-color: #000 -} - -.modal-backdrop.fade { - opacity: 0 -} - -.modal-backdrop.show { - opacity: .5 -} - -.gdpr-modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - outline: 0 -} -.gdpr-modal a { - text-decoration: none; -} -.gdpr-modal .gdpr-modal-dialog { - position: relative; - width: auto; - margin: .5rem; - pointer-events: none; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212529; - text-align: left; - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - min-height: calc(100% - (.5rem * 2)) -} -@media (min-width: 576px) { - .gdpr-modal .gdpr-modal-dialog { - max-width:500px; - margin: 1.75rem auto; - min-height: calc(100% - (1.75rem * 2)); - } -} -@media (min-width: 992px) { - .gdpr-modal .gdpr-modal-dialog { - max-width: 900px; - } -} -.gdpr-modal-content { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - width: 100%; - pointer-events: auto; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0,0,0,.2); - border-radius: .3rem; - outline: 0 -} -.gdpr-modal .row { - margin: 0 -15px; -} -.gdpr-modal .modal-body { - padding: 0; - position: relative; - -ms-flex: 1 1 auto; - flex: 1 1 auto; -} -.gdpr-modal .close { - position: absolute; - right: 10px; - top: 10px; - z-index: 1; - padding: 0; - background-color: transparent; - border: 0; - -webkit-appearance: none; - font-size: 1.5rem; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; -} -.gdpr-modal .close:focus { - outline: 0; -} -.gdpr-switch { - display: inline-block; - position: relative; - min-height: 1px; - padding-left: 70px; - font-size: 14px; -} -.gdpr-switch input[type="checkbox"] { - display:none; -} -.gdpr-switch .gdpr-slider { - background-color: #e3e1e8; - height: 24px; - width: 50px; - bottom: 0; - cursor: pointer; - left: 0; - position: absolute; - right: 0; - top: 0; - transition: .4s; -} -.gdpr-switch .gdpr-slider:before { - background-color: #fff; - bottom: 2px; - content: ""; - height: 20px; - left: 2px; - position: absolute; - transition: .4s; - width: 20px; -} -.gdpr-switch input:checked + .gdpr-slider { - background-color:rgb(99, 179, 95); -} -.gdpr-switch input:checked + .gdpr-slider:before { - transform: translateX(26px); -} -.gdpr-switch .gdpr-slider { - border-radius: 34px; -} -.gdpr-switch .gdpr-slider:before { - border-radius: 50%; -} -.gdpr-tab-content>.gdpr-tab-pane { - display: none; -} -.gdpr-tab-content>.active { - display: block; -} -.gdpr-fade { - transition: opacity .15s linear; -} -.gdpr-nav-pills { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - padding-left: 0; - margin-bottom: 0; - list-style: none; - -ms-flex-direction: column !important; - flex-direction: column !important; - align-items: stretch !important; - -ms-align-items: stretch !important; -} -.nav.gdpr-nav-pills, .gdpr-tab-content { - width: 100%; - padding: 30px; -} -.nav.gdpr-nav-pills { - background: #f3f3f3; -} -.nav.gdpr-nav-pills .gdpr-nav-link { - border: 1px solid #0070ad; - margin-bottom: 10px; - color: #0070ad; - font-size: 14px; - display: block; - padding: .5rem 1rem; - border-radius: .25rem; -} -.nav.gdpr-nav-pills .gdpr-nav-link.active, .nav.gdpr-nav-pills .show>.gdpr-nav-link { - background-color: #0070ad; - border: 1px solid #0070ad; -} -.nav.gdpr-nav-pills .gdpr-nav-link.active { - color: #ffffff; -} -.gdpr-tab-content .gdpr-button-wrapper { - padding-top: 30px; - margin-top: 30px; - border-top: 1px solid #d6d6d6; -} -.gdpr-tab-content .gdpr-button-wrapper .btn-gdpr { - background-color: #0070ad; - border-color: #0070ad; - color: #ffffff; - font-size: 14px; - display: inline-block; - font-weight: 400; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - border: 1px solid transparent; - padding: .375rem .75rem; - font-size: 1rem; - line-height: 1.5; - border-radius: .25rem; - transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; -} -.gdpr-tab-content p { - color: #343438; - font-size: 14px; - margin-top: 0; -} -.gdpr-tab-content h4 { - font-size: 20px; - margin-bottom: .5rem; - margin-top: 0; - font-family: inherit; - font-weight: 500; - line-height: 1.2; - color: inherit; -} - - -.cli-container-fluid { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -.cli-row { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - margin-right: -15px; - margin-left: -15px; -} -.cli-col-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; -} -.cli-col-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; -} -.cli-align-items-stretch { - -ms-flex-align: stretch!important; - align-items: stretch!important; -} -.cli-d-flex { - display: -ms-flexbox!important; - display: flex!important; -} -.cli-px-0 { - padding-left: 0; - padding-right: 0; -} -.cli-btn { - cursor: pointer; - font-size: 14px; - display: inline-block; - font-weight: 400; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - border: 1px solid transparent; - padding: .5rem 1.25rem; - line-height: 1; - border-radius: .25rem; - transition: all .15s ease-in-out; -} -.cli-btn:hover { - opacity: .8; -} -.cli-read-more-link { - cursor: pointer; - font-size: 15px; - font-weight: 500; - text-decoration: underline; -} -.cli-btn:focus { - outline: 0; -} -.cli-modal-backdrop.cli-show { - opacity: .8; -} -.cli-modal-open { - overflow: hidden -} -.cli-barmodal-open { - overflow: hidden -} -.cli-modal-open .cli-modal { - overflow-x: hidden; - overflow-y: auto -} -.cli-modal.cli-fade .cli-modal-dialog { - transition: -webkit-transform .3s ease-out; - transition: transform .3s ease-out; - transition: transform .3s ease-out,-webkit-transform .3s ease-out; - -webkit-transform: translate(0,-25%); - transform: translate(0,-25%) -} -.cli-modal.cli-show .cli-modal-dialog { - -webkit-transform: translate(0,0); - transform: translate(0,0) -} -.cli-modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000; - display: none; -} -.cli-modal-backdrop.cli-fade { - opacity: 0 -} -.cli-modal-backdrop.cli-show { - opacity: .5; - display: block; -} -.cli-modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 99999; - display: none; - overflow: hidden; - outline: 0 -} -.cli-modal.cli-show { - display: block; -} -.cli-modal a { - text-decoration: none; -} -.cli-modal .cli-modal-dialog { - position: relative; - width: auto; - margin: .5rem; - pointer-events: none; - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212529; - text-align: left; - display: -ms-flexbox; - display: flex; - -ms-flex-align: center; - align-items: center; - min-height: calc(100% - (.5rem * 2)) -} -@media (min-width: 576px) { - .cli-modal .cli-modal-dialog { - max-width:500px; - margin: 1.75rem auto; - min-height: calc(100% - (1.75rem * 2)) - } -} -@media (min-width: 992px) { - .cli-modal .cli-modal-dialog { - max-width: 900px; - } -} -.cli-modal-content { - position: relative; - display: -ms-flexbox; - display: flex; - -ms-flex-direction: column; - flex-direction: column; - width: 100%; - pointer-events: auto; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0,0,0,.2); - border-radius: .3rem; - outline: 0 -} -.cli-modal .row { - margin: 0 -15px; -} -.cli-modal .modal-body { - padding: 0; - position: relative; - -ms-flex: 1 1 auto; - flex: 1 1 auto; -} -.cli-modal .cli-modal-close { - position: absolute; - right: 10px; - top: 10px; - z-index: 1; - padding: 0; - background-color: transparent; - border: 0; - -webkit-appearance: none; - font-size: 1.5rem; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; -} -.cli-modal .cli-modal-close:focus { - outline: 0; -} -.cli-switch { - display: inline-block; - position: relative; - min-height: 1px; - padding-left: 70px; - font-size: 14px; -} -.cli-switch input[type="checkbox"] { - display:none; -} -.cli-switch .cli-slider { - background-color: #e3e1e8; - height: 24px; - width: 50px; - bottom: 0; - cursor: pointer; - left: 0; - position: absolute; - right: 0; - top: 0; - transition: .4s; -} -.cli-switch .cli-slider:before { - background-color: #fff; - bottom: 2px; - content: ""; - height: 20px; - left: 2px; - position: absolute; - transition: .4s; - width: 20px; -} -.cli-switch input:checked + .cli-slider { - background-color: #00acad -} -.cli-switch input:checked + .cli-slider:before { - transform: translateX(26px); -} -.cli-switch .cli-slider { - border-radius: 34px; -} -.cli-switch .cli-slider:before { - border-radius: 50%; -} -.cli-tab-content { -background: #ffffff; -} -.cli-tab-content>.cli-tab-pane { - display: none; -} -.cli-tab-content>.cli-active { - display: block; -} -.cli-fade { - transition: opacity .15s linear; -} -.cli-nav-pills { - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - padding-left: 0; - margin-bottom: 0; - list-style: none; - -ms-flex-direction: column; - flex-direction: column; -} -.cli-nav-pills, .cli-tab-content { - width: 100%; - padding: 30px; -} -@media (max-width: 767px) { - .cli-nav-pills, .cli-tab-content { - padding: 30px 10px; - } -} -.cli-nav-pills { - background: #f3f3f3; -} -.cli-nav-pills .cli-nav-link { - border: 1px solid #00acad; - margin-bottom: 10px; - color: #00acad; - font-size: 14px; - display: block; - padding: .5rem 1rem; - border-radius: .25rem; - cursor: pointer -} -.cli-nav-pills .cli-nav-link.cli-active, .cli-nav-pills .cli-show>.cli-nav-link { - background-color: #00acad; - border: 1px solid #00acad; -} -.cli-nav-pills .cli-nav-link.cli-active { - color: #ffffff; -} -.cli-tab-content .cli-button-wrapper { - padding-top: 30px; - margin-top: 30px; - border-top: 1px solid #d6d6d6; -} -.cli-tab-content p { - color: #343438; - font-size: 14px; - margin-top: 0; -} -.cli-tab-content h4 { - font-size: 20px; - margin-bottom: 1.5rem; - margin-top: 0; - font-family: inherit; - font-weight: 500; - line-height: 1.2; - color: inherit; -} +.gdpr-container-fluid { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.gdpr-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} +.gdpr-col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} +.gdpr-col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} +.gdpr-align-items-stretch { + -ms-flex-align: stretch!important; + align-items: stretch!important; +} +.gdpr-d-flex { + display: -ms-flexbox!important; + display: flex!important; +} +.gdpr-px-0 { + padding-left: 0; + padding-right: 0; +} +.modal-backdrop.show { + opacity: .8; +} +.modal-open { + overflow: hidden +} + +.modal-open .gdpr-modal { + overflow-x: hidden; + overflow-y: auto +} + +.gdpr-modal.fade .gdpr-modal-dialog { + transition: -webkit-transform .3s ease-out; + transition: transform .3s ease-out; + transition: transform .3s ease-out,-webkit-transform .3s ease-out; + -webkit-transform: translate(0,-25%); + transform: translate(0,-25%) +} + +.gdpr-modal.show .gdpr-modal-dialog { + -webkit-transform: translate(0,0); + transform: translate(0,0) +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1039; + background-color: #000 +} + +.modal-backdrop.fade { + opacity: 0 +} + +.modal-backdrop.show { + opacity: .5 +} + +.gdpr-modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + display: none; + overflow: hidden; + outline: 0 +} +.gdpr-modal a { + text-decoration: none; +} +.gdpr-modal .gdpr-modal-dialog { + position: relative; + width: auto; + margin: .5rem; + pointer-events: none; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - (.5rem * 2)) +} +@media (min-width: 576px) { + .gdpr-modal .gdpr-modal-dialog { + max-width:500px; + margin: 1.75rem auto; + min-height: calc(100% - (1.75rem * 2)); + } +} +@media (min-width: 992px) { + .gdpr-modal .gdpr-modal-dialog { + max-width: 900px; + } +} +.gdpr-modal-content { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.2); + border-radius: .3rem; + outline: 0 +} +.gdpr-modal .row { + margin: 0 -15px; +} +.gdpr-modal .modal-body { + padding: 0; + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} +.gdpr-modal .close { + position: absolute; + right: 10px; + top: 10px; + z-index: 1; + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; +} +.gdpr-modal .close:focus { + outline: 0; +} +.gdpr-switch { + display: inline-block; + position: relative; + min-height: 1px; + padding-left: 70px; + font-size: 14px; +} +.gdpr-switch input[type="checkbox"] { + display:none; +} +.gdpr-switch .gdpr-slider { + background-color: #e3e1e8; + height: 24px; + width: 50px; + bottom: 0; + cursor: pointer; + left: 0; + position: absolute; + right: 0; + top: 0; + transition: .4s; +} +.gdpr-switch .gdpr-slider:before { + background-color: #fff; + bottom: 2px; + content: ""; + height: 20px; + left: 2px; + position: absolute; + transition: .4s; + width: 20px; +} +.gdpr-switch input:checked + .gdpr-slider { + background-color:rgb(99, 179, 95); +} +.gdpr-switch input:checked + .gdpr-slider:before { + transform: translateX(26px); +} +.gdpr-switch .gdpr-slider { + border-radius: 34px; +} +.gdpr-switch .gdpr-slider:before { + border-radius: 50%; +} +.gdpr-tab-content>.gdpr-tab-pane { + display: none; +} +.gdpr-tab-content>.active { + display: block; +} +.gdpr-fade { + transition: opacity .15s linear; +} +.gdpr-nav-pills { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; + -ms-flex-direction: column !important; + flex-direction: column !important; + align-items: stretch !important; + -ms-align-items: stretch !important; +} +.nav.gdpr-nav-pills, .gdpr-tab-content { + width: 100%; + padding: 30px; +} +.nav.gdpr-nav-pills { + background: #f3f3f3; +} +.nav.gdpr-nav-pills .gdpr-nav-link { + border: 1px solid #0070ad; + margin-bottom: 10px; + color: #0070ad; + font-size: 14px; + display: block; + padding: .5rem 1rem; + border-radius: .25rem; +} +.nav.gdpr-nav-pills .gdpr-nav-link.active, .nav.gdpr-nav-pills .show>.gdpr-nav-link { + background-color: #0070ad; + border: 1px solid #0070ad; +} +.nav.gdpr-nav-pills .gdpr-nav-link.active { + color: #ffffff; +} +.gdpr-tab-content .gdpr-button-wrapper { + padding-top: 30px; + margin-top: 30px; + border-top: 1px solid #d6d6d6; +} +.gdpr-tab-content .gdpr-button-wrapper .btn-gdpr { + background-color: #0070ad; + border-color: #0070ad; + color: #ffffff; + font-size: 14px; + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border: 1px solid transparent; + padding: .375rem .75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: .25rem; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; +} +.gdpr-tab-content p { + color: #343438; + font-size: 14px; + margin-top: 0; +} +.gdpr-tab-content h4 { + font-size: 20px; + margin-bottom: .5rem; + margin-top: 0; + font-family: inherit; + font-weight: 500; + line-height: 1.2; + color: inherit; +} + + +.cli-container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.cli-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} +.cli-col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} +.cli-col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} +.cli-align-items-stretch { + -ms-flex-align: stretch!important; + align-items: stretch!important; +} +.cli-d-flex { + display: -ms-flexbox!important; + display: flex!important; +} +.cli-px-0 { + padding-left: 0; + padding-right: 0; +} +.cli-btn { + cursor: pointer; + font-size: 14px; + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border: 1px solid transparent; + padding: .5rem 1.25rem; + line-height: 1; + border-radius: .25rem; + transition: all .15s ease-in-out; +} +.cli-btn:hover { + opacity: .8; +} +.cli-read-more-link { + cursor: pointer; + font-size: 15px; + font-weight: 500; + text-decoration: underline; +} +.cli-btn:focus { + outline: 0; +} +.cli-modal-backdrop.cli-show { + opacity: .8; +} +.cli-modal-open { + overflow: hidden +} +.cli-barmodal-open { + overflow: hidden +} +.cli-modal-open .cli-modal { + overflow-x: hidden; + overflow-y: auto +} +.cli-modal.cli-fade .cli-modal-dialog { + transition: -webkit-transform .3s ease-out; + transition: transform .3s ease-out; + transition: transform .3s ease-out,-webkit-transform .3s ease-out; + -webkit-transform: translate(0,-25%); + transform: translate(0,-25%) +} +.cli-modal.cli-show .cli-modal-dialog { + -webkit-transform: translate(0,0); + transform: translate(0,0) +} +.cli-modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; + display: none; +} +.cli-modal-backdrop.cli-fade { + opacity: 0 +} +.cli-modal-backdrop.cli-show { + opacity: .5; + display: block; +} +.cli-modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99999; + display: none; + overflow: hidden; + outline: 0 +} +.cli-modal.cli-show { + display: block; +} +.cli-modal a { + text-decoration: none; +} +.cli-modal .cli-modal-dialog { + position: relative; + width: auto; + margin: .5rem; + pointer-events: none; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - (.5rem * 2)) +} +@media (min-width: 576px) { + .cli-modal .cli-modal-dialog { + max-width:500px; + margin: 1.75rem auto; + min-height: calc(100% - (1.75rem * 2)) + } +} +@media (min-width: 992px) { + .cli-modal .cli-modal-dialog { + max-width: 900px; + } +} +.cli-modal-content { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.2); + border-radius: .3rem; + outline: 0 +} +.cli-modal .row { + margin: 0 -15px; +} +.cli-modal .modal-body { + padding: 0; + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} +.cli-modal .cli-modal-close { + position: absolute; + right: 10px; + top: 10px; + z-index: 1; + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; +} +.cli-modal .cli-modal-close:focus { + outline: 0; +} +.cli-switch { + display: inline-block; + position: relative; + min-height: 1px; + padding-left: 70px; + font-size: 14px; +} +.cli-switch input[type="checkbox"] { + display:none; +} +.cli-switch .cli-slider { + background-color: #e3e1e8; + height: 24px; + width: 50px; + bottom: 0; + cursor: pointer; + left: 0; + position: absolute; + right: 0; + top: 0; + transition: .4s; +} +.cli-switch .cli-slider:before { + background-color: #fff; + bottom: 2px; + content: ""; + height: 20px; + left: 2px; + position: absolute; + transition: .4s; + width: 20px; +} +.cli-switch input:checked + .cli-slider { + background-color: #00acad +} +.cli-switch input:checked + .cli-slider:before { + transform: translateX(26px); +} +.cli-switch .cli-slider { + border-radius: 34px; +} +.cli-switch .cli-slider:before { + border-radius: 50%; +} +.cli-tab-content { +background: #ffffff; +} +.cli-tab-content>.cli-tab-pane { + display: none; +} +.cli-tab-content>.cli-active { + display: block; +} +.cli-fade { + transition: opacity .15s linear; +} +.cli-nav-pills { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; + -ms-flex-direction: column; + flex-direction: column; +} +.cli-nav-pills, .cli-tab-content { + width: 100%; + padding: 30px; +} +@media (max-width: 767px) { + .cli-nav-pills, .cli-tab-content { + padding: 30px 10px; + } +} +.cli-nav-pills { + background: #f3f3f3; +} +.cli-nav-pills .cli-nav-link { + border: 1px solid #00acad; + margin-bottom: 10px; + color: #00acad; + font-size: 14px; + display: block; + padding: .5rem 1rem; + border-radius: .25rem; + cursor: pointer +} +.cli-nav-pills .cli-nav-link.cli-active, .cli-nav-pills .cli-show>.cli-nav-link { + background-color: #00acad; + border: 1px solid #00acad; +} +.cli-nav-pills .cli-nav-link.cli-active { + color: #ffffff; +} +.cli-tab-content .cli-button-wrapper { + padding-top: 30px; + margin-top: 30px; + border-top: 1px solid #d6d6d6; +} +.cli-tab-content p { + color: #343438; + font-size: 14px; + margin-top: 0; +} +.cli-tab-content h4 { + font-size: 20px; + margin-bottom: 1.5rem; + margin-top: 0; + font-family: inherit; + font-weight: 500; + line-height: 1.2; + color: inherit; +} diff --git a/geonode/static/geonode/css/cookie-law-info/cookie-law-info-public.css b/geonode/static/geonode/css/cookie-law-info/cookie-law-info-public.css index e6c7d6994d7..910d585f452 100644 --- a/geonode/static/geonode/css/cookie-law-info/cookie-law-info-public.css +++ b/geonode/static/geonode/css/cookie-law-info/cookie-law-info-public.css @@ -1,114 +1,114 @@ -#cookie-law-info-bar { - /*border: 0; */ - font-size: 12pt; - margin: 0 auto; - padding: 13px 10px; - position: absolute; - text-align: center; - box-sizing: border-box; - width:100%; - z-index: 9999; - box-shadow:rgba(0,0,0,.5) 0px 5px 50px; - display: none; - left:0px; - font-weight:300; -} -#cookie-law-info-again { - font-size: 10pt; - margin: 0; - padding:5px 10px; - text-align: center; - z-index: 9999; - cursor: pointer; - box-shadow: #161616 2px 2px 5px 2px; -} -#cookie-law-info-bar span { - vertical-align: middle; -} - -/** Buttons (http://papermashup.com/demos/css-buttons) */ -.cli-plugin-button, .cli-plugin-button:visited { - display: inline-block; - padding:10px 16px 10px; - color: #fff; - text-decoration: none; - position: relative; - cursor: pointer; - margin-left: 0px; - text-decoration: none; -} -.cli-plugin-main-link { - margin-left:0px; - font-weight: 550; text-decoration: underline; -} -.cli-plugin-button:hover { - background-color: #111; - color: #fff; - text-decoration: none; -} -.small.cli-plugin-button, .small.cli-plugin-button:visited { - font-size: 11px; -} -.cli-plugin-button, .cli-plugin-button:visited, - .medium.cli-plugin-button, .medium.cli-plugin-button:visited { - font-size: 14px; - font-weight: 500; - line-height: 1; -} -.large.cli-plugin-button, .large.cli-plugin-button:visited { - font-size: 14px; - padding: 8px 14px 9px; -} -.super.cli-plugin-button, .super.cli-plugin-button:visited { - font-size: 34px; - padding: 8px 14px 9px; -} -.pink.cli-plugin-button, .magenta.cli-plugin-button:visited { - background-color: #e22092; -} -.pink.cli-plugin-button:hover { - background-color: #c81e82; -} -.green.cli-plugin-button, .green.cli-plugin-button:visited { - background-color: #91bd09; -} -.green.cli-plugin-button:hover { - background-color: #749a02; -} -.red.cli-plugin-button, .red.cli-plugin-button:visited { - background-color: #e62727; -} -.red.cli-plugin-button:hover { - background-color: #cf2525; -} -.orange.cli-plugin-button, .orange.cli-plugin-button:visited { - background-color: #ff5c00; -} -.orange.cli-plugin-button:hover { - background-color: #d45500; -} -.blue.cli-plugin-button, .blue.cli-plugin-button:visited { - background-color: #2981e4; -} -.blue.cli-plugin-button:hover { - background-color: #2575cf; -} -.yellow.cli-plugin-button, .yellow.cli-plugin-button:visited { - background-color: #ffb515; -} -.yellow.cli-plugin-button:hover { - background-color: #fc9200; -} -.cli-plugin-button{ margin-top:5px; } -.cli-bar-popup{ - -moz-background-clip: padding; - -webkit-background-clip: padding; - background-clip: padding-box; - border:20px solid rgba(0,0,0,0.5) !important; - -webkit-border-radius:30px; - -moz-border-radius:30px; - border-radius:30px; - padding:20px; -} -.cli-powered_by_p{width:100% !important; display:block !important; color:#333; clear:both; font-style:italic !important; font-size:12px !important; margin-top:15px !important; } -.cli-powered_by_a{color:#333; font-weight:600 !important; font-size:12px !important;} +#cookie-law-info-bar { + /*border: 0; */ + font-size: 12pt; + margin: 0 auto; + padding: 13px 10px; + position: absolute; + text-align: center; + box-sizing: border-box; + width:100%; + z-index: 9999; + box-shadow:rgba(0,0,0,.5) 0px 5px 50px; + display: none; + left:0px; + font-weight:300; +} +#cookie-law-info-again { + font-size: 10pt; + margin: 0; + padding:5px 10px; + text-align: center; + z-index: 9999; + cursor: pointer; + box-shadow: #161616 2px 2px 5px 2px; +} +#cookie-law-info-bar span { + vertical-align: middle; +} + +/** Buttons (http://papermashup.com/demos/css-buttons) */ +.cli-plugin-button, .cli-plugin-button:visited { + display: inline-block; + padding:10px 16px 10px; + color: #fff; + text-decoration: none; + position: relative; + cursor: pointer; + margin-left: 0px; + text-decoration: none; +} +.cli-plugin-main-link { + margin-left:0px; + font-weight: 550; text-decoration: underline; +} +.cli-plugin-button:hover { + background-color: #111; + color: #fff; + text-decoration: none; +} +.small.cli-plugin-button, .small.cli-plugin-button:visited { + font-size: 11px; +} +.cli-plugin-button, .cli-plugin-button:visited, + .medium.cli-plugin-button, .medium.cli-plugin-button:visited { + font-size: 14px; + font-weight: 500; + line-height: 1; +} +.large.cli-plugin-button, .large.cli-plugin-button:visited { + font-size: 14px; + padding: 8px 14px 9px; +} +.super.cli-plugin-button, .super.cli-plugin-button:visited { + font-size: 34px; + padding: 8px 14px 9px; +} +.pink.cli-plugin-button, .magenta.cli-plugin-button:visited { + background-color: #e22092; +} +.pink.cli-plugin-button:hover { + background-color: #c81e82; +} +.green.cli-plugin-button, .green.cli-plugin-button:visited { + background-color: #91bd09; +} +.green.cli-plugin-button:hover { + background-color: #749a02; +} +.red.cli-plugin-button, .red.cli-plugin-button:visited { + background-color: #e62727; +} +.red.cli-plugin-button:hover { + background-color: #cf2525; +} +.orange.cli-plugin-button, .orange.cli-plugin-button:visited { + background-color: #ff5c00; +} +.orange.cli-plugin-button:hover { + background-color: #d45500; +} +.blue.cli-plugin-button, .blue.cli-plugin-button:visited { + background-color: #2981e4; +} +.blue.cli-plugin-button:hover { + background-color: #2575cf; +} +.yellow.cli-plugin-button, .yellow.cli-plugin-button:visited { + background-color: #ffb515; +} +.yellow.cli-plugin-button:hover { + background-color: #fc9200; +} +.cli-plugin-button{ margin-top:5px; } +.cli-bar-popup{ + -moz-background-clip: padding; + -webkit-background-clip: padding; + background-clip: padding-box; + border:20px solid rgba(0,0,0,0.5) !important; + -webkit-border-radius:30px; + -moz-border-radius:30px; + border-radius:30px; + padding:20px; +} +.cli-powered_by_p{width:100% !important; display:block !important; color:#333; clear:both; font-style:italic !important; font-size:12px !important; margin-top:15px !important; } +.cli-powered_by_a{color:#333; font-weight:600 !important; font-size:12px !important;} diff --git a/geonode/static/geonode/js/cookie-law-info/cookie-law-info-public.js b/geonode/static/geonode/js/cookie-law-info/cookie-law-info-public.js index 974a4aa44f0..c9bf6a8c050 100644 --- a/geonode/static/geonode/js/cookie-law-info/cookie-law-info-public.js +++ b/geonode/static/geonode/js/cookie-law-info/cookie-law-info-public.js @@ -1,563 +1,563 @@ -CLI_ACCEPT_COOKIE_NAME =(typeof CLI_ACCEPT_COOKIE_NAME !== 'undefined' ? CLI_ACCEPT_COOKIE_NAME : 'viewed_cookie_policy'); -CLI_ACCEPT_COOKIE_EXPIRE =(typeof CLI_ACCEPT_COOKIE_EXPIRE !== 'undefined' ? CLI_ACCEPT_COOKIE_EXPIRE : 365); -CLI_COOKIEBAR_AS_POPUP=(typeof CLI_COOKIEBAR_AS_POPUP !== 'undefined' ? CLI_COOKIEBAR_AS_POPUP : false); -var CLI_Cookie={ - set: function (name, value, days) { - if (days) { - var date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - var expires = "; expires=" + date.toGMTString(); - } else - var expires = ""; - document.cookie = name + "=" + value + expires + "; path=/"; - if(days<1) - { - host_name=window.location.hostname; - document.cookie = name + "=" + value + expires + "; path=/; domain=."+host_name+";"; - if(host_name.indexOf("www")!=1) - { - var host_name_withoutwww=host_name.replace('www',''); - document.cookie = name + "=" + value + expires + "; path=/; domain="+host_name_withoutwww+";"; - } - host_name=host_name.substring(host_name.lastIndexOf(".", host_name.lastIndexOf(".")-1)); - document.cookie = name + "=" + value + expires + "; path=/; domain="+host_name+";"; - } - }, - read: function (name) { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') { - c = c.substring(1, c.length); - } - if (c.indexOf(nameEQ) === 0) { - return c.substring(nameEQ.length, c.length); - } - } - return null; - }, - erase: function (name) { - this.set(name, "", -10); - }, - exists: function (name) { - return (this.read(name) !== null); - }, - getallcookies:function() - { - var pairs = document.cookie.split(";"); - var cookieslist = {}; - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split("="); - cookieslist[(pair[0] + '').trim()] = unescape(pair[1]); - } - return cookieslist; - } -} -var CLI= -{ - bar_config:{}, - showagain_config:{}, - set:function(args) - { - if(typeof JSON.parse !== "function") - { - console.log("CookieLawInfo requires JSON.parse but your browser doesn't support it"); - return; - } - this.settings = JSON.parse(args.settings); - this.bar_elm=jQuery(this.settings.notify_div_id); - this.showagain_elm = jQuery(this.settings.showagain_div_id); - - /* buttons */ - this.main_button=jQuery('.cli-plugin-main-button'); - this.main_link = jQuery('.cli-plugin-main-link'); - this.reject_link = jQuery('.cookie_action_close_header_reject'); - this.delete_link=jQuery(".cookielawinfo-cookie-delete"); - - if(this.settings.cookie_bar_as=='popup') - { - CLI_COOKIEBAR_AS_POPUP=true; - } - this.configBar(); - this.toggleBar(); - this.attachDelete(); - this.attachEvents(); - this.configButtons(); - var cli_hidebar_on_readmore=this.hideBarInReadMoreLink(); - if(this.settings.scroll_close===true && cli_hidebar_on_readmore===false) - { - window.addEventListener("scroll",CLI.closeOnScroll, false); - } - }, - hideBarInReadMoreLink:function() - { - if(CLI.settings.button_2_hidebar===true && this.main_link.length>0 && this.main_link.hasClass('cli-minimize-bar')) - { - this.hideHeader(); - this.showagain_elm.slideDown(this.settings.animate_speed_show); - return true; - } - return false; - }, - attachEvents:function() - { - jQuery('.cli_action_button').click(function(e){ - e.preventDefault(); - var elm=jQuery(this); - var button_action=elm.attr('data-cli_action'); - var open_link=elm[0].hasAttribute("href") && elm.attr("href") != '#' ? true : false; - var new_window=false; - if(button_action=='accept') - { - CLI.accept_close(); - new_window=CLI.settings.button_1_new_win ? true : false; - }else if(button_action=='reject') - { - CLI.reject_close(); - new_window=CLI.settings.button_3_new_win ? true : false; - } - if(open_link) - { - if(new_window) - { - window.open(elm.attr("href"),'_blank'); - }else - { - window.location.href =elm.attr("href"); - } - } - }); - }, - attachDelete:function() - { - this.delete_link.click(function () { - CLI_Cookie.erase(CLI_ACCEPT_COOKIE_NAME); - for(var k in Cli_Data.nn_cookie_ids) - { - CLI_Cookie.erase(Cli_Data.nn_cookie_ids[k]); - } - return false; - }); - }, - configButtons:function() - { - /*[cookie_button] */ - this.main_button.css('color',this.settings.button_1_link_colour); - if(this.settings.button_1_as_button) - { - this.main_button.css('background-color',this.settings.button_1_button_colour); - this.main_button.hover(function () { - jQuery(this).css('background-color',CLI.settings.button_1_button_hover); - },function (){ - jQuery(this).css('background-color',CLI.settings.button_1_button_colour); - }); - } - - /* [cookie_link] */ - this.main_link.css('color',this.settings.button_2_link_colour); - if(this.settings.button_2_as_button) - { - this.main_link.css('background-color',this.settings.button_2_button_colour); - this.main_link.hover(function () { - jQuery(this).css('background-color',CLI.settings.button_2_button_hover); - },function (){ - jQuery(this).css('background-color',CLI.settings.button_2_button_colour); - }); - } - - - /* [cookie_reject] */ - this.reject_link.css('color',this.settings.button_3_link_colour); - if(this.settings.button_3_as_button) - { - this.reject_link.css('background-color',this.settings.button_3_button_colour); - this.reject_link.hover(function () { - jQuery(this).css('background-color',CLI.settings.button_3_button_hover); - },function () { - jQuery(this).css('background-color',CLI.settings.button_3_button_colour); - }); - } - }, - toggleBar:function() - { - if(CLI_COOKIEBAR_AS_POPUP) - { - this.barAsPopUp(1); - } - if(CLI.settings.cookie_bar_as=='widget') - { - this.barAsWidget(1); - } - if(!CLI_Cookie.exists(CLI_ACCEPT_COOKIE_NAME)) - { - this.displayHeader(); - }else - { - this.hideHeader(); - } - if(this.settings.show_once_yn) - { - setTimeout(function(){ - CLI.close_header(); - },CLI.settings.show_once); - } - - this.showagain_elm.click(function (e) { - e.preventDefault(); - CLI.showagain_elm.slideUp(CLI.settings.animate_speed_hide,function() - { - CLI.bar_elm.slideDown(CLI.settings.animate_speed_show); - if(CLI_COOKIEBAR_AS_POPUP) - { - CLI.showPopupOverlay(); - } - }); - }); - }, - configShowAgain:function() - { - this.showagain_config = { - 'background-color': this.settings.background, - 'color':this.l1hs(this.settings.text), - 'position': 'fixed', - 'font-family': this.settings.font_family - }; - if(this.settings.border_on) - { - var border_to_hide = 'border-' + this.settings.notify_position_vertical; - this.showagain_config['border'] = '1px solid ' + this.l1hs(this.settings.border); - this.showagain_config[border_to_hide] = 'none'; - } - var cli_win=jQuery(window); - var cli_winw=cli_win.width(); - var showagain_x_pos=this.settings.showagain_x_position; - if(cli_winw<300) - { - showagain_x_pos=10; - this.showagain_config.width=cli_winw-20; - }else - { - this.showagain_config.width='auto'; - } - var cli_defw=cli_winw>400 ? 500 : cli_winw-20; - if(CLI_COOKIEBAR_AS_POPUP) /* cookie bar as popup */ - { - var sa_pos=this.settings.popup_showagain_position; - var sa_pos_arr=sa_pos.split('-'); - if(sa_pos_arr[1]=='left') - { - this.showagain_config.left=showagain_x_pos; - }else if(sa_pos_arr[1]=='right') - { - this.showagain_config.right=showagain_x_pos; - } - if(sa_pos_arr[0]=='top') - { - this.showagain_config.top=0; - - }else if(sa_pos_arr[0]=='bottom') - { - this.showagain_config.bottom=0; - } - this.bar_config['position'] = 'fixed'; - - }else if(this.settings.cookie_bar_as=='widget') - { - this.showagain_config.bottom=0; - if(this.settings.widget_position=='left') - { - this.showagain_config.left=showagain_x_pos; - }else if(this.settings.widget_position=='right') - { - this.showagain_config.right=showagain_x_pos; - } - } - else - { - if(this.settings.notify_position_vertical == "top") - { - this.showagain_config.top = '0'; - } - else if(this.settings.notify_position_vertical == "bottom") - { - this.bar_config['position'] = 'fixed'; - this.bar_config['bottom'] = '0'; - this.showagain_config.bottom = '0'; - } - if(this.settings.notify_position_horizontal == "left") - { - this.showagain_config.left =showagain_x_pos; - }else if(this.settings.notify_position_horizontal == "right") - { - this.showagain_config.right =showagain_x_pos; - } - } - this.showagain_elm.css(this.showagain_config); - }, - configBar:function() - { - this.bar_config = { - 'background-color':this.settings.background, - 'color':this.settings.text, - 'font-family':this.settings.font_family - }; - if(this.settings.notify_position_vertical=="top") - { - this.bar_config['top'] = '0'; - if(this.settings.header_fix === true) - { - this.bar_config['position'] = 'fixed'; - } - }else - { - this.bar_config['bottom'] = '0'; - } - this.configShowAgain(); - this.bar_elm.css(this.bar_config).hide(); - }, - l1hs:function(str) - { - if (str.charAt(0) == "#") { - str = str.substring(1, str.length); - } else { - return "#" + str; - } - return this.l1hs(str); - }, - close_header:function() - { - CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'yes',CLI_ACCEPT_COOKIE_EXPIRE); - this.hideHeader(); - }, - accept_close:function() - { - this.hidePopupOverlay(); - CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'yes',CLI_ACCEPT_COOKIE_EXPIRE); - if(this.settings.notify_animate_hide) - { - this.bar_elm.slideUp(this.settings.animate_speed_hide); - }else - { - this.bar_elm.hide(); - } - if(this.settings.showagain_tab) - { - this.showagain_elm.slideDown(this.settings.animate_speed_show); - } - if(this.settings.accept_close_reload === true) - { - this.reload_current_page(); - } - return false; - }, - reject_close:function() - { - this.hidePopupOverlay(); - for(var k in Cli_Data.nn_cookie_ids) - { - CLI_Cookie.erase(Cli_Data.nn_cookie_ids[k]); - } - CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'no',CLI_ACCEPT_COOKIE_EXPIRE); - if(this.settings.notify_animate_hide) - { - this.bar_elm.slideUp(this.settings.animate_speed_hide); - } else - { - this.bar_elm.hide(); - } - if(this.settings.showagain_tab) - { - this.showagain_elm.slideDown(this.settings.animate_speed_show); - } - if(this.settings.reject_close_reload === true) - { - this.reload_current_page(); - } - return false; - }, - reload_current_page:function() - { - if(typeof cli_flush_cache!=='undefined' && cli_flush_cache==1) - { - window.location.href=this.add_clear_cache_url_query(); - }else - { - window.location.reload(true); - } - }, - add_clear_cache_url_query:function() - { - var cli_rand=new Date().getTime()/1000; - var cli_url=window.location.href; - var cli_hash_arr=cli_url.split('#'); - var cli_urlparts= cli_hash_arr[0].split('?'); - if(cli_urlparts.length>=2) - { - var cli_url_arr=cli_urlparts[1].split('&'); - cli_url_temp_arr=new Array(); - for(var cli_i=0; cli_i0 ? '&': '')+'cli_action='; - }else - { - cli_url=cli_hash_arr[0]+'?cli_action='; - } - cli_url+=cli_rand; - if(cli_hash_arr.length>1) - { - cli_url+='#'+cli_hash_arr[1]; - } - return cli_url; - }, - closeOnScroll:function() - { - if(window.pageYOffset > 100 && !CLI_Cookie.read(CLI_ACCEPT_COOKIE_NAME)) - { - CLI.accept_close(); - if(CLI.settings.scroll_close_reload === true) - { - window.location.reload(); - } - window.removeEventListener("scroll",CLI.closeOnScroll,false); - } - }, - displayHeader:function() - { - if(this.settings.notify_animate_show) - { - this.bar_elm.slideDown(this.settings.animate_speed_show); - }else - { - this.bar_elm.show(); - } - this.showagain_elm.hide(); - if(CLI_COOKIEBAR_AS_POPUP) - { - this.showPopupOverlay(); - } - }, - hideHeader:function() - { - if(this.settings.showagain_tab) - { - if(this.settings.notify_animate_show) - { - this.showagain_elm.slideDown(this.settings.animate_speed_show); - } else { - this.showagain_elm.show(); - } - }else - { - this.showagain_elm.hide(); - } - this.bar_elm.slideUp(this.settings.animate_speed_show); - this.hidePopupOverlay(); - }, - hidePopupOverlay:function() - { - jQuery('body').removeClass("cli-barmodal-open"); - jQuery(".cli-popupbar-overlay").removeClass("cli-show"); - }, - showPopupOverlay:function() - { - if(this.settings.popup_overlay) - { - jQuery('body').addClass("cli-barmodal-open"); - jQuery(".cli-popupbar-overlay").addClass("cli-show"); - } - }, - barAsWidget:function(a) - { - var cli_elm=this.bar_elm; - var cli_win=jQuery(window); - var cli_winh=cli_win.height()-40; - var cli_winw=cli_win.width(); - var cli_defw=cli_winw>400 ? 300 : cli_winw-30; - cli_elm.css({ - 'width':cli_defw,'height':'auto','max-height':cli_winh,'padding':'25px 15px','overflow':'auto','position':'fixed','box-sizing':'border-box' - }); - if(this.settings.widget_position=='left') - { - cli_elm.css({ - 'left':'15px','right':'auto','bottom':'15px','top':'auto' - }); - }else - { - cli_elm.css({ - 'left':'auto','right':'15px','bottom':'15px','top':'auto' - }); - } - if(a) - { - this.setResize(); - } - }, - barAsPopUp:function(a) - { - if(typeof cookie_law_info_bar_as_popup==='function') - { - return false; - } - var cli_elm=this.bar_elm; - var cli_win=jQuery(window); - var cli_winh=cli_win.height()-40; - var cli_winw=cli_win.width(); - var cli_defw=cli_winw>700 ? 500 : cli_winw-20; - - cli_elm.css({ - 'width':cli_defw,'height':'auto','max-height':cli_winh,'bottom':'','top':'50%','left':'50%','margin-left':(cli_defw/2)*-1,'margin-top':'-100px','padding':'25px 15px','overflow':'auto' - }).addClass('cli-bar-popup cli-modal-content'); - - - cli_h=cli_elm.height(); - li_h=cli_h<200 ? 200 : cli_h; - cli_elm.css({'top':'50%','margin-top':((cli_h/2)+30)*-1}); - setTimeout(function(){ - cli_elm.css({ - 'bottom':'' - }); - },100); - if(a) - { - this.setResize(); - } - }, - setResize:function() - { - var resizeTmr=null; - jQuery(window).resize(function() { - clearTimeout(resizeTmr); - resizeTmr=setTimeout(function() - { - if(CLI_COOKIEBAR_AS_POPUP) - { - CLI.barAsPopUp(); - } - if(CLI.settings.cookie_bar_as=='widget') - { - CLI.barAsWidget(); - } - CLI.configShowAgain(); - },500); - }); - } -} -jQuery(document).ready(function() { - if(typeof cli_cookiebar_settings!='undefined') - { - CLI.set({ - settings:cli_cookiebar_settings - }); - } -}); +CLI_ACCEPT_COOKIE_NAME =(typeof CLI_ACCEPT_COOKIE_NAME !== 'undefined' ? CLI_ACCEPT_COOKIE_NAME : 'viewed_cookie_policy'); +CLI_ACCEPT_COOKIE_EXPIRE =(typeof CLI_ACCEPT_COOKIE_EXPIRE !== 'undefined' ? CLI_ACCEPT_COOKIE_EXPIRE : 365); +CLI_COOKIEBAR_AS_POPUP=(typeof CLI_COOKIEBAR_AS_POPUP !== 'undefined' ? CLI_COOKIEBAR_AS_POPUP : false); +var CLI_Cookie={ + set: function (name, value, days) { + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + var expires = "; expires=" + date.toGMTString(); + } else + var expires = ""; + document.cookie = name + "=" + value + expires + "; path=/"; + if(days<1) + { + host_name=window.location.hostname; + document.cookie = name + "=" + value + expires + "; path=/; domain=."+host_name+";"; + if(host_name.indexOf("www")!=1) + { + var host_name_withoutwww=host_name.replace('www',''); + document.cookie = name + "=" + value + expires + "; path=/; domain="+host_name_withoutwww+";"; + } + host_name=host_name.substring(host_name.lastIndexOf(".", host_name.lastIndexOf(".")-1)); + document.cookie = name + "=" + value + expires + "; path=/; domain="+host_name+";"; + } + }, + read: function (name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) === 0) { + return c.substring(nameEQ.length, c.length); + } + } + return null; + }, + erase: function (name) { + this.set(name, "", -10); + }, + exists: function (name) { + return (this.read(name) !== null); + }, + getallcookies:function() + { + var pairs = document.cookie.split(";"); + var cookieslist = {}; + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i].split("="); + cookieslist[(pair[0] + '').trim()] = unescape(pair[1]); + } + return cookieslist; + } +} +var CLI= +{ + bar_config:{}, + showagain_config:{}, + set:function(args) + { + if(typeof JSON.parse !== "function") + { + console.log("CookieLawInfo requires JSON.parse but your browser doesn't support it"); + return; + } + this.settings = JSON.parse(args.settings); + this.bar_elm=jQuery(this.settings.notify_div_id); + this.showagain_elm = jQuery(this.settings.showagain_div_id); + + /* buttons */ + this.main_button=jQuery('.cli-plugin-main-button'); + this.main_link = jQuery('.cli-plugin-main-link'); + this.reject_link = jQuery('.cookie_action_close_header_reject'); + this.delete_link=jQuery(".cookielawinfo-cookie-delete"); + + if(this.settings.cookie_bar_as=='popup') + { + CLI_COOKIEBAR_AS_POPUP=true; + } + this.configBar(); + this.toggleBar(); + this.attachDelete(); + this.attachEvents(); + this.configButtons(); + var cli_hidebar_on_readmore=this.hideBarInReadMoreLink(); + if(this.settings.scroll_close===true && cli_hidebar_on_readmore===false) + { + window.addEventListener("scroll",CLI.closeOnScroll, false); + } + }, + hideBarInReadMoreLink:function() + { + if(CLI.settings.button_2_hidebar===true && this.main_link.length>0 && this.main_link.hasClass('cli-minimize-bar')) + { + this.hideHeader(); + this.showagain_elm.slideDown(this.settings.animate_speed_show); + return true; + } + return false; + }, + attachEvents:function() + { + jQuery('.cli_action_button').click(function(e){ + e.preventDefault(); + var elm=jQuery(this); + var button_action=elm.attr('data-cli_action'); + var open_link=elm[0].hasAttribute("href") && elm.attr("href") != '#' ? true : false; + var new_window=false; + if(button_action=='accept') + { + CLI.accept_close(); + new_window=CLI.settings.button_1_new_win ? true : false; + }else if(button_action=='reject') + { + CLI.reject_close(); + new_window=CLI.settings.button_3_new_win ? true : false; + } + if(open_link) + { + if(new_window) + { + window.open(elm.attr("href"),'_blank'); + }else + { + window.location.href =elm.attr("href"); + } + } + }); + }, + attachDelete:function() + { + this.delete_link.click(function () { + CLI_Cookie.erase(CLI_ACCEPT_COOKIE_NAME); + for(var k in Cli_Data.nn_cookie_ids) + { + CLI_Cookie.erase(Cli_Data.nn_cookie_ids[k]); + } + return false; + }); + }, + configButtons:function() + { + /*[cookie_button] */ + this.main_button.css('color',this.settings.button_1_link_colour); + if(this.settings.button_1_as_button) + { + this.main_button.css('background-color',this.settings.button_1_button_colour); + this.main_button.hover(function () { + jQuery(this).css('background-color',CLI.settings.button_1_button_hover); + },function (){ + jQuery(this).css('background-color',CLI.settings.button_1_button_colour); + }); + } + + /* [cookie_link] */ + this.main_link.css('color',this.settings.button_2_link_colour); + if(this.settings.button_2_as_button) + { + this.main_link.css('background-color',this.settings.button_2_button_colour); + this.main_link.hover(function () { + jQuery(this).css('background-color',CLI.settings.button_2_button_hover); + },function (){ + jQuery(this).css('background-color',CLI.settings.button_2_button_colour); + }); + } + + + /* [cookie_reject] */ + this.reject_link.css('color',this.settings.button_3_link_colour); + if(this.settings.button_3_as_button) + { + this.reject_link.css('background-color',this.settings.button_3_button_colour); + this.reject_link.hover(function () { + jQuery(this).css('background-color',CLI.settings.button_3_button_hover); + },function () { + jQuery(this).css('background-color',CLI.settings.button_3_button_colour); + }); + } + }, + toggleBar:function() + { + if(CLI_COOKIEBAR_AS_POPUP) + { + this.barAsPopUp(1); + } + if(CLI.settings.cookie_bar_as=='widget') + { + this.barAsWidget(1); + } + if(!CLI_Cookie.exists(CLI_ACCEPT_COOKIE_NAME)) + { + this.displayHeader(); + }else + { + this.hideHeader(); + } + if(this.settings.show_once_yn) + { + setTimeout(function(){ + CLI.close_header(); + },CLI.settings.show_once); + } + + this.showagain_elm.click(function (e) { + e.preventDefault(); + CLI.showagain_elm.slideUp(CLI.settings.animate_speed_hide,function() + { + CLI.bar_elm.slideDown(CLI.settings.animate_speed_show); + if(CLI_COOKIEBAR_AS_POPUP) + { + CLI.showPopupOverlay(); + } + }); + }); + }, + configShowAgain:function() + { + this.showagain_config = { + 'background-color': this.settings.background, + 'color':this.l1hs(this.settings.text), + 'position': 'fixed', + 'font-family': this.settings.font_family + }; + if(this.settings.border_on) + { + var border_to_hide = 'border-' + this.settings.notify_position_vertical; + this.showagain_config['border'] = '1px solid ' + this.l1hs(this.settings.border); + this.showagain_config[border_to_hide] = 'none'; + } + var cli_win=jQuery(window); + var cli_winw=cli_win.width(); + var showagain_x_pos=this.settings.showagain_x_position; + if(cli_winw<300) + { + showagain_x_pos=10; + this.showagain_config.width=cli_winw-20; + }else + { + this.showagain_config.width='auto'; + } + var cli_defw=cli_winw>400 ? 500 : cli_winw-20; + if(CLI_COOKIEBAR_AS_POPUP) /* cookie bar as popup */ + { + var sa_pos=this.settings.popup_showagain_position; + var sa_pos_arr=sa_pos.split('-'); + if(sa_pos_arr[1]=='left') + { + this.showagain_config.left=showagain_x_pos; + }else if(sa_pos_arr[1]=='right') + { + this.showagain_config.right=showagain_x_pos; + } + if(sa_pos_arr[0]=='top') + { + this.showagain_config.top=0; + + }else if(sa_pos_arr[0]=='bottom') + { + this.showagain_config.bottom=0; + } + this.bar_config['position'] = 'fixed'; + + }else if(this.settings.cookie_bar_as=='widget') + { + this.showagain_config.bottom=0; + if(this.settings.widget_position=='left') + { + this.showagain_config.left=showagain_x_pos; + }else if(this.settings.widget_position=='right') + { + this.showagain_config.right=showagain_x_pos; + } + } + else + { + if(this.settings.notify_position_vertical == "top") + { + this.showagain_config.top = '0'; + } + else if(this.settings.notify_position_vertical == "bottom") + { + this.bar_config['position'] = 'fixed'; + this.bar_config['bottom'] = '0'; + this.showagain_config.bottom = '0'; + } + if(this.settings.notify_position_horizontal == "left") + { + this.showagain_config.left =showagain_x_pos; + }else if(this.settings.notify_position_horizontal == "right") + { + this.showagain_config.right =showagain_x_pos; + } + } + this.showagain_elm.css(this.showagain_config); + }, + configBar:function() + { + this.bar_config = { + 'background-color':this.settings.background, + 'color':this.settings.text, + 'font-family':this.settings.font_family + }; + if(this.settings.notify_position_vertical=="top") + { + this.bar_config['top'] = '0'; + if(this.settings.header_fix === true) + { + this.bar_config['position'] = 'fixed'; + } + }else + { + this.bar_config['bottom'] = '0'; + } + this.configShowAgain(); + this.bar_elm.css(this.bar_config).hide(); + }, + l1hs:function(str) + { + if (str.charAt(0) == "#") { + str = str.substring(1, str.length); + } else { + return "#" + str; + } + return this.l1hs(str); + }, + close_header:function() + { + CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'yes',CLI_ACCEPT_COOKIE_EXPIRE); + this.hideHeader(); + }, + accept_close:function() + { + this.hidePopupOverlay(); + CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'yes',CLI_ACCEPT_COOKIE_EXPIRE); + if(this.settings.notify_animate_hide) + { + this.bar_elm.slideUp(this.settings.animate_speed_hide); + }else + { + this.bar_elm.hide(); + } + if(this.settings.showagain_tab) + { + this.showagain_elm.slideDown(this.settings.animate_speed_show); + } + if(this.settings.accept_close_reload === true) + { + this.reload_current_page(); + } + return false; + }, + reject_close:function() + { + this.hidePopupOverlay(); + for(var k in Cli_Data.nn_cookie_ids) + { + CLI_Cookie.erase(Cli_Data.nn_cookie_ids[k]); + } + CLI_Cookie.set(CLI_ACCEPT_COOKIE_NAME,'no',CLI_ACCEPT_COOKIE_EXPIRE); + if(this.settings.notify_animate_hide) + { + this.bar_elm.slideUp(this.settings.animate_speed_hide); + } else + { + this.bar_elm.hide(); + } + if(this.settings.showagain_tab) + { + this.showagain_elm.slideDown(this.settings.animate_speed_show); + } + if(this.settings.reject_close_reload === true) + { + this.reload_current_page(); + } + return false; + }, + reload_current_page:function() + { + if(typeof cli_flush_cache!=='undefined' && cli_flush_cache==1) + { + window.location.href=this.add_clear_cache_url_query(); + }else + { + window.location.reload(true); + } + }, + add_clear_cache_url_query:function() + { + var cli_rand=new Date().getTime()/1000; + var cli_url=window.location.href; + var cli_hash_arr=cli_url.split('#'); + var cli_urlparts= cli_hash_arr[0].split('?'); + if(cli_urlparts.length>=2) + { + var cli_url_arr=cli_urlparts[1].split('&'); + cli_url_temp_arr=new Array(); + for(var cli_i=0; cli_i0 ? '&': '')+'cli_action='; + }else + { + cli_url=cli_hash_arr[0]+'?cli_action='; + } + cli_url+=cli_rand; + if(cli_hash_arr.length>1) + { + cli_url+='#'+cli_hash_arr[1]; + } + return cli_url; + }, + closeOnScroll:function() + { + if(window.pageYOffset > 100 && !CLI_Cookie.read(CLI_ACCEPT_COOKIE_NAME)) + { + CLI.accept_close(); + if(CLI.settings.scroll_close_reload === true) + { + window.location.reload(); + } + window.removeEventListener("scroll",CLI.closeOnScroll,false); + } + }, + displayHeader:function() + { + if(this.settings.notify_animate_show) + { + this.bar_elm.slideDown(this.settings.animate_speed_show); + }else + { + this.bar_elm.show(); + } + this.showagain_elm.hide(); + if(CLI_COOKIEBAR_AS_POPUP) + { + this.showPopupOverlay(); + } + }, + hideHeader:function() + { + if(this.settings.showagain_tab) + { + if(this.settings.notify_animate_show) + { + this.showagain_elm.slideDown(this.settings.animate_speed_show); + } else { + this.showagain_elm.show(); + } + }else + { + this.showagain_elm.hide(); + } + this.bar_elm.slideUp(this.settings.animate_speed_show); + this.hidePopupOverlay(); + }, + hidePopupOverlay:function() + { + jQuery('body').removeClass("cli-barmodal-open"); + jQuery(".cli-popupbar-overlay").removeClass("cli-show"); + }, + showPopupOverlay:function() + { + if(this.settings.popup_overlay) + { + jQuery('body').addClass("cli-barmodal-open"); + jQuery(".cli-popupbar-overlay").addClass("cli-show"); + } + }, + barAsWidget:function(a) + { + var cli_elm=this.bar_elm; + var cli_win=jQuery(window); + var cli_winh=cli_win.height()-40; + var cli_winw=cli_win.width(); + var cli_defw=cli_winw>400 ? 300 : cli_winw-30; + cli_elm.css({ + 'width':cli_defw,'height':'auto','max-height':cli_winh,'padding':'25px 15px','overflow':'auto','position':'fixed','box-sizing':'border-box' + }); + if(this.settings.widget_position=='left') + { + cli_elm.css({ + 'left':'15px','right':'auto','bottom':'15px','top':'auto' + }); + }else + { + cli_elm.css({ + 'left':'auto','right':'15px','bottom':'15px','top':'auto' + }); + } + if(a) + { + this.setResize(); + } + }, + barAsPopUp:function(a) + { + if(typeof cookie_law_info_bar_as_popup==='function') + { + return false; + } + var cli_elm=this.bar_elm; + var cli_win=jQuery(window); + var cli_winh=cli_win.height()-40; + var cli_winw=cli_win.width(); + var cli_defw=cli_winw>700 ? 500 : cli_winw-20; + + cli_elm.css({ + 'width':cli_defw,'height':'auto','max-height':cli_winh,'bottom':'','top':'50%','left':'50%','margin-left':(cli_defw/2)*-1,'margin-top':'-100px','padding':'25px 15px','overflow':'auto' + }).addClass('cli-bar-popup cli-modal-content'); + + + cli_h=cli_elm.height(); + li_h=cli_h<200 ? 200 : cli_h; + cli_elm.css({'top':'50%','margin-top':((cli_h/2)+30)*-1}); + setTimeout(function(){ + cli_elm.css({ + 'bottom':'' + }); + },100); + if(a) + { + this.setResize(); + } + }, + setResize:function() + { + var resizeTmr=null; + jQuery(window).resize(function() { + clearTimeout(resizeTmr); + resizeTmr=setTimeout(function() + { + if(CLI_COOKIEBAR_AS_POPUP) + { + CLI.barAsPopUp(); + } + if(CLI.settings.cookie_bar_as=='widget') + { + CLI.barAsWidget(); + } + CLI.configShowAgain(); + },500); + }); + } +} +jQuery(document).ready(function() { + if(typeof cli_cookiebar_settings!='undefined') + { + CLI.set({ + settings:cli_cookiebar_settings + }); + } +}); diff --git a/geonode/templates/robots.txt b/geonode/templates/robots.txt index 54648d3bcc6..494081df2d1 100644 --- a/geonode/templates/robots.txt +++ b/geonode/templates/robots.txt @@ -1,6 +1,6 @@ -User-agent: * - -Disallow: /cgi-bin/ -Disallow: /api/ -Disallow: /static/ -Disallow: /uploaded/ +User-agent: * + +Disallow: /cgi-bin/ +Disallow: /api/ +Disallow: /static/ +Disallow: /uploaded/ diff --git a/geonode/tests/data/kml/Thuenen_BD_BT1_NewCategory.kml b/geonode/tests/data/kml/Thuenen_BD_BT1_NewCategory.kml index a2881478edf..e80fa5987db 100644 --- a/geonode/tests/data/kml/Thuenen_BD_BT1_NewCategory.kml +++ b/geonode/tests/data/kml/Thuenen_BD_BT1_NewCategory.kml @@ -1,20 +1,20 @@ - - - - Thuenen-BD - - 1 - relativeToGround - - - - 10.442495,52.284308,100 - 10.443053,52.284299,100 - 10.443049,52.284166,100 - 10.442490,52.284180,100 - - - - - + + + + Thuenen-BD + + 1 + relativeToGround + + + + 10.442495,52.284308,100 + 10.443053,52.284299,100 + 10.443049,52.284166,100 + 10.442490,52.284180,100 + + + + + \ No newline at end of file diff --git a/geonode/tests/data/kml/Thuenen_BD_BT1_NoCategory.kml b/geonode/tests/data/kml/Thuenen_BD_BT1_NoCategory.kml index a2881478edf..e80fa5987db 100644 --- a/geonode/tests/data/kml/Thuenen_BD_BT1_NoCategory.kml +++ b/geonode/tests/data/kml/Thuenen_BD_BT1_NoCategory.kml @@ -1,20 +1,20 @@ - - - - Thuenen-BD - - 1 - relativeToGround - - - - 10.442495,52.284308,100 - 10.443053,52.284299,100 - 10.443049,52.284166,100 - 10.442490,52.284180,100 - - - - - + + + + Thuenen-BD + + 1 + relativeToGround + + + + 10.442495,52.284308,100 + 10.443053,52.284299,100 + 10.443049,52.284166,100 + 10.442490,52.284180,100 + + + + + \ No newline at end of file diff --git a/geonode/tests/data/kml/Thuenen_BD_BT1_planningCadastre.kml b/geonode/tests/data/kml/Thuenen_BD_BT1_planningCadastre.kml index a2881478edf..e80fa5987db 100644 --- a/geonode/tests/data/kml/Thuenen_BD_BT1_planningCadastre.kml +++ b/geonode/tests/data/kml/Thuenen_BD_BT1_planningCadastre.kml @@ -1,20 +1,20 @@ - - - - Thuenen-BD - - 1 - relativeToGround - - - - 10.442495,52.284308,100 - 10.443053,52.284299,100 - 10.443049,52.284166,100 - 10.442490,52.284180,100 - - - - - + + + + Thuenen-BD + + 1 + relativeToGround + + + + 10.442495,52.284308,100 + 10.443053,52.284299,100 + 10.443049,52.284166,100 + 10.442490,52.284180,100 + + + + + \ No newline at end of file diff --git a/geonode/tests/data/kml/Thuenen_BD_BT1_structure.kml b/geonode/tests/data/kml/Thuenen_BD_BT1_structure.kml index a2881478edf..e80fa5987db 100644 --- a/geonode/tests/data/kml/Thuenen_BD_BT1_structure.kml +++ b/geonode/tests/data/kml/Thuenen_BD_BT1_structure.kml @@ -1,20 +1,20 @@ - - - - Thuenen-BD - - 1 - relativeToGround - - - - 10.442495,52.284308,100 - 10.443053,52.284299,100 - 10.443049,52.284166,100 - 10.442490,52.284180,100 - - - - - + + + + Thuenen-BD + + 1 + relativeToGround + + + + 10.442495,52.284308,100 + 10.443053,52.284299,100 + 10.443049,52.284166,100 + 10.442490,52.284180,100 + + + + + \ No newline at end of file diff --git a/geonode/themes/admin.py b/geonode/themes/admin.py index 4801afde299..4e3cc553828 100644 --- a/geonode/themes/admin.py +++ b/geonode/themes/admin.py @@ -1,82 +1,82 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from django import forms -from django.contrib import admin - -from .models import GeoNodeThemeCustomization, JumbotronThemeSlide - - -class GeonodeThemCustomizationForm(forms.ModelForm): - class Meta: - model = GeoNodeThemeCustomization - widgets = { - "body_color": forms.TextInput(attrs={"type": "color"}), - "body_text_color": forms.TextInput(attrs={"type": "color"}), - "navbar_color": forms.TextInput(attrs={"type": "color"}), - "navbar_text_color": forms.TextInput(attrs={"type": "color"}), - "navbar_text_hover": forms.TextInput(attrs={"type": "color"}), - "navbar_text_hover_focus": forms.TextInput(attrs={"type": "color"}), - "navbar_dropdown_menu": forms.TextInput(attrs={"type": "color"}), - "navbar_dropdown_menu_text": forms.TextInput(attrs={"type": "color"}), - "navbar_dropdown_menu_hover": forms.TextInput(attrs={"type": "color"}), - "navbar_dropdown_menu_divider": forms.TextInput(attrs={"type": "color"}), - "jumbotron_color": forms.TextInput(attrs={"type": "color"}), - "jumbotron_title_color": forms.TextInput(attrs={"type": "color"}), - "jumbotron_text_color": forms.TextInput(attrs={"type": "color"}), - "search_bg_color": forms.TextInput(attrs={"type": "color"}), - "search_title_color": forms.TextInput(attrs={"type": "color"}), - "search_link_color": forms.TextInput(attrs={"type": "color"}), - "copyright_color": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_background": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_border": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_1_button_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_1_button_hover": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_1_link_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_2_button_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_2_button_hover": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_2_link_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_3_button_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_3_button_hover": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_3_link_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_4_button_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_4_button_hover": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_button_4_link_colour": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_showagain_background": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_showagain_border": forms.TextInput(attrs={"type": "color"}), - "cookie_law_info_text": forms.TextInput(attrs={"type": "color"}), - "footer_bg_color": forms.TextInput(attrs={"type": "color"}), - "footer_text_color": forms.TextInput(attrs={"type": "color"}), - "footer_href_color": forms.TextInput(attrs={"type": "color"}), - } - fields = "__all__" - - -@admin.register(GeoNodeThemeCustomization) -class GeoNodeThemeCustomizationAdmin(admin.ModelAdmin): - form = GeonodeThemCustomizationForm - list_display = ("id", "is_enabled", "name", "date", "description") - list_display_links = ( - "id", - "name", - ) - - -@admin.register(JumbotronThemeSlide) -class JumbotronThemeSlideAdmin(admin.ModelAdmin): - pass +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from django import forms +from django.contrib import admin + +from .models import GeoNodeThemeCustomization, JumbotronThemeSlide + + +class GeonodeThemCustomizationForm(forms.ModelForm): + class Meta: + model = GeoNodeThemeCustomization + widgets = { + "body_color": forms.TextInput(attrs={"type": "color"}), + "body_text_color": forms.TextInput(attrs={"type": "color"}), + "navbar_color": forms.TextInput(attrs={"type": "color"}), + "navbar_text_color": forms.TextInput(attrs={"type": "color"}), + "navbar_text_hover": forms.TextInput(attrs={"type": "color"}), + "navbar_text_hover_focus": forms.TextInput(attrs={"type": "color"}), + "navbar_dropdown_menu": forms.TextInput(attrs={"type": "color"}), + "navbar_dropdown_menu_text": forms.TextInput(attrs={"type": "color"}), + "navbar_dropdown_menu_hover": forms.TextInput(attrs={"type": "color"}), + "navbar_dropdown_menu_divider": forms.TextInput(attrs={"type": "color"}), + "jumbotron_color": forms.TextInput(attrs={"type": "color"}), + "jumbotron_title_color": forms.TextInput(attrs={"type": "color"}), + "jumbotron_text_color": forms.TextInput(attrs={"type": "color"}), + "search_bg_color": forms.TextInput(attrs={"type": "color"}), + "search_title_color": forms.TextInput(attrs={"type": "color"}), + "search_link_color": forms.TextInput(attrs={"type": "color"}), + "copyright_color": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_background": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_border": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_1_button_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_1_button_hover": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_1_link_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_2_button_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_2_button_hover": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_2_link_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_3_button_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_3_button_hover": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_3_link_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_4_button_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_4_button_hover": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_button_4_link_colour": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_showagain_background": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_showagain_border": forms.TextInput(attrs={"type": "color"}), + "cookie_law_info_text": forms.TextInput(attrs={"type": "color"}), + "footer_bg_color": forms.TextInput(attrs={"type": "color"}), + "footer_text_color": forms.TextInput(attrs={"type": "color"}), + "footer_href_color": forms.TextInput(attrs={"type": "color"}), + } + fields = "__all__" + + +@admin.register(GeoNodeThemeCustomization) +class GeoNodeThemeCustomizationAdmin(admin.ModelAdmin): + form = GeonodeThemCustomizationForm + list_display = ("id", "is_enabled", "name", "date", "description") + list_display_links = ( + "id", + "name", + ) + + +@admin.register(JumbotronThemeSlide) +class JumbotronThemeSlideAdmin(admin.ModelAdmin): + pass diff --git a/geonode/themes/apps.py b/geonode/themes/apps.py index b5cce53ac19..ea627dee90f 100644 --- a/geonode/themes/apps.py +++ b/geonode/themes/apps.py @@ -1,26 +1,26 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from django.apps import AppConfig as BaseAppConfig -from django.utils.translation import gettext_lazy as _ - - -class AppConfig(BaseAppConfig): - name = "geonode.themes" - label = "geonode_themes" - verbose_name = _("GeoNode Themes Library") +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from django.apps import AppConfig as BaseAppConfig +from django.utils.translation import gettext_lazy as _ + + +class AppConfig(BaseAppConfig): + name = "geonode.themes" + label = "geonode_themes" + verbose_name = _("GeoNode Themes Library") diff --git a/geonode/themes/context_processors.py b/geonode/themes/context_processors.py index ae345fdd19a..1dd0370c059 100644 --- a/geonode/themes/context_processors.py +++ b/geonode/themes/context_processors.py @@ -1,39 +1,39 @@ -######################################################################### -# -# Copyright (C) 2018 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 . -# -######################################################################### -from django.core.cache import cache - -from .models import GeoNodeThemeCustomization, THEME_CACHE_KEY - - -def custom_theme(request): - theme = cache.get(THEME_CACHE_KEY) - if theme is None: - try: - theme = GeoNodeThemeCustomization.objects.get(is_enabled=True) - slides = theme.jumbotron_slide_show.filter(is_enabled=True) - except Exception: - theme = {} - slides = [] - cache.set(THEME_CACHE_KEY, theme) - else: - try: - slides = theme.jumbotron_slide_show.filter(is_enabled=True) - except Exception: - slides = [] - return {"custom_theme": theme, "slides": slides} +######################################################################### +# +# Copyright (C) 2018 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 . +# +######################################################################### +from django.core.cache import cache + +from .models import GeoNodeThemeCustomization, THEME_CACHE_KEY + + +def custom_theme(request): + theme = cache.get(THEME_CACHE_KEY) + if theme is None: + try: + theme = GeoNodeThemeCustomization.objects.get(is_enabled=True) + slides = theme.jumbotron_slide_show.filter(is_enabled=True) + except Exception: + theme = {} + slides = [] + cache.set(THEME_CACHE_KEY, theme) + else: + try: + slides = theme.jumbotron_slide_show.filter(is_enabled=True) + except Exception: + slides = [] + return {"custom_theme": theme, "slides": slides} diff --git a/geonode/upload/handlers/remote/cog.py b/geonode/upload/handlers/remote/cog.py index 75e958b80f4..b77637e6f59 100644 --- a/geonode/upload/handlers/remote/cog.py +++ b/geonode/upload/handlers/remote/cog.py @@ -1,175 +1,175 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### -import logging -import requests -from osgeo import gdal - -from geonode.layers.models import Dataset -from geonode.upload.handlers.common.remote import BaseRemoteResourceHandler -from geonode.upload.handlers.common.serializer import RemoteResourceSerializer -from geonode.upload.api.exceptions import ImportException -from geonode.upload.orchestrator import orchestrator - -logger = logging.getLogger("importer") - - -class RemoteCOGResourceHandler(BaseRemoteResourceHandler): - - @property - def supported_file_extension_config(self): - return {} - - @staticmethod - def has_serializer(data) -> bool: - if "url" in data and "cog" in data.get("type", "").lower(): - return RemoteResourceSerializer - return False - - @staticmethod - def can_handle(_data) -> bool: - """ - This endpoint will return True or False if with the info provided - the handler is able to handle the file or not - """ - if "url" in _data and "cog" in _data.get("type", "").lower(): - return True - return False - - @staticmethod - def is_valid_url(url, **kwargs): - """ - Check if the URL is reachable and supports HTTP Range requests - """ - logger.debug(f"Checking COG URL validity (HEAD): {url}") - try: - # Reachability check using HEAD - head_res = requests.head(url, timeout=10, allow_redirects=True) - logger.debug(f"HTTP HEAD status: {head_res.status_code}") - head_res.raise_for_status() - - accept_ranges = head_res.headers.get("Accept-Ranges", "").lower() - - # Check for range request support - if accept_ranges == "bytes": - logger.debug("Server explicitly supports Accept-Ranges: bytes") - return True - - # Some servers might not return Accept-Ranges in HEAD, so we try a small range request - logger.debug("Accept-Ranges header missing, trying a small Range GET...") - range_res = requests.get(url, headers={"Range": "bytes=0-1"}, timeout=10, stream=True) - logger.debug(f"Range GET status: {range_res.status_code}") - try: - if range_res.status_code != 206: - raise ImportException( - "The remote server does not support HTTP Range requests, which are required for COG." - ) - finally: - range_res.close() - except Exception as e: - logger.debug(f"is_valid_url ERROR: {str(e)}") - logger.exception(e) - if isinstance(e, ImportException): - raise e - raise ImportException("Error checking COG URL") - - return True - - def create_geonode_resource( - self, - layer_name: str, - alternate: str, - execution_id: str, - resource_type: Dataset = Dataset, - asset=None, - ): - """ - Base function to create the resource into geonode. - """ - logger.debug(f"Entering create_geonode_resource for {layer_name}") - _exec = orchestrator.get_execution_object(execution_id) - params = _exec.input_params.copy() - url = params.get("url") - - # Extract metadata via GDAL VSICURL - gdal.UseExceptions() - logger.debug(f"Attempting to open COG with GDAL: /vsicurl/{url}") - try: - # Set GDAL config options for faster failure - gdal.SetThreadLocalConfigOption("GDAL_HTTP_TIMEOUT", "15") - gdal.SetThreadLocalConfigOption("GDAL_HTTP_MAX_RETRY", "1") - - vsiurl = f"/vsicurl/{url}" - ds = gdal.OpenEx(vsiurl) - if ds is None: - logger.debug(f"GDAL failed to open dataset: {vsiurl}") - raise ImportException(f"Could not open remote COG: {url}") - - if not ds.GetSpatialRef(): - raise ImportException(f"Could not extract spatial reference from COG: {url}") - - srid = self.identify_authority(ds) - - # Get BBox - gt = ds.GetGeoTransform() - width = ds.RasterXSize - height = ds.RasterYSize - - # Check for rotation - is_rotated = gt[2] != 0 or gt[4] != 0 - - if is_rotated: - logger.info("COG has rotation/skew - calculating envelope bbox") - # Calculate all four corners - corners = [ - (gt[0], gt[3]), - (gt[0] + width * gt[1], gt[3] + width * gt[4]), - (gt[0] + width * gt[1] + height * gt[2], gt[3] + width * gt[4] + height * gt[5]), - (gt[0] + height * gt[2], gt[3] + height * gt[5]), - ] - xs = [x for x, y in corners] - ys = [y for x, y in corners] - bbox = [min(xs), min(ys), max(xs), max(ys)] - else: - # Simple calculation for north-up images - minx = gt[0] - maxy = gt[3] - maxx = gt[0] + width * gt[1] - miny = gt[3] + height * gt[5] - bbox = [minx, miny, maxx, maxy] - - ds = None # close dataset - logger.debug("GDAL operations finished.") - except Exception as e: - logger.debug(f"GDAL ERROR: {str(e)}") - logger.exception(e) - if isinstance(e, ImportException): - raise e - raise ImportException(f"Failed to extract metadata from COG: {url}") - resource = super().create_geonode_resource(layer_name, alternate, execution_id, resource_type, asset) - resource.set_bbox_polygon(bbox, srid) - return resource - - def generate_resource_payload(self, layer_name, alternate, asset, _exec, workspace, **kwargs): - payload = super().generate_resource_payload(layer_name, alternate, asset, _exec, workspace, **kwargs) - payload.update( - { - "name": alternate, - } - ) - return payload +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### +import logging +import requests +from osgeo import gdal + +from geonode.layers.models import Dataset +from geonode.upload.handlers.common.remote import BaseRemoteResourceHandler +from geonode.upload.handlers.common.serializer import RemoteResourceSerializer +from geonode.upload.api.exceptions import ImportException +from geonode.upload.orchestrator import orchestrator + +logger = logging.getLogger("importer") + + +class RemoteCOGResourceHandler(BaseRemoteResourceHandler): + + @property + def supported_file_extension_config(self): + return {} + + @staticmethod + def has_serializer(data) -> bool: + if "url" in data and "cog" in data.get("type", "").lower(): + return RemoteResourceSerializer + return False + + @staticmethod + def can_handle(_data) -> bool: + """ + This endpoint will return True or False if with the info provided + the handler is able to handle the file or not + """ + if "url" in _data and "cog" in _data.get("type", "").lower(): + return True + return False + + @staticmethod + def is_valid_url(url, **kwargs): + """ + Check if the URL is reachable and supports HTTP Range requests + """ + logger.debug(f"Checking COG URL validity (HEAD): {url}") + try: + # Reachability check using HEAD + head_res = requests.head(url, timeout=10, allow_redirects=True) + logger.debug(f"HTTP HEAD status: {head_res.status_code}") + head_res.raise_for_status() + + accept_ranges = head_res.headers.get("Accept-Ranges", "").lower() + + # Check for range request support + if accept_ranges == "bytes": + logger.debug("Server explicitly supports Accept-Ranges: bytes") + return True + + # Some servers might not return Accept-Ranges in HEAD, so we try a small range request + logger.debug("Accept-Ranges header missing, trying a small Range GET...") + range_res = requests.get(url, headers={"Range": "bytes=0-1"}, timeout=10, stream=True) + logger.debug(f"Range GET status: {range_res.status_code}") + try: + if range_res.status_code != 206: + raise ImportException( + "The remote server does not support HTTP Range requests, which are required for COG." + ) + finally: + range_res.close() + except Exception as e: + logger.debug(f"is_valid_url ERROR: {str(e)}") + logger.exception(e) + if isinstance(e, ImportException): + raise e + raise ImportException("Error checking COG URL") + + return True + + def create_geonode_resource( + self, + layer_name: str, + alternate: str, + execution_id: str, + resource_type: Dataset = Dataset, + asset=None, + ): + """ + Base function to create the resource into geonode. + """ + logger.debug(f"Entering create_geonode_resource for {layer_name}") + _exec = orchestrator.get_execution_object(execution_id) + params = _exec.input_params.copy() + url = params.get("url") + + # Extract metadata via GDAL VSICURL + gdal.UseExceptions() + logger.debug(f"Attempting to open COG with GDAL: /vsicurl/{url}") + try: + # Set GDAL config options for faster failure + gdal.SetThreadLocalConfigOption("GDAL_HTTP_TIMEOUT", "15") + gdal.SetThreadLocalConfigOption("GDAL_HTTP_MAX_RETRY", "1") + + vsiurl = f"/vsicurl/{url}" + ds = gdal.OpenEx(vsiurl) + if ds is None: + logger.debug(f"GDAL failed to open dataset: {vsiurl}") + raise ImportException(f"Could not open remote COG: {url}") + + if not ds.GetSpatialRef(): + raise ImportException(f"Could not extract spatial reference from COG: {url}") + + srid = self.identify_authority(ds) + + # Get BBox + gt = ds.GetGeoTransform() + width = ds.RasterXSize + height = ds.RasterYSize + + # Check for rotation + is_rotated = gt[2] != 0 or gt[4] != 0 + + if is_rotated: + logger.info("COG has rotation/skew - calculating envelope bbox") + # Calculate all four corners + corners = [ + (gt[0], gt[3]), + (gt[0] + width * gt[1], gt[3] + width * gt[4]), + (gt[0] + width * gt[1] + height * gt[2], gt[3] + width * gt[4] + height * gt[5]), + (gt[0] + height * gt[2], gt[3] + height * gt[5]), + ] + xs = [x for x, y in corners] + ys = [y for x, y in corners] + bbox = [min(xs), min(ys), max(xs), max(ys)] + else: + # Simple calculation for north-up images + minx = gt[0] + maxy = gt[3] + maxx = gt[0] + width * gt[1] + miny = gt[3] + height * gt[5] + bbox = [minx, miny, maxx, maxy] + + ds = None # close dataset + logger.debug("GDAL operations finished.") + except Exception as e: + logger.debug(f"GDAL ERROR: {str(e)}") + logger.exception(e) + if isinstance(e, ImportException): + raise e + raise ImportException(f"Failed to extract metadata from COG: {url}") + resource = super().create_geonode_resource(layer_name, alternate, execution_id, resource_type, asset) + resource.set_bbox_polygon(bbox, srid) + return resource + + def generate_resource_payload(self, layer_name, alternate, asset, _exec, workspace, **kwargs): + payload = super().generate_resource_payload(layer_name, alternate, asset, _exec, workspace, **kwargs) + payload.update( + { + "name": alternate, + } + ) + return payload diff --git a/geonode/upload/handlers/remote/tests/test_cog.py b/geonode/upload/handlers/remote/tests/test_cog.py index 87f8b086561..2b2236c2c71 100644 --- a/geonode/upload/handlers/remote/tests/test_cog.py +++ b/geonode/upload/handlers/remote/tests/test_cog.py @@ -1,108 +1,108 @@ -######################################################################### -# -# Copyright (C) 2026 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 . -# -######################################################################### -from django.test import TestCase -from mock import MagicMock, patch -from geonode.upload.api.exceptions import ImportException -from django.contrib.auth import get_user_model -from geonode.upload.handlers.remote.cog import RemoteCOGResourceHandler -from geonode.upload.orchestrator import orchestrator -from geonode.layers.models import Dataset -from geonode.base.models import Link - - -class TestRemoteCOGResourceHandler(TestCase): - databases = ("default", "datastore") - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.handler = RemoteCOGResourceHandler() - cls.valid_url = "http://example.com/test.tif" - cls.user, _ = get_user_model().objects.get_or_create(username="admin") - cls.valid_payload = { - "url": cls.valid_url, - "type": "cog", - "title": "COG Test", - } - cls.owner = cls.user - - def test_can_handle_cog(self): - self.assertTrue(self.handler.can_handle(self.valid_payload)) - self.assertTrue(self.handler.can_handle({"url": "http://example.com/y.tiff", "type": "cog"})) - self.assertFalse(self.handler.can_handle({"url": "http://example.com/y.jpg", "type": "image"})) - - @patch("geonode.upload.handlers.remote.cog.requests.head") - @patch("geonode.upload.handlers.remote.cog.requests.get") - @patch("geonode.upload.handlers.common.remote.requests.get") - def test_is_valid_url_success(self, mock_base_get, mock_get, mock_head): - mock_head.return_value.headers = {"Accept-Ranges": "bytes"} - mock_head.return_value.status_code = 200 - mock_base_get.return_value.status_code = 200 - - self.assertTrue(self.handler.is_valid_url(self.valid_url)) - - @patch("geonode.upload.handlers.remote.cog.requests.head") - @patch("geonode.upload.handlers.remote.cog.requests.get") - @patch("geonode.upload.handlers.common.remote.requests.get") - def test_is_valid_url_no_range_support(self, mock_base_get, mock_get, mock_head): - mock_head.return_value.headers = {} - mock_get.return_value.status_code = 404 # Not 206 - mock_base_get.return_value.status_code = 200 - - with self.assertRaises(ImportException): - self.handler.is_valid_url(self.valid_url) - - @patch("geonode.upload.handlers.remote.cog.gdal.OpenEx") - def test_create_geonode_resource(self, mock_gdal_openex): - # Mock GDAL dataset - mock_ds = MagicMock() - mock_srs = MagicMock() - mock_srs.GetAuthorityName.return_value = "EPSG" - mock_srs.GetAuthorityCode.return_value = "4326" - mock_ds.GetSpatialRef.return_value = mock_srs - mock_ds.GetGeoTransform.return_value = [0, 1, 0, 0, 0, -1] - mock_ds.RasterXSize = 100 - mock_ds.RasterYSize = 100 - mock_gdal_openex.return_value = mock_ds - - exec_id = orchestrator.create_execution_request( - user=self.owner, - func_name="funct1", - step="step", - input_params=self.valid_payload, - ) - - resource = self.handler.create_geonode_resource( - "test_cog", - "test_cog_alternate", - execution_id=str(exec_id), - resource_type=Dataset, - ) - - self.assertIsNotNone(resource) - self.assertEqual(resource.subtype, "cog") - self.assertEqual(resource.alternate, "test_cog_alternate") - self.assertEqual(resource.srid, "EPSG:4326") - self.assertIsNotNone(resource.bbox_polygon) - - # Verify Link creation (where URL is stored) - link = Link.objects.get(resource=resource, link_type="data") - self.assertEqual(link.url, self.valid_url) - self.assertEqual(link.extension, "cog") - self.assertEqual(link.name, resource.alternate) +######################################################################### +# +# Copyright (C) 2026 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 . +# +######################################################################### +from django.test import TestCase +from mock import MagicMock, patch +from geonode.upload.api.exceptions import ImportException +from django.contrib.auth import get_user_model +from geonode.upload.handlers.remote.cog import RemoteCOGResourceHandler +from geonode.upload.orchestrator import orchestrator +from geonode.layers.models import Dataset +from geonode.base.models import Link + + +class TestRemoteCOGResourceHandler(TestCase): + databases = ("default", "datastore") + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.handler = RemoteCOGResourceHandler() + cls.valid_url = "http://example.com/test.tif" + cls.user, _ = get_user_model().objects.get_or_create(username="admin") + cls.valid_payload = { + "url": cls.valid_url, + "type": "cog", + "title": "COG Test", + } + cls.owner = cls.user + + def test_can_handle_cog(self): + self.assertTrue(self.handler.can_handle(self.valid_payload)) + self.assertTrue(self.handler.can_handle({"url": "http://example.com/y.tiff", "type": "cog"})) + self.assertFalse(self.handler.can_handle({"url": "http://example.com/y.jpg", "type": "image"})) + + @patch("geonode.upload.handlers.remote.cog.requests.head") + @patch("geonode.upload.handlers.remote.cog.requests.get") + @patch("geonode.upload.handlers.common.remote.requests.get") + def test_is_valid_url_success(self, mock_base_get, mock_get, mock_head): + mock_head.return_value.headers = {"Accept-Ranges": "bytes"} + mock_head.return_value.status_code = 200 + mock_base_get.return_value.status_code = 200 + + self.assertTrue(self.handler.is_valid_url(self.valid_url)) + + @patch("geonode.upload.handlers.remote.cog.requests.head") + @patch("geonode.upload.handlers.remote.cog.requests.get") + @patch("geonode.upload.handlers.common.remote.requests.get") + def test_is_valid_url_no_range_support(self, mock_base_get, mock_get, mock_head): + mock_head.return_value.headers = {} + mock_get.return_value.status_code = 404 # Not 206 + mock_base_get.return_value.status_code = 200 + + with self.assertRaises(ImportException): + self.handler.is_valid_url(self.valid_url) + + @patch("geonode.upload.handlers.remote.cog.gdal.OpenEx") + def test_create_geonode_resource(self, mock_gdal_openex): + # Mock GDAL dataset + mock_ds = MagicMock() + mock_srs = MagicMock() + mock_srs.GetAuthorityName.return_value = "EPSG" + mock_srs.GetAuthorityCode.return_value = "4326" + mock_ds.GetSpatialRef.return_value = mock_srs + mock_ds.GetGeoTransform.return_value = [0, 1, 0, 0, 0, -1] + mock_ds.RasterXSize = 100 + mock_ds.RasterYSize = 100 + mock_gdal_openex.return_value = mock_ds + + exec_id = orchestrator.create_execution_request( + user=self.owner, + func_name="funct1", + step="step", + input_params=self.valid_payload, + ) + + resource = self.handler.create_geonode_resource( + "test_cog", + "test_cog_alternate", + execution_id=str(exec_id), + resource_type=Dataset, + ) + + self.assertIsNotNone(resource) + self.assertEqual(resource.subtype, "cog") + self.assertEqual(resource.alternate, "test_cog_alternate") + self.assertEqual(resource.srid, "EPSG:4326") + self.assertIsNotNone(resource.bbox_polygon) + + # Verify Link creation (where URL is stored) + link = Link.objects.get(resource=resource, link_type="data") + self.assertEqual(link.url, self.valid_url) + self.assertEqual(link.extension, "cog") + self.assertEqual(link.name, resource.alternate) diff --git a/geonode/upload/tests/data/arc_sample/precip30min.prj b/geonode/upload/tests/data/arc_sample/precip30min.prj index 2051f9e4e1a..41844c0a090 100644 --- a/geonode/upload/tests/data/arc_sample/precip30min.prj +++ b/geonode/upload/tests/data/arc_sample/precip30min.prj @@ -1,9 +1,9 @@ - GEOGCS["WGS 84", - DATUM["World Geodetic System 1984", - SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], - AUTHORITY["EPSG","6326"]], - PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], - UNIT["degree", 0.017453292519943295], - AXIS["Geodetic longitude", EAST], - AXIS["Geodetic latitude", NORTH], + GEOGCS["WGS 84", + DATUM["World Geodetic System 1984", + SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], + AUTHORITY["EPSG","6326"]], + PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], + UNIT["degree", 0.017453292519943295], + AXIS["Geodetic longitude", EAST], + AXIS["Geodetic latitude", NORTH], AUTHORITY["EPSG","4326"]] \ No newline at end of file diff --git a/geonode/upload/tests/fixture/invalid.geojson b/geonode/upload/tests/fixture/invalid.geojson index c59aecd3f39..c9ceda2656a 100644 --- a/geonode/upload/tests/fixture/invalid.geojson +++ b/geonode/upload/tests/fixture/invalid.geojson @@ -1,11 +1,11 @@ -invalid={ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": { - "name": "Dinagat Islands" - } - } - ] +invalid={ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Dinagat Islands" + } + } + ] } \ No newline at end of file diff --git a/geonode/upload/tests/fixture/valid.csv b/geonode/upload/tests/fixture/valid.csv index e3eb9e98d48..44366e97c93 100644 --- a/geonode/upload/tests/fixture/valid.csv +++ b/geonode/upload/tests/fixture/valid.csv @@ -1,4 +1,4 @@ -id;name;amount;city;geom -1;Kevin;2.1;Rapperswil;POINT(8.8249 47.2274) -2;Eva;2.2;Zürich;POINT(8.5435 47.3768) +id;name;amount;city;geom +1;Kevin;2.1;Rapperswil;POINT(8.8249 47.2274) +2;Eva;2.2;Zürich;POINT(8.5435 47.3768) 3;"Jimmy;Muff";2.3;;POINT(7.4397 46.9487) \ No newline at end of file diff --git a/geonode/upload/tests/fixture/valid.geojson b/geonode/upload/tests/fixture/valid.geojson index cd4d6ea302f..6fec1ee32d7 100644 --- a/geonode/upload/tests/fixture/valid.geojson +++ b/geonode/upload/tests/fixture/valid.geojson @@ -1,18 +1,18 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "Point", - "coordinates": [ - 11.93115234375, - 42.147114459220994 - ] - }, - "properties": { - "name": "Dinagat Islands" - } - } - ] +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 11.93115234375, + 42.147114459220994 + ] + }, + "properties": { + "name": "Dinagat Islands" + } + } + ] } \ No newline at end of file diff --git a/geonode/upload/tests/fixture/wrong_data.csv b/geonode/upload/tests/fixture/wrong_data.csv index 967a1f66be8..0a215ede2cf 100644 --- a/geonode/upload/tests/fixture/wrong_data.csv +++ b/geonode/upload/tests/fixture/wrong_data.csv @@ -1 +1 @@ -id,name,latitude,longitude,description +id,name,latitude,longitude,description diff --git a/setup_external_datastore.sh b/setup_external_datastore.sh new file mode 100644 index 00000000000..dd50c921f05 --- /dev/null +++ b/setup_external_datastore.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# ============================================================ +# setup_external_datastore.sh +# +# Configura o GeoServer para conectar ao banco externo db_geo_prd +# Executa APOS o docker compose estar rodando e o GeoServer healthy +# +# Uso: bash setup_external_datastore.sh +# +# As credenciais sao lidas de variaveis de ambiente ou do arquivo +# .env_external (nao versionado). Veja .env_external.sample +# ============================================================ + +set -e + +# Carregar credenciais do arquivo .env_external se existir +if [ -f ".env_external" ]; then + set -a + source .env_external + set +a +fi + +GEOSERVER_URL="${GEOSERVER_URL:-http://localhost:8080/geoserver}" +GS_USER="${GS_USER:-admin}" +GS_PASS="${GS_PASS:-geoserver}" + +# Dados do banco externo +DB_HOST="${EXT_DB_HOST:?Variavel EXT_DB_HOST nao definida. Crie .env_external a partir de .env_external.sample}" +DB_PORT="${EXT_DB_PORT:-5432}" +DB_NAME="${EXT_DB_NAME:?Variavel EXT_DB_NAME nao definida}" +DB_SCHEMA="${EXT_DB_SCHEMA:-public}" +DB_USER="${EXT_DB_USER:?Variavel EXT_DB_USER nao definida}" +DB_PASS="${EXT_DB_PASS:?Variavel EXT_DB_PASS nao definida}" + +WORKSPACE="${GS_WORKSPACE:-geonode}" +DATASTORE_NAME="${GS_DATASTORE_NAME:-${DB_NAME}}" + +echo "============================================" +echo " Configurando datastore externo no GeoServer" +echo "============================================" + +# 1. Verificar se o GeoServer esta acessivel +echo "[1/3] Verificando GeoServer..." +until curl -sf "${GEOSERVER_URL}/web/" > /dev/null 2>&1; do + echo " Aguardando GeoServer ficar disponivel..." + sleep 5 +done +echo " GeoServer acessivel em ${GEOSERVER_URL}" + +# 2. Verificar se o workspace 'geonode' existe (criado automaticamente pelo GeoNode) +echo "[2/3] Verificando workspace '${WORKSPACE}'..." +WS_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -u "${GS_USER}:${GS_PASS}" \ + "${GEOSERVER_URL}/rest/workspaces/${WORKSPACE}.json") + +if [ "$WS_STATUS" != "200" ]; then + echo " Workspace '${WORKSPACE}' nao encontrado. Criando..." + curl -s -u "${GS_USER}:${GS_PASS}" \ + -XPOST "${GEOSERVER_URL}/rest/workspaces" \ + -H "Content-Type: application/json" \ + -d "{\"workspace\":{\"name\":\"${WORKSPACE}\"}}" + echo " Workspace criado." +else + echo " Workspace '${WORKSPACE}' ja existe." +fi + +# 3. Criar datastore apontando para o banco externo +echo "[3/3] Criando datastore '${DATASTORE_NAME}'..." +DS_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -u "${GS_USER}:${GS_PASS}" \ + "${GEOSERVER_URL}/rest/workspaces/${WORKSPACE}/datastores/${DATASTORE_NAME}.json") + +if [ "$DS_STATUS" == "200" ]; then + echo " Datastore '${DATASTORE_NAME}' ja existe. Pulando criacao." +else + curl -s -u "${GS_USER}:${GS_PASS}" \ + -XPOST "${GEOSERVER_URL}/rest/workspaces/${WORKSPACE}/datastores" \ + -H "Content-Type: application/json" \ + -d "{ + \"dataStore\": { + \"name\": \"${DATASTORE_NAME}\", + \"type\": \"PostGIS\", + \"enabled\": true, + \"connectionParameters\": { + \"entry\": [ + {\"@key\": \"host\", \"\$\": \"${DB_HOST}\"}, + {\"@key\": \"port\", \"\$\": \"${DB_PORT}\"}, + {\"@key\": \"database\", \"\$\": \"${DB_NAME}\"}, + {\"@key\": \"schema\", \"\$\": \"${DB_SCHEMA}\"}, + {\"@key\": \"user\", \"\$\": \"${DB_USER}\"}, + {\"@key\": \"passwd\", \"\$\": \"${DB_PASS}\"}, + {\"@key\": \"dbtype\", \"\$\": \"postgis\"}, + {\"@key\": \"Expose primary keys\", \"\$\": \"true\"}, + {\"@key\": \"validate connections\", \"\$\": \"true\"}, + {\"@key\": \"max connections\", \"\$\": \"10\"}, + {\"@key\": \"min connections\", \"\$\": \"1\"} + ] + } + } + }" + echo "" + echo " Datastore '${DATASTORE_NAME}' criado com sucesso!" +fi + +echo "" +echo "============================================" +echo " Configuracao concluida!" +echo "" +echo " GeoServer: ${GEOSERVER_URL}/web/" +echo " Login: ${GS_USER} / ${GS_PASS}" +echo "" +echo " Datastore: ${DATASTORE_NAME}" +echo " Host: ${DB_HOST}:${DB_PORT}" +echo " Database: ${DB_NAME}" +echo " Schema: ${DB_SCHEMA}" +echo "" +echo " Proximo passo:" +echo " 1. Acesse ${GEOSERVER_URL}/web/" +echo " 2. Va em Layers > Add a new layer" +echo " 3. Selecione '${WORKSPACE}:${DATASTORE_NAME}'" +echo " 4. Publique as tabelas desejadas do db_geo_prd" +echo " 5. As camadas publicadas aparecerao no GeoNode" +echo "============================================" diff --git a/start_local.sh b/start_local.sh new file mode 100644 index 00000000000..cf771c00838 --- /dev/null +++ b/start_local.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# ============================================================ +# start_local.sh +# +# Script de inicializacao do ambiente local GeoNode +# Sobe toda a stack e configura o datastore externo +# +# Uso: bash start_local.sh +# ============================================================ + +set -e + +echo "============================================" +echo " Iniciando stack GeoNode local" +echo "============================================" +echo "" + +# 1. Subir a stack com docker compose +echo "[1/2] Subindo containers..." +docker compose -f docker-compose-local.yml up -d --build + +echo "" +echo " Aguardando servicos ficarem healthy..." +echo " (isso pode levar alguns minutos na primeira vez)" +echo "" + +# Aguardar GeoServer ficar pronto +echo " Aguardando GeoServer..." +until curl -sf "http://localhost:8080/geoserver/web/" > /dev/null 2>&1; do + sleep 10 + echo " ..." +done +echo " GeoServer: OK" + +# Aguardar GeoNode/Nginx ficar pronto +echo " Aguardando GeoNode..." +until curl -sf "http://localhost/" > /dev/null 2>&1; do + sleep 10 + echo " ..." +done +echo " GeoNode: OK" + +# 2. Configurar datastore externo +echo "" +echo "[2/2] Configurando datastore externo (db_geo_prd)..." +bash setup_external_datastore.sh + +echo "" +echo "============================================" +echo " Ambiente pronto!" +echo "" +echo " GeoNode: http://localhost/" +echo " Admin: admin / admin" +echo "" +echo " GeoServer: http://localhost/geoserver/web/" +echo " Login: via OAuth2 (loga pelo GeoNode)" +echo "" +echo " DB local: localhost:5434" +echo " User: postgres / postgres" +echo "" +echo " DB externo: 172.20.30.31:5432" +echo " Database: db_geo_prd (schema: geonode)" +echo "" +echo " Sync automatico: a cada 120s (Celery Beat)" +echo " Ajustar: GEOSERVER_SYNC_INTERVAL no .env" +echo "" +echo " Docs: ver SETUP_REFERENCE.txt" +echo "============================================" diff --git a/status.sh b/status.sh new file mode 100644 index 00000000000..d9d4ff03897 --- /dev/null +++ b/status.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# ============================================================ +# status.sh - Verifica o estado de todos os servicos GeoNode +# Uso: bash status.sh +# ============================================================ + +echo "============================================" +echo " Status do ambiente GeoNode" +echo " $(date)" +echo "============================================" +echo "" + +echo "[Containers]" +docker ps --format " {{.Names}}\t{{.Status}}" --filter "label=com.docker.compose.project=geonode" 2>/dev/null || echo " Docker nao esta rodando" +echo "" + +echo "[Conectividade]" +# GeoNode +if curl -sf "http://localhost/" > /dev/null 2>&1; then + echo " GeoNode (http://localhost/) OK" +else + echo " GeoNode (http://localhost/) FALHA" +fi + +# GeoServer +if curl -sf "http://localhost:8080/geoserver/ows" > /dev/null 2>&1; then + echo " GeoServer (:8080/geoserver/ows) OK" +else + echo " GeoServer (:8080/geoserver/ows) FALHA" +fi + +# DB local +if docker exec db4geonode pg_isready -U postgres > /dev/null 2>&1; then + echo " DB local (db4geonode) OK" +else + echo " DB local (db4geonode) FALHA" +fi + +echo "" +echo "[Datastore externo]" +DS=$(docker exec geoserver4geonode curl -s -o /dev/null -w "%{http_code}" \ + -u "admin:geoserver" \ + "http://localhost:8080/geoserver/rest/workspaces/geonode/datastores/db_geo_prd.json" 2>/dev/null) +if [ "$DS" == "200" ]; then + echo " db_geo_prd no GeoServer OK" + LAYERS=$(docker exec geoserver4geonode curl -s -u "admin:geoserver" \ + "http://localhost:8080/geoserver/rest/workspaces/geonode/datastores/db_geo_prd/featuretypes.json" 2>/dev/null \ + | python3 -c "import sys,json; d=json.load(sys.stdin); ft=d.get('featureTypes',{}).get('featureType',[]); print(f' Camadas publicadas: {len(ft)}')" 2>/dev/null) + echo "$LAYERS" +else + echo " db_geo_prd no GeoServer NAO CONFIGURADO" +fi + +echo "" +echo "[Celery Beat]" +BEAT=$(docker exec celery4geonode python3 -c " +from geonode.settings import CELERY_BEAT_SCHEDULE +s = CELERY_BEAT_SCHEDULE.get('sync-geoserver-layers', {}) +print(f\" Task: {s.get('task','N/A')}\") +print(f\" Intervalo: {s.get('schedule','N/A')}s\") +print(f\" Store: {s.get('kwargs',{}).get('store','N/A')}\") +" 2>/dev/null) +if [ -n "$BEAT" ]; then + echo "$BEAT" +else + echo " Celery Beat nao esta acessivel" +fi + +echo "" +echo "============================================"