| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| .. _worldmap: | ||
|
|
||
| ======== | ||
| WorldMap | ||
| ======== | ||
|
|
||
| By using the WorldMap optional application, GeoNode is extended with the following additional features: | ||
|
|
||
| * a customized GeoExplorer viewer | ||
| * the table of contents is hierarchical with layer categories. When a layer is added a new category containing the layer is added to the table of contents. If the category is already in the table of contents, then the layer is added to it. By default the category is the same as the layer's topic category, but that can be renamed by right clicking on it | ||
| * the "Add Layers" dialog comes with a "Search" tab which uses Hypermap Registry (Hypermap) as a catalogue of remote and local layers. Hypermap is a requirement when using the WorldMap contrib application | ||
| * a gazetteer application: it is possible to add a given layer to a gazetteer. The gazetteer can be checked using the map client. When a layer is part of the gazetter it is possible to include it in a general gazetteer or in a specific project one. It is possible to search place names in the gazetteer by date range, in which case it is necessary to specify the layer attributes for the start and end depict dates | ||
|
|
||
| Installation | ||
| ============ | ||
|
|
||
| Requirements | ||
| ------------ | ||
|
|
||
| We are assuming a Ubuntu 16.04.1 LTS development environment, but these instructions can be adapted to any recent Linux distributions:: | ||
|
|
||
| # Install Ubuntu dependencies | ||
| sudo apt-get update | ||
| sudo apt-get install python-virtualenv python-dev libxml2 libxml2-dev libxslt1-dev zlib1g-dev libjpeg-dev libpq-dev libgdal-dev git default-jdk postgresql postgis | ||
|
|
||
| # Install Java 8 (needed by latest GeoServer 2.13) | ||
| sudo apt-add-repository ppa:webupd8team/java | ||
| sudo apt-get update | ||
| sudo apt-get install oracle-java8-installer | ||
|
|
||
| Virtual environment creation and installation of Python packages | ||
| ---------------------------------------------------------------- | ||
|
|
||
| Create and activate the virtual environment:: | ||
|
|
||
| cd ~ | ||
| virtualenv --no-site-packages env | ||
| . env/bin/activate | ||
|
|
||
| Now install GeoNode from source code:: | ||
|
|
||
| git clone -b https://github.com/geonode/geonode.git | ||
| cd geonode | ||
| pip install -r requirements.txt | ||
| pip install pygdal==1.11.3.3 | ||
| pip install -e . | ||
| paver setup | ||
| paver sync | ||
|
|
||
| Set the following environment variables as needed (change SITE_NAME and SERVER_IP s needed. Also HYPERMAP_REGISTRY_URL and SOLR_URL may be different). Even better, create a file and source it:: | ||
|
|
||
| export USE_WORLDMAP=True | ||
| export SITE_NAME=worldmap | ||
| export SERVER_IP=128.31.22.73 | ||
| export PG_USERNAME=worldmap | ||
| export PG_PASSWORD=worldmap | ||
| export PG_WORLDMAP_DJANGO_DB=worldmap | ||
| export PG_WORLDMAP_UPLOADS_DB=wmdata | ||
| export OWNER=$PG_USERNAME | ||
| export ALLOWED_HOSTS="localhost, $SERVER_IP, " | ||
| export GEOSERVER_LOCATION=http://localhost:8080/geoserver/ | ||
| export GEOSERVER_PUBLIC_LOCATION=http://$SERVER_IP/geoserver/ | ||
| export SOLR_URL =http://localhost:8983/solr/hypermap/select/ | ||
| export HYPERMAP_REGISTRY_URL =http://localhost:8001 | ||
| export MAPPROXY_URL=http://localhost:8001 | ||
|
|
||
|
|
||
| You can install GeoNode WorldMap in two different ways: | ||
|
|
||
| 1) By installing GeoNode itself | ||
| 2) By using the recommended way of a geonode-project | ||
|
|
||
| GeoNode/WorldMap without a geonode-project | ||
| ------------------------------------------ | ||
|
|
||
| Copy the included local_settings.py file and customize it to your needs:: | ||
|
|
||
| cp local_settings.py.worldmap.sample local_settings.py | ||
|
|
||
| GeoNode/WorldMap with a geonode-project | ||
| --------------------------------------- | ||
|
|
||
| You will use a geonode-project in order to separate the customization of your instance from GeoNode. | ||
|
|
||
| Create your geonode project by using the WorldMap geonode-project as a template (https://github.com/cga-harvard/geonode-project). Rename it to something meaningful (for example your web site name):: | ||
|
|
||
| cd ~ | ||
| django-admin startproject $SITE_NAME --template=https://github.com/cga-harvard/geonode-project/archive/master.zip -epy,rst | ||
| cd $SITE_NAME | ||
|
|
||
| Create a local_settings.py by copying the included template:: | ||
|
|
||
| cp $SITE_NAME/local_settings.py.sample $SITE_NAME/local_settings.py | ||
| make build | ||
| paver setup | ||
|
|
||
| Start the Server | ||
| ---------------- | ||
|
|
||
| Start GeoNode with Worldmap using pavement:: | ||
|
|
||
| python manage.py runserver 0.0.0.0:8000 | ||
| paver start_geoserver | ||
|
|
||
| To upload layers you can login with the default GeoNode administrative account: | ||
|
|
||
| user: admin | ||
| password: admin | ||
|
|
||
| Configuring instance for production | ||
| ----------------------------------- | ||
|
|
||
| Please follow best practices suggested by GeoNode documentation: | ||
|
|
||
| http://docs.geonode.org/en/master/tutorials/advanced/geonode_production/ | ||
|
|
||
| Remember to add the ip of your server in ALLOWED_HOSTS in the local_settings.py file:: | ||
|
|
||
| ALLOWED_HOSTS = ['localhost', '128.31.22.73', ] | ||
|
|
||
| Hypermap Registry | ||
| ================= | ||
|
|
||
| GeoNode with the WorldMap contribute module requires a Hypermap Registry (Hypermap) running instance. | ||
|
|
||
| You can install Hypermap by following these instructions (use the "Manual Installation" section): https://github.com/cga-harvard/HHypermap/blob/master/_docs/developers.md | ||
|
|
||
| Note that you can bypass Java 8 installation as it was installed previously. As a search engine you should install Solr, as we haven't tested Elasticsearch with WorldMap so far. Create a specific virtual environment for Hypermap in order not to interfere with the GeoNode/WorldMap virtual environment. | ||
|
|
||
| After installing Hypermap, start it on a different port than 8000, for example:: | ||
|
|
||
| python manage.py runserver 0.0.0.0:8001 | ||
|
|
||
| In another shell start the Celery process as well:: | ||
|
|
||
| cd HHypermap | ||
| celery -A hypermap worker --beat --scheduler django -l info | ||
|
|
||
| Test the stack | ||
| ============== | ||
|
|
||
| Now that GeoNode/WorldMap and Hypermap are both running, test the stack by uploading a layer. | ||
|
|
||
| Login in GeoNode (admin/admin) and upload a shapefile from this page: http://localhost:8000/layers/upload | ||
|
|
||
| Make sure the shapefile is correctly displayed in GeoNode by going to the layer page. | ||
|
|
||
| Now login in Hypermap (admin/admin) and go to the admin services page: http://localhost:8001/admin/aggregator/service/ Add a service like this: | ||
|
|
||
| * Title: My GeoNode WorldMap SDI | ||
| * Url: http://localhost:8000/ | ||
| * Type: GeoNode WorldMap | ||
|
|
||
| Go to the Hypermap service page and check it the service and the layer is there: | ||
| http://localhost:8001/registry/ | ||
|
|
||
| In order to have layers in the search engine (Solr) there are two options: | ||
|
|
||
| 1) from task runner press the "Index cached layers" button | ||
| 2) schedule a task in celery | ||
|
|
||
| We recommend the second option, which can be configured in the next section. | ||
|
|
||
| Schedule Celery tasks | ||
| ===================== | ||
|
|
||
| Go to the Periodic Task administrative interface: http://localhost:8001/admin/django_celery_beat/periodictask/ | ||
|
|
||
| Create the following two tasks: | ||
|
|
||
| Index Cached Layer Task | ||
| ----------------------- | ||
|
|
||
| This task will sync the layers from the cache to the search engine. Layers are sent in the cache every time they are saved: | ||
|
|
||
| * Name: Index Cached Layer | ||
| * Task (registered): hypermap.aggregator.tasks.index_cached_layers | ||
| * Interval: every 1 minute (or as needed) | ||
|
|
||
| Check Worldmap Service | ||
| ---------------------- | ||
|
|
||
| This task will do a check of all of WorldMap service: | ||
|
|
||
| * Name: Check WorldMap Service | ||
| * Task (registered): hypermap.aggregator.tasks.check_service | ||
| * Interval: every 1 minute (or as needed) | ||
| * Arguments: [1] # 1 is the id of the service. Change it as is needed | ||
|
|
||
| Now upload a new layer in GeoNode/WorldMap and check if it appears in Hypermap and in Solr (you may need to wait for the tasks to be executed) | ||
|
|
||
| Update Last GeoNode WorldMap Layers | ||
| ----------------------------------- | ||
|
|
||
| If your GeoNode/WorldMap instance has many layers, it is preferable to runt the check_service not so often, as it can be time consuming, and rather use the update_last_wm_layers. | ||
|
|
||
| As a first thing, change the interval for the check_service task you created for GeoNode/WorldMap to a value such as "one day" or "one week". | ||
|
|
||
| Then create the following periodic task: | ||
|
|
||
| * Name: Sync last layers in WorldMap Service | ||
| * Task (registered): hypermap.aggregator.update_last_wm_layers | ||
| * Interval: every 1 minute | ||
| * Arguments: [1] # 1 is the id of the service. Change it as is needed |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,8 @@ | |
|
|
||
| import os | ||
|
|
||
| __version__ = (2, 7, 7, 'unstable', 0) | ||
|
|
||
|
|
||
| default_app_config = "geonode.apps.AppConfig" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # -*- coding: utf-8 -*- | ||
| ######################################################################### | ||
| # | ||
| # 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 <http://www.gnu.org/licenses/>. | ||
| # | ||
| ######################################################################### | ||
|
|
||
| from django.core.management.base import BaseCommand | ||
| from geonode.layers.models import Layer | ||
| from geonode.catalogue.models import catalogue_post_save | ||
|
|
||
|
|
||
| class Command(BaseCommand): | ||
| """Resets Permissions to Public for All Layers | ||
| """ | ||
|
|
||
| def handle(self, *args, **options): | ||
| all_layers = Layer.objects.all() | ||
|
|
||
| for index, layer in enumerate(all_layers): | ||
| print "[%s / %s] Updating Layer [%s] ..." % ((index + 1), len(all_layers), layer.name) | ||
| try: | ||
| catalogue_post_save(instance=layer, sender=layer.__class__) | ||
| except: | ||
| # import traceback | ||
| # traceback.print_exc() | ||
| print "[ERROR] Layer [%s] couldn't be updated" % (layer.name) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| {% include "geoext/ext_header.html" %} | ||
| {% include "geoext/app_header.html" %} | ||
| {% include "geoext/geo_header.html" %} | ||
| <link href="{{ STATIC_URL}}geonode/css/geoexplorer/map_geoexplorer.css" rel="stylesheet"/> | ||
| <script type="text/javascript" src="{{ STATIC_URL}}geonode/js/extjs/GeoNode-mixin.js"></script> | ||
| <script type="text/javascript" src="{{ STATIC_URL}}geonode/js/extjs/Geonode-CatalogueApiSearch.js"></script> | ||
| <script type="text/javascript" src="{{ STATIC_URL}}geonode/js/extjs/GeoNode-GeoExplorer.js"></script> | ||
| <script type="text/javascript"> | ||
| var app; | ||
| Ext.onReady(function() { | ||
| {% autoescape off %} | ||
| GeoExt.Lang.set("{{ LANGUAGE_CODE }}"); | ||
| var config = Ext.apply({ | ||
| authStatus: {% if user.is_authenticated %} 200{% else %} 401{% endif %}, | ||
| {% if PROXY_URL %} | ||
| proxy: '{{ PROXY_URL }}', | ||
| {% endif %} | ||
|
|
||
| {% if 'access_token' in request.session %} | ||
| access_token: "{{request.session.access_token}}", | ||
| {% else %} | ||
| access_token: null, | ||
| {% endif %} | ||
|
|
||
| {% if MAPFISH_PRINT_ENABLED %} | ||
| printService: "{{ GEOSERVER_BASE_URL }}pdf/", | ||
| {% else %} | ||
| printService: null, | ||
| printCapabilities: null, | ||
| {% endif %} | ||
|
|
||
| useCapabilities: false, | ||
| useToolbar: true, | ||
|
|
||
| /* The URL to a REST map configuration service. This service | ||
| * provides listing and, with an authenticated user, saving of | ||
| * maps on the server for sharing and editing. | ||
| */ | ||
| rest: "{% url "maps_browse" %}", | ||
| ajaxLoginUrl: "{% url "account_ajax_login" %}", | ||
| homeUrl: "{% url "home" %}", | ||
| localGeoServerBaseUrl: "{{ GEOSERVER_BASE_URL }}", | ||
| localCSWBaseUrl: "{{ CATALOGUE_BASE_URL }}", | ||
| csrfToken: "{{ csrf_token }}", | ||
| tools: [{ptype: "gxp_getfeedfeatureinfo"}], | ||
| listeners: { | ||
| "ready": function() { | ||
| app.mapPanel.map.getResolutions = function() { | ||
| return [156543.03390625, 78271.516953125, 39135.7584765625, | ||
| 19567.87923828125, 9783.939619140625, 4891.9698095703125, | ||
| 2445.9849047851562, 1222.9924523925781, 611.4962261962891, | ||
| 305.74811309814453, 152.87405654907226, 76.43702827453613, | ||
| 38.218514137268066, 19.109257068634033, 9.554628534317017, | ||
| 4.777314267158508, 2.388657133579254, 1.194328566789627, | ||
| 0.5971642833948135, 0.25, 0.1, 0.05]; | ||
| } | ||
| app.mapPanel.map.getServerResolutions = function() { | ||
| return [156543.03390625, 78271.516953125, 39135.7584765625, | ||
| 19567.87923828125, 9783.939619140625, | ||
| 4891.9698095703125, 2445.9849047851562, | ||
| 1222.9924523925781, 611.4962261962891, | ||
| 305.74811309814453, 152.87405654907226, | ||
| 76.43702827453613, 38.218514137268066, | ||
| 19.109257068634033, 9.554628534317017, | ||
| 4.777314267158508, 2.388657133579254, | ||
| 1.194328566789627, 0.5971642833948135]; | ||
| } | ||
| app.mapPanel.map.getMaxResolution = function() { | ||
| return 156543.0339 * 2; | ||
| } | ||
| app.mapPanel.map.getNumZoomLevels = function() { | ||
| return 28; | ||
| } | ||
| app.mapPanel.map.getMinZoom = function() { | ||
| return 0; | ||
| } | ||
| app.mapPanel.map.getMaxZoom = function() { | ||
| return 28; | ||
| } | ||
| app.mapPanel.map.getResolutionForZoom = function(zoom) { | ||
| zoom = Math.max(0, Math.min(zoom, this.getResolutions().length - 1)); | ||
| var resolution; | ||
| var fractionalZoom = true; | ||
| if(fractionalZoom) { | ||
| var low = Math.floor(zoom); | ||
| var high = Math.ceil(zoom); | ||
| resolution = this.getResolutions()[low] - | ||
| ((zoom-low) * (this.getResolutions()[low]-this.getResolutions()[high])); | ||
| } else { | ||
| resolution = this.getResolutions()[Math.round(zoom)]; | ||
| } | ||
| return resolution; | ||
| } | ||
| app.mapPanel.map.adjustZoom = function(zoom) { | ||
| var maxResolution = 156543.0339 * 4; | ||
| if (this.baseLayer && this.baseLayer.wrapDateLine) { | ||
| var resolution, resolutions = this.getResolutions(), | ||
| // maxResolution = this.getMaxExtent().getWidth() / this.size.w; | ||
| maxResolution = this.getMaxResolution(); | ||
| if (this.getResolutionForZoom(zoom) > maxResolution) { | ||
| var fractionalZoom = true; | ||
| if (fractionalZoom) { | ||
| zoom = this.getZoomForResolution(maxResolution); | ||
| } else { | ||
| for (var i=zoom|0, ii=resolutions.length; i<ii; ++i) { | ||
| if (resolutions[i] <= maxResolution) { | ||
| zoom = i; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return zoom; | ||
| } | ||
|
|
||
| try { | ||
| l = app.selectedLayer.getLayer(); | ||
| l.addOptions({wrapDateLine:true, displayOutsideMaxExtent: true}); | ||
| l.addOptions({maxExtent:app.mapPanel.map.getMaxExtent()}); | ||
| } catch(err) { | ||
| ; | ||
| } | ||
|
|
||
| {% if 'access_token' in request.session %} | ||
| try { | ||
| if(l.url != undefined && (typeof l.url) == "string") { | ||
| l.url += ( !l.url.match(/\b\?/gi) || l.url.match(/\b\?/gi).length == 0 ? '?' : '&'); | ||
| if((!l.url.match(/\baccess_token/gi))) { | ||
| l.url += "access_token={{request.session.access_token}}"; | ||
| } else { | ||
| l.url = | ||
| l.url.replace(/(access_token)(.+?)(?=\&)/, "$1={{request.session.access_token}}"); | ||
| } | ||
| } | ||
| } catch(err) { | ||
| console.log(err); | ||
| } | ||
| {% endif %} | ||
|
|
||
| for (var ll in app.mapPanel.map.layers) { | ||
| l = app.mapPanel.map.layers[ll]; | ||
| if (l.url != undefined && (typeof l.url) == "string" && l.url.indexOf('{{GEOSERVER_BASE_URL}}') !== -1) { | ||
| l.addOptions({wrapDateLine:true, displayOutsideMaxExtent: true}); | ||
| l.addOptions({maxExtent:app.mapPanel.map.getMaxExtent()}); | ||
| {% if 'access_token' in request.session %} | ||
| try { | ||
| l.url += ( !l.url.match(/\b\?/gi) || l.url.match(/\b\?/gi).length == 0 ? '?' : '&'); | ||
| if((!l.url.match(/\baccess_token/gi))) { | ||
| l.url += "access_token={{request.session.access_token}}"; | ||
| } else { | ||
| l.url = | ||
| l.url.replace(/(access_token)(.+?)(?=\&)/, "$1={{request.session.access_token}}"); | ||
| } | ||
| } catch(err) { | ||
| console.log(err); | ||
| } | ||
| {% endif %} | ||
| } | ||
| } | ||
|
|
||
| var map = app.mapPanel.map; | ||
| var layer = app.map.layers.slice(-1)[0]; | ||
| var bbox = layer.bbox; | ||
| var crs = layer.srs; | ||
| if (bbox != undefined) | ||
| { | ||
| var extent = new OpenLayers.Bounds(); | ||
|
|
||
| if (layer.capability.bbox && | ||
| !Array.isArray(layer.capability.bbox) && | ||
| map.projection in layer.capability.bbox) { | ||
| bbox = layer.capability.bbox[map.projection].bbox; | ||
| extent = OpenLayers.Bounds.fromArray(bbox); | ||
| } else { | ||
| if (crs != map.projection) { | ||
| extent = OpenLayers.Bounds.fromArray(bbox); | ||
| extent = extent.clone().transform(crs, map.projection); | ||
| } else { | ||
| extent = OpenLayers.Bounds.fromArray(bbox); | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| 'save': function(obj_id) { | ||
| createMapThumbnail(obj_id); | ||
| } | ||
| } | ||
| }, {{ config }}); | ||
|
|
||
| app = new GeoNode.Viewer(config); | ||
| {% endautoescape %} | ||
| }); | ||
| </script> |