def geoserver_post_save2(layer_id): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ from geonode.layers.models import Layer instance = Layer.objects.get(id=layer_id) # Don't run this signal if is a Layer from a remote service if getattr(instance, "service", None) is not None: return instance # Don't run this signal handler if it is a tile layer # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr(instance, 'storeType') == 'tileStore': return instance gs_resource = None # If the store in None then it's a new instance from an upload, # only in this case run the geonode_uplaod method if not instance.store or getattr(instance, 'overwrite', False): base_file, info = instance.get_base_file() # There is no need to process it if there is not file. if base_file is None: return instance gs_name, workspace, values, gs_resource = geoserver_upload( instance, base_file.file.path, instance.owner, instance.name, overwrite=True, title=instance.title, abstract=instance.abstract, # keywords=instance.keywords, charset=instance.charset) # Set fields obtained via the geoserver upload. instance.name = gs_name instance.workspace = workspace instance.store = values['store'] # Iterate over values from geoserver. for key in ['typename', 'store', 'storeType']: setattr(instance, key, values[key]) instance.save() if not gs_resource: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) if gs_resource: gs_resource.title = instance.title if instance.title else "" gs_resource.abstract = instance.abstract if instance.abstract else "" gs_resource.name = instance.name if instance.name else "" # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) if gs_resource: gs_resource.metadata_links = metadata_links # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if gs_resource and getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) gs_layer = gs_catalog.get_layer(instance.name) if instance.poc and instance.poc: # gsconfig now utilizes an attribution dictionary gs_layer.attribution = { 'title': str(instance.poc), 'width': None, 'height': None, 'href': None, 'url': None, 'type': None } profile = Profile.objects.get(username=instance.poc.username) gs_layer.attribution_link = settings.SITEURL[: -1] + profile.get_absolute_url( ) # gs_layer should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_layer) """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ if gs_resource: bbox = gs_resource.latlon_bbox # FIXME(Ariel): Correct srid setting below # self.srid = gs_resource.src instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" # Set bounding box values instance.bbox_x0 = bbox[0] instance.bbox_x1 = bbox[1] instance.bbox_y0 = bbox[2] instance.bbox_y1 = bbox[3] # store the resource to avoid another geoserver call in the post_save instance.gs_resource = gs_resource instance.save() if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return instance if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return instance if not getattr(instance, 'gs_resource', None): try: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return instance else: gs_resource = instance.gs_resource if gs_resource is None: return instance if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) gs_store_type = gs_resource.store.type.lower( ) if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get( 'geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '') if gs_store_type == 'geogig' and geogig_repo_name: repo_url = '{url}geogig/repos/{repo_name}'.format( url=ogc_server_settings.public_url, repo_name=geogig_repo_name) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html')) def command_url(command): return "{repo_url}/{command}.json?{path}".format( repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html')) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html')) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8')) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', )) create_gs_thumbnail(instance, overwrite=False) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', )) ogc_wms_path = '%s/wms' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Define the link after the cleanup, we should use this more rather then remove # potential parasites tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') link, created = Link.objects.get_or_create( resource=instance.resourcebase_ptr, extension='tiles', name="Tiles", mime='image/png', link_type='image', ) if created: Link.objects.filter(pk=link.pk).update(url=tile_url) # Save layer attributes set_attributes_from_geoserver(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 from geonode.catalogue.models import catalogue_post_save from geonode.layers.models import Layer catalogue_post_save(instance, Layer) return instance
def test_ogc_server_defaults(self): """ Tests that OGC_SERVER_SETTINGS are built if they do not exist in the settings. """ from django.urls import reverse, resolve from ..ows import _wcs_get_capabilities, _wfs_get_capabilities, _wms_get_capabilities OGC_SERVER = {'default': dict()} defaults = self.OGC_DEFAULT_SETTINGS.get('default') ogc_settings = OGC_Servers_Handler(OGC_SERVER)['default'] self.assertEqual(ogc_settings.server, defaults) self.assertEqual(ogc_settings.rest, f"{defaults['LOCATION']}rest") self.assertEqual(ogc_settings.ows, f"{defaults['LOCATION']}ows") # Make sure we get None vs a KeyError when the key does not exist self.assertIsNone(ogc_settings.SFDSDFDSF) # Testing REST endpoints route = resolve('/gs/rest/layers').route self.assertEqual(route, '^gs/rest/layers') route = resolve('/gs/rest/imports').route self.assertEqual(route, '^gs/rest/imports') route = resolve('/gs/rest/sldservice').route self.assertEqual(route, '^gs/rest/sldservice') store_resolver = resolve('/gs/rest/stores/geonode_data/') self.assertEqual(store_resolver.url_name, 'stores') self.assertEqual(store_resolver.kwargs['store_type'], 'geonode_data') self.assertEqual(store_resolver.route, '^gs/rest/stores/(?P<store_type>\\w+)/$') sld_resolver = resolve('/gs/rest/styles') self.assertIsNone(sld_resolver.url_name) self.assertTrue('workspace' not in sld_resolver.kwargs) self.assertEqual(sld_resolver.kwargs['proxy_path'], '/gs/rest/styles') self.assertEqual(sld_resolver.kwargs['downstream_path'], 'rest/styles') self.assertEqual(sld_resolver.route, '^gs/rest/styles') sld_resolver = resolve('/gs/rest/workspaces/geonode/styles') self.assertIsNone(sld_resolver.url_name) self.assertEqual(sld_resolver.kwargs['workspace'], 'geonode') self.assertEqual(sld_resolver.kwargs['proxy_path'], '/gs/rest/workspaces') self.assertEqual(sld_resolver.kwargs['downstream_path'], 'rest/workspaces') self.assertEqual(sld_resolver.route, '^gs/rest/workspaces/(?P<workspace>\\w+)') # Testing OWS endpoints wcs = _wcs_get_capabilities() logger.debug(wcs) self.assertIsNotNone(wcs) try: wcs_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except Exception: wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wcs.startswith(wcs_url)) self.assertIn("service=WCS", wcs) self.assertIn("request=GetCapabilities", wcs) self.assertIn("version=2.0.1", wcs) wfs = _wfs_get_capabilities() logger.debug(wfs) self.assertIsNotNone(wfs) try: wfs_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except Exception: wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wfs.startswith(wfs_url)) self.assertIn("service=WFS", wfs) self.assertIn("request=GetCapabilities", wfs) self.assertIn("version=1.1.0", wfs) wms = _wms_get_capabilities() logger.debug(wms) self.assertIsNotNone(wms) try: wms_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except Exception: wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wms.startswith(wms_url)) self.assertIn("service=WMS", wms) self.assertIn("request=GetCapabilities", wms) self.assertIn("version=1.3.0", wms) # Test OWS Download Links from geonode.geoserver.ows import wcs_links, wfs_links, wms_links instance = create_single_dataset("san_andres_y_providencia_water") instance.name = 'san_andres_y_providencia_water' instance.save() bbox = instance.bbox srid = instance.srid height = 512 width = 512 # Default Style (expect exception since we are offline) style = get_sld_for(gs_catalog, instance) logger.error( f" style -------------------------------------------> {style}") if isinstance(style, str): style = gs_catalog.get_style(instance.name, workspace=instance.workspace) self.assertIsNotNone(style) self.assertFalse(isinstance(style, str)) instance.default_style, _ = Style.objects.get_or_create( name=style.name, defaults=dict(sld_title=style.sld_title, sld_body=style.sld_body)) self.assertIsNotNone(instance.default_style) self.assertIsNotNone(instance.default_style.name) # WMS Links wms_links = wms_links(f"{ogc_settings.public_url}wms?", instance.alternate, bbox, srid, height, width) self.assertIsNotNone(wms_links) self.assertEqual(len(wms_links), 3) wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wms') identifier = urlencode({'layers': instance.alternate}) for _link in wms_links: logger.debug(f'{wms_url} --> {_link[3]}') self.assertTrue(wms_url in _link[3]) logger.debug(f'{identifier} --> {_link[3]}') self.assertTrue(identifier in _link[3]) # WFS Links wfs_links = wfs_links(f"{ogc_settings.public_url}wfs?", instance.alternate, bbox, srid) self.assertIsNotNone(wfs_links) self.assertEqual(len(wfs_links), 6) wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wfs') identifier = urlencode({'typename': instance.alternate}) for _link in wfs_links: logger.debug(f'{wfs_url} --> {_link[3]}') self.assertTrue(wfs_url in _link[3]) logger.debug(f'{identifier} --> {_link[3]}') self.assertTrue(identifier in _link[3]) # WCS Links wcs_links = wcs_links(f"{ogc_settings.public_url}wcs?", instance.alternate, bbox, srid) self.assertIsNotNone(wcs_links) self.assertEqual(len(wcs_links), 2) wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wcs') identifier = urlencode( {'coverageid': instance.alternate.replace(':', '__', 1)}) for _link in wcs_links: logger.debug(f'{wcs_url} --> {_link[3]}') self.assertTrue(wcs_url in _link[3]) logger.debug(f'{identifier} --> {_link[3]}') self.assertTrue(identifier in _link[3])
def test_ogc_server_defaults(self): """ Tests that OGC_SERVER_SETTINGS are built if they do not exist in the settings. """ OGC_SERVER = {'default': dict()} defaults = self.OGC_DEFAULT_SETTINGS.get('default') ogc_settings = OGC_Servers_Handler(OGC_SERVER)['default'] self.assertEqual(ogc_settings.server, defaults) self.assertEqual(ogc_settings.rest, defaults['LOCATION'] + 'rest') self.assertEqual(ogc_settings.ows, defaults['LOCATION'] + 'ows') # Make sure we get None vs a KeyError when the key does not exist self.assertIsNone(ogc_settings.SFDSDFDSF) # Testing OWS endpoints from urlparse import urljoin from django.core.urlresolvers import reverse from .ows import _wcs_get_capabilities, _wfs_get_capabilities, _wms_get_capabilities wcs = _wcs_get_capabilities() logger.debug(wcs) self.assertIsNotNone(wcs) try: wcs_url = urljoin(settings.SITEURL, reverse('wcs_endpoint')) except BaseException: wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals(wcs, '%s?version=2.0.1&request=GetCapabilities&service=WCS' % wcs_url) wfs = _wfs_get_capabilities() logger.debug(wfs) self.assertIsNotNone(wfs) try: wfs_url = urljoin(settings.SITEURL, reverse('wfs_endpoint')) except BaseException: wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals(wfs, '%s?version=1.1.0&request=GetCapabilities&service=WFS' % wfs_url) wms = _wms_get_capabilities() logger.debug(wms) self.assertIsNotNone(wms) try: wms_url = urljoin(settings.SITEURL, reverse('wms_endpoint')) except BaseException: wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals(wms, '%s?version=1.1.1&request=GetCapabilities&service=WMS' % wms_url) # Test OWS Download Links import urllib from geonode.geoserver.ows import wcs_links, wfs_links, wms_links instance = Layer.objects.all()[0] bbox = instance.bbox srid = instance.srid height = 512 width = 512 # WMS Links wms_links = wms_links(ogc_settings.public_url + 'wms?', instance.alternate.encode('utf-8'), bbox, srid, height, width) self.assertIsNotNone(wms_links) self.assertEquals(len(wms_links), 3) wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wms') identifier = urllib.urlencode({'layers': instance.alternate.encode('utf-8')}) for _link in wms_links: logger.debug('%s --> %s' % (wms_url, _link[3])) self.assertTrue(wms_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WFS Links wfs_links = wfs_links(ogc_settings.public_url + 'wfs?', instance.alternate.encode('utf-8'), bbox, srid) self.assertIsNotNone(wfs_links) self.assertEquals(len(wfs_links), 6) wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wfs') identifier = urllib.urlencode({'typename': instance.alternate.encode('utf-8')}) for _link in wfs_links: logger.debug('%s --> %s' % (wfs_url, _link[3])) self.assertTrue(wfs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WCS Links wcs_links = wcs_links(ogc_settings.public_url + 'wcs?', instance.alternate.encode('utf-8'), bbox, srid) self.assertIsNotNone(wcs_links) self.assertEquals(len(wcs_links), 2) wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wcs') identifier = urllib.urlencode({'coverageid': instance.alternate.encode('utf-8')}) for _link in wcs_links: logger.debug('%s --> %s' % (wcs_url, _link[3])) self.assertTrue(wcs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3])
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes(instance) return if not getattr(instance, 'gs_resource', None): try: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return else: gs_resource = instance.gs_resource if gs_resource is None: return if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links( ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) if gs_resource.store.type and gs_resource.store.type.lower() == 'geogig' and \ gs_resource.store.connection_parameters.get('geogig_repository'): repo_url = '{url}geogig/{geogig_repository}'.format( url=ogc_server_settings.public_url, geogig_repository=gs_resource.store.connection_parameters.get('geogig_repository')) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html' ) ) def command_url(command): return "{repo_url}/{command}.json?{path}".format(repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html' ) ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html' ) ) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8')) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', ) ) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', ) ) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', ) ) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8' ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name="Tiles", mime='image/png', link_type='image', ) ) html_link_url = '%s%s' % ( settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', ) ) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, 'TIME': '-99999999999-01-01T00:00:00.0Z/99999999999-01-01T00:00:00.0Z' } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + \ "wms/reflect?" + p thumbnail_create_url = ogc_server_settings.LOCATION + \ "wms/reflect?" + p create_thumbnail(instance, thumbnail_remote_url, thumbnail_create_url, ogc_client=http_client) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', ) ) ogc_wms_path = '%s/wms' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', ) ) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', ) ) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', ) ) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse( settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Save layer attributes set_attributes(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 from geonode.catalogue.models import catalogue_post_save from geonode.layers.models import Layer catalogue_post_save(instance, Layer)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ url = ogc_server_settings.internal_rest try: gs_resource= gs_catalog.get_resource(instance.name) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() #gs_resource should only be called if ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings,"BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource= instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime=='SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) elif instance.storeType == 'coverageStore': #FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = {} permissions['anonymous'] = instance.get_gen_level(ANONYMOUS_USERS) permissions['authenticated'] = instance.get_gen_level(AUTHENTICATED_USERS) instance.set_gen_level(ANONYMOUS_USERS,'layer_readonly') #Potentially 3 dimensions can be returned by the grid if there is a z #axis. Since we only want width/height, slice to the second dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', ) ) instance.set_gen_level(ANONYMOUS_USERS,permissions['anonymous']) instance.set_gen_level(AUTHENTICATED_USERS,permissions['authenticated']) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode({ 'layers': instance.typename.encode('utf-8'), 'mode': "download" }) Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name=_("KML"), mime='text/xml', link_type='data', ) ) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode({ 'layers': instance.typename.encode('utf-8'), 'mode': "refresh" }) Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', ) ) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8' ) Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name=_("Tiles"), mime='image/png', link_type='image', ) ) wms_path = '%s/%s/wms' % (instance.workspace, instance.name) ows_url = urljoin(ogc_server_settings.public_url, wms_path) Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=ows_url, defaults=dict( extension='html', name=_("OWS"), url=ows_url, mime='text/html', link_type='OGC:WMS', ) ) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', ) ) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s"%item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + "wms/reflect?" + p create_thumbnail(instance, thumbnail_remote_url) legend_url = ogc_server_settings.PUBLIC_LOCATION +'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER='+instance.typename+'&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name=_('Legend'), url=legend_url, mime='image/png', link_type='image', ) ) ogc_wms_url = ogc_server_settings.public_url + 'wms?' Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=instance.name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', ) ) if instance.storeType == "dataStore": ogc_wfs_url = ogc_server_settings.public_url + 'wfs?' Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', ) ) if instance.storeType == "coverageStore": ogc_wcs_url = ogc_server_settings.public_url + 'wcs?' Link.objects.get_or_create(resource= instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', ) ) #remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse(link.url).hostname and not \ urlparse(ogc_server_settings.public_url).hostname == urlparse(link.url).hostname: link.delete() #Save layer attributes set_attributes(instance) #Save layer styles set_styles(instance, gs_catalog)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ if instance.storeType == "remoteStore": #Save layer attributes set_attributes(instance) return url = ogc_server_settings.internal_rest try: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if gs_resource is None: return if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() #gs_resource should only be called if ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) elif instance.storeType == 'coverageStore': #FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = instance.get_all_level_info() instance.set_permissions( {'users': { 'AnonymousUser': ['view_resourcebase'] }}) try: #Potentially 3 dimensions can be returned by the grid if there is a z #axis. Since we only want width/height, slice to the second dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] except GeoNodeException, e: msg = _('Could not create a download link for layer.') logger.warn(msg, e) else: links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) instance.set_permissions(permissions)
def test_ogc_server_defaults(self): """ Tests that OGC_SERVER_SETTINGS are built if they do not exist in the settings. """ OGC_SERVER = {'default': dict()} defaults = self.OGC_DEFAULT_SETTINGS.get('default') ogc_settings = OGC_Servers_Handler(OGC_SERVER)['default'] self.assertEqual(ogc_settings.server, defaults) self.assertEqual(ogc_settings.rest, defaults['LOCATION'] + 'rest') self.assertEqual(ogc_settings.ows, defaults['LOCATION'] + 'ows') # Make sure we get None vs a KeyError when the key does not exist self.assertIsNone(ogc_settings.SFDSDFDSF) # Testing OWS endpoints from django.urls import reverse from ..ows import _wcs_get_capabilities, _wfs_get_capabilities, _wms_get_capabilities wcs = _wcs_get_capabilities() logger.debug(wcs) self.assertIsNotNone(wcs) try: wcs_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except BaseException: wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wcs.startswith(wcs_url)) self.assertIn("service=WCS", wcs) self.assertIn("request=GetCapabilities", wcs) self.assertIn("version=2.0.1", wcs) wfs = _wfs_get_capabilities() logger.debug(wfs) self.assertIsNotNone(wfs) try: wfs_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except BaseException: wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wfs.startswith(wfs_url)) self.assertIn("service=WFS", wfs) self.assertIn("request=GetCapabilities", wfs) self.assertIn("version=1.1.0", wfs) wms = _wms_get_capabilities() logger.debug(wms) self.assertIsNotNone(wms) try: wms_url = urljoin(settings.SITEURL, reverse('ows_endpoint')) except BaseException: wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertTrue(wms.startswith(wms_url)) self.assertIn("service=WMS", wms) self.assertIn("request=GetCapabilities", wms) self.assertIn("version=1.3.0", wms) # Test OWS Download Links from geonode.geoserver.ows import wcs_links, wfs_links, wms_links instance = Layer.objects.all()[0] bbox = instance.bbox srid = instance.srid height = 512 width = 512 # Default Style (expect exception since we are offline) style = None with self.assertRaises(GeoNodeException): style = get_sld_for(gs_catalog, instance) self.assertIsNone(style) style = gs_catalog.get_style("line") self.assertIsNotNone(style) instance.default_style, _ = Style.objects.get_or_create( name=style.name, defaults=dict( sld_title=style.sld_title, sld_body=style.sld_body ) ) self.assertIsNotNone(instance.default_style) self.assertIsNotNone(instance.default_style.name) # WMS Links wms_links = wms_links(ogc_settings.public_url + 'wms?', instance.alternate, bbox, srid, height, width) self.assertIsNotNone(wms_links) self.assertEquals(len(wms_links), 3) wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wms') identifier = urlencode({'layers': instance.alternate}) for _link in wms_links: logger.debug('%s --> %s' % (wms_url, _link[3])) self.assertTrue(wms_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WFS Links wfs_links = wfs_links(ogc_settings.public_url + 'wfs?', instance.alternate, bbox, srid) self.assertIsNotNone(wfs_links) self.assertEquals(len(wfs_links), 6) wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wfs') identifier = urlencode({'typename': instance.alternate}) for _link in wfs_links: logger.debug('%s --> %s' % (wfs_url, _link[3])) self.assertTrue(wfs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WCS Links wcs_links = wcs_links(ogc_settings.public_url + 'wcs?', instance.alternate, bbox, srid) self.assertIsNotNone(wcs_links) self.assertEquals(len(wcs_links), 2) wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wcs') identifier = urlencode({'coverageid': instance.alternate}) for _link in wcs_links: logger.debug('%s --> %s' % (wcs_url, _link[3])) self.assertTrue(wcs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # Thumbnails Generation Default create_gs_thumbnail(instance, overwrite=True) self.assertIsNotNone(instance.get_thumbnail_url()) # Thumbnails Generation Through "remote url" create_gs_thumbnail_geonode(instance, overwrite=True, check_bbox=True) # Thumbnails Generation Through "image" request_body = { 'width': width, 'height': height, 'layers': instance.alternate } if hasattr(instance, 'default_style'): if instance.default_style: request_body['styles'] = instance.default_style.name self.assertIsNotNone(request_body['styles']) try: image = _prepare_thumbnail_body_from_opts(request_body) except BaseException as e: logger.exception(e) image = None # We are offline here, the layer does not exists in GeoServer # - we expect the image is None self.assertIsNone(image)
def test_ogc_server_defaults(self): """ Tests that OGC_SERVER_SETTINGS are built if they do not exist in the settings. """ OGC_SERVER = {'default': dict()} defaults = self.OGC_DEFAULT_SETTINGS.get('default') ogc_settings = OGC_Servers_Handler(OGC_SERVER)['default'] self.assertEqual(ogc_settings.server, defaults) self.assertEqual(ogc_settings.rest, defaults['LOCATION'] + 'rest') self.assertEqual(ogc_settings.ows, defaults['LOCATION'] + 'ows') # Make sure we get None vs a KeyError when the key does not exist self.assertIsNone(ogc_settings.SFDSDFDSF) # Testing OWS endpoints from urlparse import urljoin from django.core.urlresolvers import reverse from .ows import _wcs_get_capabilities, _wfs_get_capabilities, _wms_get_capabilities wcs = _wcs_get_capabilities() logger.debug(wcs) self.assertIsNotNone(wcs) try: wcs_url = urljoin(settings.SITEURL, reverse('wcs_endpoint')) except BaseException: wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals( wcs, '%s?version=2.0.1&request=GetCapabilities&service=WCS' % wcs_url) wfs = _wfs_get_capabilities() logger.debug(wfs) self.assertIsNotNone(wfs) try: wfs_url = urljoin(settings.SITEURL, reverse('wfs_endpoint')) except BaseException: wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals( wfs, '%s?version=1.1.0&request=GetCapabilities&service=WFS' % wfs_url) wms = _wms_get_capabilities() logger.debug(wms) self.assertIsNotNone(wms) try: wms_url = urljoin(settings.SITEURL, reverse('wms_endpoint')) except BaseException: wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'ows') self.assertEquals( wms, '%s?version=1.1.1&request=GetCapabilities&service=WMS' % wms_url) # Test OWS Download Links import urllib from geonode.geoserver.ows import wcs_links, wfs_links, wms_links instance = Layer.objects.all()[0] bbox = instance.bbox srid = instance.srid height = 512 width = 512 # WMS Links wms_links = wms_links(ogc_settings.public_url + 'wms?', instance.alternate.encode('utf-8'), bbox, srid, height, width) self.assertIsNotNone(wms_links) self.assertEquals(len(wms_links), 3) wms_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wms') identifier = urllib.urlencode( {'layers': instance.alternate.encode('utf-8')}) for _link in wms_links: logger.debug('%s --> %s' % (wms_url, _link[3])) self.assertTrue(wms_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WFS Links wfs_links = wfs_links(ogc_settings.public_url + 'wfs?', instance.alternate.encode('utf-8'), bbox, srid) self.assertIsNotNone(wfs_links) self.assertEquals(len(wfs_links), 6) wfs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wfs') identifier = urllib.urlencode( {'typename': instance.alternate.encode('utf-8')}) for _link in wfs_links: logger.debug('%s --> %s' % (wfs_url, _link[3])) self.assertTrue(wfs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3]) # WCS Links wcs_links = wcs_links(ogc_settings.public_url + 'wcs?', instance.alternate.encode('utf-8'), bbox, srid) self.assertIsNotNone(wcs_links) self.assertEquals(len(wcs_links), 2) wcs_url = urljoin(ogc_settings.PUBLIC_LOCATION, 'wcs') identifier = urllib.urlencode( {'coverageid': instance.alternate.encode('utf-8')}) for _link in wcs_links: logger.debug('%s --> %s' % (wcs_url, _link[3])) self.assertTrue(wcs_url in _link[3]) logger.debug('%s --> %s' % (identifier, _link[3])) self.assertTrue(identifier in _link[3])
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ url = ogc_server_settings.internal_rest try: gs_resource = gs_catalog.get_resource(instance.name) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() #gs_resource should only be called if ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) elif instance.storeType == 'coverageStore': #FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = {} permissions['anonymous'] = instance.get_gen_level(ANONYMOUS_USERS) permissions['authenticated'] = instance.get_gen_level( AUTHENTICATED_USERS) instance.set_gen_level(ANONYMOUS_USERS, 'layer_readonly') #Potentially 3 dimensions can be returned by the grid if there is a z #axis. Since we only want width/height, slice to the second dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) instance.set_gen_level(ANONYMOUS_USERS, permissions['anonymous']) instance.set_gen_level(AUTHENTICATED_USERS, permissions['authenticated']) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode( { 'layers': instance.typename.encode('utf-8'), 'mode': "download" }) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name=_("KML"), mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode( { 'layers': instance.typename.encode('utf-8'), 'mode': "refresh" }) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name=_("Tiles"), mime='image/png', link_type='image', )) wms_path = '%s/%s/wms' % (instance.workspace, instance.name) ows_url = urljoin(ogc_server_settings.public_url, wms_path) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ows_url, defaults=dict( extension='html', name=_("OWS"), url=ows_url, mime='text/html', link_type='OGC:WMS', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', )) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + "wms/reflect?" + p create_thumbnail(instance, thumbnail_remote_url) legend_url = ogc_server_settings.PUBLIC_LOCATION + 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name=_('Legend'), url=legend_url, mime='image/png', link_type='image', )) ogc_wms_url = ogc_server_settings.public_url + 'wms?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=instance.name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_url = ogc_server_settings.public_url + 'wfs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_url = ogc_server_settings.public_url + 'wcs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) #remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse(link.url).hostname and not \ urlparse(ogc_server_settings.public_url).hostname == urlparse(link.url).hostname: link.delete() #Save layer attributes set_attributes(instance) #Save layer styles set_styles(instance, gs_catalog)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ if instance.storeType == "remoteStore": # Save layer attributes set_attributes(instance) return try: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if gs_resource is None: return if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links( ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) if gs_resource.store.type.lower() == 'geogit': repo_url = '{url}geogit/{workspace}:{store}'.format( url=ogc_server_settings.public_url, workspace=instance.workspace, store=instance.store) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGit', mime='text/xml', link_type='html' ) ) command_url = lambda command: "{repo_url}/{command}.json?{path}".format( repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGit log', mime='application/json', link_type='html' ) ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGit statistics', mime='application/json', link_type='html' ) ) elif instance.storeType == 'coverageStore': # FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = instance.get_all_level_info() instance.set_permissions( {'users': {'AnonymousUser': ['view_resourcebase']}}) try: # Potentially 3 dimensions can be returned by the grid if there is a z # axis. Since we only want width/height, slice to the second # dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] except GeoNodeException as e: msg = _('Could not create a download link for layer.') logger.warn(msg, e) else: links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', ) ) instance.set_permissions(permissions) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name=_("KML"), mime='text/xml', link_type='data', ) ) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', ) ) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8' ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name=_("Tiles"), mime='image/png', link_type='image', ) ) wms_path = '%s/%s/wms' % (instance.workspace, instance.name) ows_url = urljoin(ogc_server_settings.public_url, wms_path) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ows_url, defaults=dict( extension='html', name=_("OWS"), url=ows_url, mime='text/html', link_type='OGC:WMS', ) ) html_link_url = '%s%s' % ( settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', ) ) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + \ "wms/reflect?" + p thumbail_create_url = ogc_server_settings.LOCATION + \ "wms/reflect?" + p # This is a workaround for development mode where cookies are not shared and the layer is not public so # not visible through geoserver if settings.DEBUG: from geonode.security.views import _perms_info_json current_perms = _perms_info_json(instance.get_self_resource()) instance.set_default_permissions() create_thumbnail(instance, thumbnail_remote_url, thumbail_create_url) if settings.DEBUG: instance.set_permissions(json.loads(current_perms)) legend_url = ogc_server_settings.PUBLIC_LOCATION + 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name=_('Legend'), url=legend_url, mime='image/png', link_type='image', ) ) ogc_wms_url = ogc_server_settings.public_url + 'wms?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=instance.name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', ) ) if instance.storeType == "dataStore": ogc_wfs_url = ogc_server_settings.public_url + 'wfs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', ) ) if instance.storeType == "coverageStore": ogc_wcs_url = ogc_server_settings.public_url + 'wcs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', ) ) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse( settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Save layer attributes set_attributes(instance) # Save layer styles set_styles(instance, gs_catalog)
def geoserver_post_save_local(instance, *args, **kwargs): """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ # Don't run this signal if is a Layer from a remote service if getattr(instance, "remote_service", None) is not None: return # Don't run this signal handler if it is a tile layer or a remote store (Service) # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr(instance, 'storeType') in ['tileStore', 'remoteStore']: return instance gs_resource = None values = None # If the store in None then it's a new instance from an upload, # only in this case run the geoserver_upload method if not instance.store or getattr(instance, 'overwrite', False): base_file, info = instance.get_base_file() # There is no need to process it if there is not file. if base_file is None: return gs_name, workspace, values, gs_resource = geoserver_upload(instance, base_file.file.path, instance.owner, instance.name, overwrite=True, title=instance.title, abstract=instance.abstract, # keywords=instance.keywords, charset=instance.charset) if not gs_resource: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource(instance.alternate) if gs_resource: gs_resource.title = instance.title or "" gs_resource.abstract = instance.abstract or "" gs_resource.name = instance.name or "" if not values: values = dict(store=gs_resource.store.name, storeType=gs_resource.store.resource_type, alternate=gs_resource.store.workspace.name + ':' + gs_resource.name, title=gs_resource.title or gs_resource.store.name, abstract=gs_resource.abstract or '', owner=instance.owner) else: msg = "There isn't a geoserver resource for this layer: %s" % instance.name logger.exception(msg) raise Exception(msg) # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) gs_resource.metadata_links = metadata_links # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg,) logger.exception(e) # Update Attribution link if instance.poc: # gsconfig now utilizes an attribution dictionary gs_resource.attribution = {'title': str(instance.poc), 'width': None, 'height': None, 'href': None, 'url': None, 'type': None} profile = Profile.objects.get(username=instance.poc.username) site_url = settings.SITEURL.rstrip('/') if settings.SITEURL.startswith('http') else settings.SITEURL gs_resource.attribution_link = site_url + profile.get_absolute_url() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save layer named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg,) logger.exception(e) if isinstance(instance, ResourceBase): if hasattr(instance, 'layer'): instance = instance.layer else: return # Save layer attributes set_attributes_from_geoserver(instance) # Save layer styles set_styles(instance, gs_catalog) # set SLD sld = instance.default_style.sld_body if instance.default_style else None if sld: set_layer_style(instance, instance.alternate, sld) # Invalidate GeoWebCache for the updated resource try: _stylefilterparams_geowebcache_layer(instance.alternate) _invalidate_geowebcache_layer(instance.alternate) except BaseException: pass if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ # instance.name = instance.name or gs_resource.name # instance.title = instance.title or gs_resource.title instance.abstract = gs_resource.abstract or '' instance.workspace = gs_resource.store.workspace.name instance.store = gs_resource.store.name try: bbox = gs_resource.native_bbox # Set bounding box values instance.bbox_x0 = bbox[0] instance.bbox_x1 = bbox[1] instance.bbox_y0 = bbox[2] instance.bbox_y1 = bbox[3] instance.srid = bbox[4] except BaseException: pass if instance.srid: instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" else: raise GeoNodeException("Invalid Projection. Layer is missing CRS!") # Iterate over values from geoserver. for key in ['alternate', 'store', 'storeType']: # attr_name = key if 'typename' not in key else 'alternate' # print attr_name setattr(instance, key, values[key]) if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = 'true' if instance.is_published else 'false' gs_catalog.save(gs_resource) if not settings.FREETEXT_KEYWORDS_READONLY: try: if len(instance.keyword_list()) == 0 and gs_resource.keywords: for keyword in gs_resource.keywords: if keyword not in instance.keyword_list(): instance.keywords.add(keyword) except BaseException: pass if any(instance.keyword_list()): keywords = instance.keyword_list() gs_resource.keywords = [kw.decode("utf-8", "replace") for kw in list(set(keywords))] # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg,) logger.exception(e) to_update = { 'title': instance.title or instance.name, 'abstract': instance.abstract or "", 'alternate': instance.alternate, 'bbox_x0': instance.bbox_x0, 'bbox_x1': instance.bbox_x1, 'bbox_y0': instance.bbox_y0, 'bbox_y1': instance.bbox_y1, 'srid': instance.srid } # Update ResourceBase resources = ResourceBase.objects.filter(id=instance.resourcebase_ptr.id) resources.update(**to_update) # to_update['name'] = instance.name, to_update['workspace'] = instance.workspace to_update['store'] = instance.store to_update['storeType'] = instance.storeType to_update['typename'] = instance.alternate # Save all the modified information in the instance without triggering signals. Layer.objects.filter(id=instance.id).update(**to_update) # Refresh from DB instance.refresh_from_db() # store the resource to avoid another geoserver call in the post_save instance.gs_resource = gs_resource try: bbox = gs_resource.native_bbox except BaseException: bbox = instance.bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Parse Layer BBOX and SRID srid = instance.srid if instance.srid else getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:4326') if srid and instance.bbox_x0: bbox = ','.join(str(x) for x in [instance.bbox_x0, instance.bbox_y0, instance.bbox_x1, instance.bbox_y1]) # Create Raw Data download link try: path = gs_resource.dom.findall('nativeName') except BaseException: path = instance.alternate download_url = urljoin(settings.SITEURL, reverse('download', args=[instance.id])) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=download_url, defaults=dict(extension='zip', name='Original Dataset', mime='application/octet-stream', link_type='original', ) ) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.alternate.encode('utf-8'), bbox, srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.alternate.encode('utf-8'), bbox=None, # bbox filter should be set at runtime otherwise conflicting with CQL srid=srid) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) gs_store_type = gs_resource.store.type.lower() if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get('geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '') if gs_store_type == 'geogig' and geogig_repo_name: repo_url = '{url}geogig/repos/{repo_name}'.format( url=ogc_server_settings.public_url, repo_name=geogig_repo_name) try: path = gs_resource.dom.findall('nativeName') except BaseException: path = instance.alternate if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html' ) ) def command_url(command): return "{repo_url}/{command}.json?{path}".format(repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html' ) ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html' ) ) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.alternate.encode('utf-8'), bbox, srid) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', ) ) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.alternate.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', ) ) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.alternate.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', ) ) site_url = settings.SITEURL.rstrip('/') if settings.SITEURL.startswith('http') else settings.SITEURL html_link_url = '%s%s' % ( site_url, instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.alternate, mime='text/html', link_type='html', ) ) # some thumbnail generators will update thumbnail_url. If so, don't # immediately re-generate the thumbnail here. use layer#save(update_fields=['thumbnail_url']) if 'update_fields' in kwargs and kwargs['update_fields'] is not None and \ 'thumbnail_url' in kwargs['update_fields']: logger.info("... Creating Thumbnail for Layer [%s]" % (instance.alternate)) create_gs_thumbnail(instance, overwrite=True) try: Link.objects.filter(resource=instance.resourcebase_ptr, name='Legend').delete() except BaseException: pass for style in instance.styles.all(): legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.alternate + '&STYLE=' + style.name + \ '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', ) ) # ogc_wms_path = '%s/ows' % instance.workspace ogc_wms_path = 'ows' ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', ) ) if instance.storeType == "dataStore": # ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_path = 'wfs' ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', ) ) if instance.storeType == "coverageStore": # ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_path = 'wcs' ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', ) ) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse( settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Define the link after the cleanup, we should use this more rather then remove # potential parasites tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.alternate.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8' ) link, created = Link.objects.get_or_create(resource=instance.resourcebase_ptr, extension='tiles', name="Tiles", mime='image/png', link_type='image', ) if created: Link.objects.filter(pk=link.pk).update(url=tile_url) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 catalogue_post_save(instance, Layer) # Updating HAYSTACK Indexes if needed if settings.HAYSTACK_SEARCH: from django.core.management import call_command call_command('update_index')
def geoserver_post_save2(layer_id): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ from geonode.layers.models import Layer instance = Layer.objects.get(id=layer_id) # Don't run this signal if is a Layer from a remote service if getattr(instance, "service", None) is not None: return instance # Don't run this signal handler if it is a tile layer or a remote store (Service) # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr(instance, 'storeType') in ['tileStore', 'remoteStore']: return instance gs_resource = None # If the store in None then it's a new instance from an upload, # only in this case run the geonode_uplaod method if not instance.store or getattr(instance, 'overwrite', False): base_file, info = instance.get_base_file() # There is no need to process it if there is not file. if base_file is None: return instance gs_name, workspace, values, gs_resource = geoserver_upload(instance, base_file.file.path, instance.owner, instance.name, overwrite=True, title=instance.title, abstract=instance.abstract, # keywords=instance.keywords, charset=instance.charset) # Set fields obtained via the geoserver upload. instance.name = gs_name instance.workspace = workspace instance.store = values['store'] # Iterate over values from geoserver. for key in ['typename', 'store', 'storeType']: setattr(instance, key, values[key]) instance.save() if not gs_resource: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) if gs_resource: gs_resource.title = instance.title if instance.title else "" gs_resource.abstract = instance.abstract if instance.abstract else "" gs_resource.name = instance.name if instance.name else "" # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) if gs_resource: gs_resource.metadata_links = metadata_links # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if gs_resource and getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) gs_layer = gs_catalog.get_layer(instance.name) if instance.poc and instance.poc: # gsconfig now utilizes an attribution dictionary gs_layer.attribution = {'title': str(instance.poc), 'width': None, 'height': None, 'href': None, 'url': None, 'type': None} profile = Profile.objects.get(username=instance.poc.username) gs_layer.attribution_link = settings.SITEURL[ :-1] + profile.get_absolute_url() # gs_layer should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_layer) """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ if gs_resource: bbox = gs_resource.latlon_bbox # FIXME(Ariel): Correct srid setting below # self.srid = gs_resource.src instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" # Set bounding box values instance.bbox_x0 = bbox[0] instance.bbox_x1 = bbox[1] instance.bbox_y0 = bbox[2] instance.bbox_y1 = bbox[3] # store the resource to avoid another geoserver call in the post_save instance.gs_resource = gs_resource instance.save() if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return instance if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return instance if not getattr(instance, 'gs_resource', None): try: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return instance else: gs_resource = instance.gs_resource if gs_resource is None: return instance if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links( ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) gs_store_type = gs_resource.store.type.lower() if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get('geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '') if gs_store_type == 'geogig' and geogig_repo_name: repo_url = '{url}geogig/repos/{repo_name}'.format( url=ogc_server_settings.public_url, repo_name=geogig_repo_name) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html' ) ) def command_url(command): return "{repo_url}/{command}.json?{path}".format(repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html' ) ) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html' ) ) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8')) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', ) ) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', ) ) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', ) ) html_link_url = '%s%s' % ( settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', ) ) create_gs_thumbnail(instance, overwrite=False) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', ) ) ogc_wms_path = '%s/wms' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', ) ) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', ) ) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', ) ) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse( settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Define the link after the cleanup, we should use this more rather then remove # potential parasites tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8' ) link, created = Link.objects.get_or_create(resource=instance.resourcebase_ptr, extension='tiles', name="Tiles", mime='image/png', link_type='image', ) if created: Link.objects.filter(pk=link.pk).update(url=tile_url) # Save layer attributes set_attributes_from_geoserver(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 from geonode.catalogue.models import catalogue_post_save from geonode.layers.models import Layer catalogue_post_save(instance, Layer) return instance
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ if type(instance) is ResourceBase: if hasattr(instance, "layer"): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes(instance) return if not getattr(instance, "gs_resource", None): try: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return else: gs_resource = instance.gs_resource if gs_resource is None: return if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links( ogc_server_settings.public_url + "wms?", instance.typename.encode("utf-8"), instance.bbox_string, instance.srid, height, width, ) for ext, name, mime, wms_url in links: Link.objects.get_or_create( resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict(extension=ext, url=wms_url, mime=mime, link_type="image"), ) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + "wfs?", instance.typename.encode("utf-8")) for ext, name, mime, wfs_url in links: if mime == "SHAPE-ZIP": name = "Zipped Shapefile" Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict(extension=ext, name=name, mime=mime, url=wfs_url, link_type="data"), ) if ( gs_resource.store.type and gs_resource.store.type.lower() == "geogig" and gs_resource.store.connection_parameters.get("geogig_repository") ): repo_url = "{url}geogig/{geogig_repository}".format( url=ogc_server_settings.public_url, geogig_repository=gs_resource.store.connection_parameters.get("geogig_repository"), ) path = gs_resource.dom.findall("nativeName") if path: path = "path={path}".format(path=path[0].text) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension="html", name="Clone in GeoGig", mime="text/xml", link_type="html"), ) def command_url(command): return "{repo_url}/{command}.json?{path}".format(repo_url=repo_url, path=path, command=command) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=command_url("log"), defaults=dict(extension="json", name="GeoGig log", mime="application/json", link_type="html"), ) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=command_url("statistics"), defaults=dict(extension="json", name="GeoGig statistics", mime="application/json", link_type="html"), ) elif instance.storeType == "coverageStore": # FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = instance.get_all_level_info() instance.set_permissions({"users": {"AnonymousUser": ["view_resourcebase"]}}) try: # Potentially 3 dimensions can be returned by the grid if there is a z # axis. Since we only want width/height, slice to the second # dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] except GeoNodeException as e: msg = _("Could not create a download link for layer.") try: # HACK: The logger on signals throws an exception logger.warn(msg, e) except: pass else: links = wcs_links( ogc_server_settings.public_url + "wcs?", instance.typename.encode("utf-8"), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth), ) for ext, name, mime, wcs_url in links: Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict(extension=ext, name=name, mime=mime, link_type="data"), ) instance.set_permissions(permissions) kml_reflector_link_download = ( ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode({"layers": instance.typename.encode("utf-8"), "mode": "download"}) ) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict(extension="kml", name="KML", mime="text/xml", link_type="data"), ) kml_reflector_link_view = ( ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode({"layers": instance.typename.encode("utf-8"), "mode": "refresh"}) ) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict(extension="kml", name="View in Google Earth", mime="text/xml", link_type="data"), ) tile_url = ( "%sgwc/service/gmaps?" % ogc_server_settings.public_url + "layers=%s" % instance.typename.encode("utf-8") + "&zoom={z}&x={x}&y={y}" + "&format=image/png8" ) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=tile_url, defaults=dict(extension="tiles", name="Tiles", mime="image/png", link_type="image"), ) html_link_url = "%s%s" % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict(extension="html", name=instance.typename, mime="text/html", link_type="html"), ) params = {"layers": instance.typename.encode("utf-8"), "format": "image/png8", "width": 200, "height": 150} # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + "wms/reflect?" + p thumbnail_create_url = ogc_server_settings.LOCATION + "wms/reflect?" + p create_thumbnail(instance, thumbnail_remote_url, thumbnail_create_url, ogc_client=http_client) legend_url = ( ogc_server_settings.PUBLIC_LOCATION + "wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=" + instance.typename + "&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on" ) Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=legend_url, defaults=dict(extension="png", name="Legend", url=legend_url, mime="image/png", link_type="image"), ) ogc_wms_path = "%s/wms" % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = "OGC WMS: %s Service" % instance.workspace Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict(extension="html", name=ogc_wms_name, url=ogc_wms_url, mime="text/html", link_type="OGC:WMS"), ) if instance.storeType == "dataStore": ogc_wfs_path = "%s/wfs" % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = "OGC WFS: %s Service" % instance.workspace Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict(extension="html", name=ogc_wfs_name, url=ogc_wfs_url, mime="text/html", link_type="OGC:WFS"), ) if instance.storeType == "coverageStore": ogc_wcs_path = "%s/wcs" % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = "OGC WCS: %s Service" % instance.workspace Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict(extension="html", name=ogc_wcs_name, url=ogc_wcs_url, mime="text/html", link_type="OGC:WCS"), ) # remove links that belong to and old address for link in instance.link_set.all(): if ( not urlparse(settings.SITEURL).hostname == urlparse(link.url).hostname and not urlparse(ogc_server_settings.public_url).hostname == urlparse(link.url).hostname ): link.delete() # Save layer attributes set_attributes(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 from geonode.catalogue.models import catalogue_post_save from geonode.layers.models import Layer catalogue_post_save(instance, Layer)
def geoserver_post_save_local(instance, *args, **kwargs): """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ # Don't run this signal if is a Layer from a remote service if getattr(instance, "remote_service", None) is not None: return # Don't run this signal handler if it is a tile layer or a remote store (Service) # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr( instance, 'storeType') in ['tileStore', 'remoteStore']: return instance gs_resource = None values = None # If the store in None then it's a new instance from an upload, # only in this case run the geoserver_upload method if not instance.store or getattr(instance, 'overwrite', False): base_file, info = instance.get_base_file() # There is no need to process it if there is not file. if base_file is None: return gs_name, workspace, values, gs_resource = geoserver_upload( instance, base_file.file.path, instance.owner, instance.name, overwrite=True, title=instance.title, abstract=instance.abstract, # keywords=instance.keywords, charset=instance.charset) if not gs_resource: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource(instance.alternate) if gs_resource: gs_resource.title = instance.title or "" gs_resource.abstract = instance.abstract or "" gs_resource.name = instance.name or "" if not values: values = dict(store=gs_resource.store.name, storeType=gs_resource.store.resource_type, alternate=gs_resource.store.workspace.name + ':' + gs_resource.name, title=gs_resource.title or gs_resource.store.name, abstract=gs_resource.abstract or '', owner=instance.owner) else: msg = "There isn't a geoserver resource for this layer: %s" % instance.name logger.exception(msg) raise Exception(msg) # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) gs_resource.metadata_links = metadata_links # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ( 'Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg, ) logger.exception(e) gs_layer = gs_catalog.get_layer(instance.name) if not gs_layer: gs_layer = gs_catalog.get_layer(instance.alternate) if gs_layer and instance.poc: # gsconfig now utilizes an attribution dictionary gs_layer.attribution = { 'title': str(instance.poc), 'width': None, 'height': None, 'href': None, 'url': None, 'type': None } profile = Profile.objects.get(username=instance.poc.username) gs_layer.attribution_link = settings.SITEURL[: -1] + profile.get_absolute_url( ) # gs_layer should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_layer) except geoserver.catalog.FailedRequestError as e: msg = ( 'Error while trying to save layer named %s in GeoServer, ' 'try to use: "%s"' % (gs_layer, str(e))) e.args = (msg, ) logger.exception(e) if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ # instance.name = instance.name or gs_layer.name # instance.title = instance.title or gs_resource.title instance.abstract = gs_resource.abstract or '' instance.workspace = gs_resource.store.workspace.name instance.store = gs_resource.store.name bbox = gs_resource.native_bbox # Set bounding box values instance.bbox_x0 = bbox[0] instance.bbox_x1 = bbox[1] instance.bbox_y0 = bbox[2] instance.bbox_y1 = bbox[3] instance.srid = bbox[4] if instance.srid: instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" else: raise GeoNodeException("Invalid Projection. Layer is missing CRS!") # Iterate over values from geoserver. for key in ['alternate', 'store', 'storeType']: # attr_name = key if 'typename' not in key else 'alternate' # print attr_name setattr(instance, key, values[key]) if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = 'true' if instance.is_published else 'false' gs_catalog.save(gs_resource) if not settings.FREETEXT_KEYWORDS_READONLY: if gs_resource.keywords: for keyword in gs_resource.keywords: if keyword not in instance.keyword_list(): instance.keywords.add(keyword) if any(instance.keyword_list()): keywords = instance.keyword_list() gs_resource.keywords = list(set(keywords)) # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ( 'Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg, ) logger.exception(e) to_update = { 'title': instance.title or instance.name, 'abstract': instance.abstract or "", 'alternate': instance.alternate, 'bbox_x0': instance.bbox_x0, 'bbox_x1': instance.bbox_x1, 'bbox_y0': instance.bbox_y0, 'bbox_y1': instance.bbox_y1, 'srid': instance.srid } # Update ResourceBase resources = ResourceBase.objects.filter(id=instance.resourcebase_ptr.id) resources.update(**to_update) # to_update['name'] = instance.name, to_update['workspace'] = instance.workspace to_update['store'] = instance.store to_update['storeType'] = instance.storeType to_update['typename'] = instance.alternate # Save all the modified information in the instance without triggering signals. Layer.objects.filter(id=instance.id).update(**to_update) # Refresh from DB instance.refresh_from_db() # store the resource to avoid another geoserver call in the post_save instance.gs_resource = gs_resource bbox = gs_resource.native_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.alternate.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.alternate.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) gs_store_type = gs_resource.store.type.lower( ) if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get( 'geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '') if gs_store_type == 'geogig' and geogig_repo_name: repo_url = '{url}geogig/repos/{repo_name}'.format( url=ogc_server_settings.public_url, repo_name=geogig_repo_name) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html')) def command_url(command): return "{repo_url}/{command}.json?{path}".format( repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html')) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html')) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.alternate.encode('utf-8'), ','.join(str(x) for x in instance.bbox[0:4]), instance.srid) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.alternate.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.alternate.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.alternate, mime='text/html', link_type='html', )) # some thumbnail generators will update thumbnail_url. If so, don't # immediately re-generate the thumbnail here. use layer#save(update_fields=['thumbnail_url']) if not ('update_fields' in kwargs and kwargs['update_fields'] is not None and 'thumbnail_url' in kwargs['update_fields']): logger.info("Creating Thumbnail for Layer [%s]" % (instance.alternate)) create_gs_thumbnail(instance, overwrite=True) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.alternate + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', )) ogc_wms_path = '%s/ows' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Define the link after the cleanup, we should use this more rather then remove # potential parasites tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.alternate.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') link, created = Link.objects.get_or_create( resource=instance.resourcebase_ptr, extension='tiles', name="Tiles", mime='image/png', link_type='image', ) if created: Link.objects.filter(pk=link.pk).update(url=tile_url) # Save layer attributes set_attributes_from_geoserver(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 catalogue_post_save(instance, Layer)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ url = ogc_server_settings.internal_rest try: gs_resource = gs_catalog.get_resource(instance.name) except (FailedRequestError, EnvironmentError) as e: msg = ('Could not connect to geoserver at "%s"' 'to save information for layer "%s"' % (ogc_server_settings.LOCATION, instance.name.encode('utf-8'))) logger.warn(msg, e) # If geoserver is not online, there is no need to continue return # If there is no resource returned it could mean one of two things: # a) There is a synchronization problem in geoserver # b) The unit tests are running and another geoserver is running in the # background. # For both cases it is sensible to stop processing the layer if gs_resource is None: logger.warn('Could not get geoserver resource for %s' % instance) return gs_resource.keywords = instance.keyword_list() #gs_resource should only be called if ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) elif instance.storeType == 'coverageStore': #FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = {} permissions['anonymous'] = instance.get_gen_level(ANONYMOUS_USERS) permissions['authenticated'] = instance.get_gen_level( AUTHENTICATED_USERS) instance.set_gen_level(ANONYMOUS_USERS, 'layer_readonly') #Potentially 3 dimensions can be returned by the grid if there is a z #axis. Since we only want width/height, slice to the second dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) instance.set_gen_level(ANONYMOUS_USERS, permissions['anonymous']) instance.set_gen_level(AUTHENTICATED_USERS, permissions['authenticated']) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode( { 'layers': instance.typename.encode('utf-8'), 'mode': "download" }) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name=_("KML"), mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + urllib.urlencode( { 'layers': instance.typename.encode('utf-8'), 'mode': "refresh" }) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name=_("Tiles"), mime='image/png', link_type='image', )) wms_path = '%s/%s/wms' % (instance.workspace, instance.name) ows_url = urljoin(ogc_server_settings.public_url, wms_path) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ows_url, defaults=dict( extension='html', name=_("OWS"), url=ows_url, mime='text/html', link_type='OGC:WMS', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', )) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_url = ogc_server_settings.LOCATION + "wms/reflect?" + p Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=thumbnail_url, defaults=dict( extension='png', name=_("Remote Thumbnail"), mime='image/png', link_type='image', )) # Download thumbnail and save it locally. resp, image = http_client.request(thumbnail_url) if 'ServiceException' in image or resp.status < 200 or resp.status > 299: msg = 'Unable to obtain thumbnail: %s' % image logger.debug(msg) # Replace error message with None. image = None if image is not None: #Clean any orphan Thumbnail before Thumbnail.objects.filter(resourcebase__id=None).delete() thumbnail, created = Thumbnail.objects.get_or_create( resourcebase__id=instance.id) thumbnail.thumb_spec = thumbnail_url thumbnail.save_thumb(image, instance._thumbnail_path()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=settings.SITEURL + instance._thumbnail_path(), defaults=dict( extension='png', name=_("Thumbnail"), mime='image/png', link_type='image', )) ogc_wms_url = ogc_server_settings.public_url + 'wms?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=instance.name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_url = ogc_server_settings.public_url + 'wfs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_url = ogc_server_settings.public_url + 'wcs?' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=instance.name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) #remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse(link.url).hostname and not \ urlparse(ogc_server_settings.public_url).hostname == urlparse(link.url).hostname: link.delete() #Save layer attributes set_attributes(instance) #Save layer styles set_styles(instance, gs_catalog)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ url = ogc_server_settings.internal_rest try: gs_resource = gs_catalog.get_resource(instance.name) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links( ogc_server_settings.public_url + "wms?", instance.typename.encode("utf-8"), instance.bbox_string, instance.srid, height, width, ) for ext, name, mime, wms_url in links: Link.objects.get_or_create( resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict(extension=ext, url=wms_url, mime=mime, link_type="image"), ) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + "wfs?", instance.typename.encode("utf-8")) for ext, name, mime, wfs_url in links: if mime == "SHAPE-ZIP": name = "Zipped Shapefile" Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict(extension=ext, name=name, mime=mime, url=wfs_url, link_type="data"), ) elif instance.storeType == "coverageStore": # FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = {} permissions["anonymous"] = instance.get_gen_level(ANONYMOUS_USERS) permissions["authenticated"] = instance.get_gen_level(AUTHENTICATED_USERS) instance.set_gen_level(ANONYMOUS_USERS, "layer_readonly") try: # Potentially 3 dimensions can be returned by the grid if there is a z # axis. Since we only want width/height, slice to the second dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] except GeoNodeException, e: msg = _("Could not create a download link for layer.") logger.warn(msg, e) else: links = wcs_links( ogc_server_settings.public_url + "wcs?", instance.typename.encode("utf-8"), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth), ) for ext, name, mime, wcs_url in links: Link.objects.get_or_create( resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict(extension=ext, name=name, mime=mime, link_type="data"), ) instance.set_gen_level(ANONYMOUS_USERS, permissions["anonymous"]) instance.set_gen_level(AUTHENTICATED_USERS, permissions["authenticated"])
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ # Don't run this signal handler if it is a tile layer # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr(instance, 'storeType') == 'tileStore': return if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return if not getattr(instance, 'gs_resource', None): try: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return else: gs_resource = instance.gs_resource if gs_resource is None: return if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) gs_store_type = gs_resource.store.type.lower( ) if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get( 'geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '') if gs_store_type == 'geogig' and geogig_repo_name: repo_url = '{url}geogig/repos/{repo_name}'.format( url=ogc_server_settings.public_url, repo_name=geogig_repo_name) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html')) def command_url(command): return "{repo_url}/{command}.json?{path}".format( repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html')) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html')) elif instance.storeType == 'coverageStore': links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8')) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name="KML", mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', )) create_gs_thumbnail(instance, overwrite=True) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name='Legend', url=legend_url, mime='image/png', link_type='image', )) ogc_wms_path = '%s/wms' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Define the link after the cleanup, we should use this more rather then remove # potential parasites tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') link, created = Link.objects.get_or_create( resource=instance.resourcebase_ptr, extension='tiles', name="Tiles", mime='image/png', link_type='image', ) if created: Link.objects.filter(pk=link.pk).update(url=tile_url) # Save layer attributes set_attributes_from_geoserver(instance) # Save layer styles set_styles(instance, gs_catalog) # NOTTODO by simod: we should not do this! # need to be removed when fixing #2015 from geonode.catalogue.models import catalogue_post_save from geonode.layers.models import Layer catalogue_post_save(instance, Layer)
def geoserver_post_save(instance, sender, **kwargs): """Save keywords to GeoServer The way keywords are implemented requires the layer to be saved to the database before accessing them. """ if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes(instance) return try: gs_resource = gs_catalog.get_resource(instance.name, store=instance.store, workspace=instance.workspace) except socket_error as serr: if serr.errno != errno.ECONNREFUSED: # Not the error we are looking for, re-raise raise serr # If the connection is refused, take it easy. return if gs_resource is None: return if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = instance.is_published gs_catalog.save(gs_resource) if any(instance.keyword_list()): gs_resource.keywords = instance.keyword_list() # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_catalog.save(gs_resource) bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.typename.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', )) if instance.storeType == "dataStore": links = wfs_links(ogc_server_settings.public_url + 'wfs?', instance.typename.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', )) if gs_resource.store.type and gs_resource.store.type.lower() == 'geogig' and \ gs_resource.store.connection_parameters.get('geogig_repository'): repo_url = '{url}geogig/{geogig_repository}'.format( url=ogc_server_settings.public_url, geogig_repository=gs_resource.store.connection_parameters.get( 'geogig_repository')) path = gs_resource.dom.findall('nativeName') if path: path = 'path={path}'.format(path=path[0].text) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=repo_url, defaults=dict(extension='html', name='Clone in GeoGig', mime='text/xml', link_type='html')) command_url = lambda command: "{repo_url}/{command}.json?{path}".format( repo_url=repo_url, path=path, command=command) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('log'), defaults=dict(extension='json', name='GeoGig log', mime='application/json', link_type='html')) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=command_url('statistics'), defaults=dict(extension='json', name='GeoGig statistics', mime='application/json', link_type='html')) elif instance.storeType == 'coverageStore': # FIXME(Ariel): This works for public layers, does it work for restricted too? # would those end up with no geotiff links, like, forever? permissions = instance.get_all_level_info() instance.set_permissions( {'users': { 'AnonymousUser': ['view_resourcebase'] }}) try: # Potentially 3 dimensions can be returned by the grid if there is a z # axis. Since we only want width/height, slice to the second # dimension covWidth, covHeight = get_coverage_grid_extent(instance)[:2] except GeoNodeException as e: msg = _('Could not create a download link for layer.') logger.warn(msg, e) else: links = wcs_links(ogc_server_settings.public_url + 'wcs?', instance.typename.encode('utf-8'), bbox=gs_resource.native_bbox[:-1], crs=gs_resource.native_bbox[-1], height=str(covHeight), width=str(covWidth)) for ext, name, mime, wcs_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wcs_url, defaults=dict( extension=ext, name=name, mime=mime, link_type='data', )) instance.set_permissions(permissions) kml_reflector_link_download = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "download"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_download, defaults=dict( extension='kml', name=_("KML"), mime='text/xml', link_type='data', )) kml_reflector_link_view = ogc_server_settings.public_url + "wms/kml?" + \ urllib.urlencode({'layers': instance.typename.encode('utf-8'), 'mode': "refresh"}) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=kml_reflector_link_view, defaults=dict( extension='kml', name="View in Google Earth", mime='text/xml', link_type='data', )) tile_url = ('%sgwc/service/gmaps?' % ogc_server_settings.public_url + 'layers=%s' % instance.typename.encode('utf-8') + '&zoom={z}&x={x}&y={y}' + '&format=image/png8') Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=tile_url, defaults=dict( extension='tiles', name=_("Tiles"), mime='image/png', link_type='image', )) html_link_url = '%s%s' % (settings.SITEURL[:-1], instance.get_absolute_url()) Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=html_link_url, defaults=dict( extension='html', name=instance.typename, mime='text/html', link_type='html', )) params = { 'layers': instance.typename.encode('utf-8'), 'format': 'image/png8', 'width': 200, 'height': 150, } # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. p = "&".join("%s=%s" % item for item in params.items()) thumbnail_remote_url = ogc_server_settings.PUBLIC_LOCATION + \ "wms/reflect?" + p thumbnail_create_url = ogc_server_settings.LOCATION + \ "wms/reflect?" + p create_thumbnail(instance, thumbnail_remote_url, thumbnail_create_url, ogc_client=http_client) legend_url = ogc_server_settings.PUBLIC_LOCATION + \ 'wms?request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \ instance.typename + '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=legend_url, defaults=dict( extension='png', name=_('Legend'), url=legend_url, mime='image/png', link_type='image', )) ogc_wms_path = '%s/wms' % instance.workspace ogc_wms_url = urljoin(ogc_server_settings.public_url, ogc_wms_path) ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wms_url, defaults=dict( extension='html', name=ogc_wms_name, url=ogc_wms_url, mime='text/html', link_type='OGC:WMS', )) if instance.storeType == "dataStore": ogc_wfs_path = '%s/wfs' % instance.workspace ogc_wfs_url = urljoin(ogc_server_settings.public_url, ogc_wfs_path) ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wfs_url, defaults=dict( extension='html', name=ogc_wfs_name, url=ogc_wfs_url, mime='text/html', link_type='OGC:WFS', )) if instance.storeType == "coverageStore": ogc_wcs_path = '%s/wcs' % instance.workspace ogc_wcs_url = urljoin(ogc_server_settings.public_url, ogc_wcs_path) ogc_wcs_name = 'OGC WCS: %s Service' % instance.workspace Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=ogc_wcs_url, defaults=dict( extension='html', name=ogc_wcs_name, url=ogc_wcs_url, mime='text/html', link_type='OGC:WCS', )) # remove links that belong to and old address for link in instance.link_set.all(): if not urlparse(settings.SITEURL).hostname == urlparse( link.url).hostname and not urlparse( ogc_server_settings.public_url).hostname == urlparse( link.url).hostname: link.delete() # Save layer attributes set_attributes(instance) # Save layer styles set_styles(instance, gs_catalog)
def geoserver_post_save_local(layer_id, *args, **kwargs): """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ # If it is a layer object, post process it. If not, abort. try: instance = Layer.objects.get(id=layer_id) except Layer.DoesNotExist as e: logger.exception(e) return # raise e # Don't run this signal if is a Layer from a remote service if getattr(instance, "service", None) is not None: return # Don't run this signal handler if it is a tile layer or a remote store (Service) # Currently only gpkg files containing tiles will have this type & will be served via MapProxy. if hasattr(instance, 'storeType') and getattr(instance, 'storeType') in ['tileStore', 'remoteStore']: return instance gs_resource = None values = None # If the store in None then it's a new instance from an upload, # only in this case run the geoserver_upload method if not instance.store or getattr(instance, 'overwrite', False): base_file, info = instance.get_base_file() # There is no need to process it if there is not file. if base_file is None: return gs_name, workspace, values, gs_resource = geoserver_upload(instance, base_file.file.path, instance.owner, instance.name, overwrite=True, title=instance.title, abstract=instance.abstract, # keywords=instance.keywords, charset=instance.charset) if not gs_resource: gs_resource = gs_catalog.get_resource( instance.name, store=instance.store, workspace=instance.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource(instance.alternate) if gs_resource: gs_resource.title = instance.title or "" gs_resource.abstract = instance.abstract or "" gs_resource.name = instance.name or "" if not values: values = dict(store=gs_resource.store.name, storeType=gs_resource.store.resource_type, alternate=gs_resource.store.workspace.name + ':' + gs_resource.name, title=gs_resource.title or gs_resource.store.name, abstract=gs_resource.abstract or '', owner=instance.owner) else: return # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) gs_resource.metadata_links = metadata_links # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg,) logger.exception(e) gs_layer = gs_catalog.get_layer(instance.name) if not gs_layer: gs_layer = gs_catalog.get_layer(instance.alternate) if gs_layer and instance.poc: # gsconfig now utilizes an attribution dictionary gs_layer.attribution = {'title': str(instance.poc), 'width': None, 'height': None, 'href': None, 'url': None, 'type': None} profile = Profile.objects.get(username=instance.poc.username) gs_layer.attribution_link = settings.SITEURL[ :-1] + profile.get_absolute_url() # gs_layer should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_layer) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save layer named %s in GeoServer, ' 'try to use: "%s"' % (gs_layer, str(e))) e.args = (msg,) logger.exception(e) if type(instance) is ResourceBase: if hasattr(instance, 'layer'): instance = instance.layer else: return if instance.storeType == "remoteStore": # Save layer attributes set_attributes_from_geoserver(instance) return """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ # instance.name = instance.name or gs_layer.name # instance.title = instance.title or gs_resource.title instance.abstract = gs_resource.abstract or '' instance.workspace = gs_resource.store.workspace.name instance.store = gs_resource.store.name bbox = gs_resource.latlon_bbox # FIXME(Ariel): Correct srid setting below # self.srid = gs_resource.src instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" # Set bounding box values instance.bbox_x0 = bbox[0] instance.bbox_x1 = bbox[1] instance.bbox_y0 = bbox[2] instance.bbox_y1 = bbox[3] # Iterate over values from geoserver. for key in ['alternate', 'store', 'storeType']: # attr_name = key if 'typename' not in key else 'alternate' # print attr_name setattr(instance, key, values[key]) if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = 'true' if instance.is_published else 'false' gs_catalog.save(gs_resource) if not settings.FREETEXT_KEYWORDS_READONLY: if gs_resource.keywords: for keyword in gs_resource.keywords: instance.keywords.add(keyword) if any(instance.keyword_list()): keywords = instance.keyword_list() if settings.FREETEXT_KEYWORDS_READONLY: if gs_resource.keywords: keywords += gs_resource.keywords gs_resource.keywords = list(set(keywords)) # gs_resource should only be called if # ogc_server_settings.BACKEND_WRITE_ENABLED == True if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): try: gs_catalog.save(gs_resource) except geoserver.catalog.FailedRequestError as e: msg = ('Error while trying to save resource named %s in GeoServer, ' 'try to use: "%s"' % (gs_resource, str(e))) e.args = (msg,) logger.exception(e) to_update = { 'title': instance.title or instance.name, 'abstract': instance.abstract or "", 'alternate': instance.alternate, 'bbox_x0': instance.bbox_x0, 'bbox_x1': instance.bbox_x1, 'bbox_y0': instance.bbox_y0, 'bbox_y1': instance.bbox_y1 } # Update ResourceBase resources = ResourceBase.objects.filter(id=instance.resourcebase_ptr.id) resources.update(**to_update) # to_update['name'] = instance.name, to_update['workspace'] = instance.workspace to_update['store'] = instance.store to_update['storeType'] = instance.storeType to_update['typename'] = instance.alternate # Save all the modified information in the instance without triggering signals. Layer.objects.filter(id=instance.id).update(**to_update) # Refresh from DB instance.refresh_from_db() # store the resource to avoid another geoserver call in the post_save instance.gs_resource = gs_resource bbox = gs_resource.latlon_bbox dx = float(bbox[1]) - float(bbox[0]) dy = float(bbox[3]) - float(bbox[2]) dataAspect = 1 if dy == 0 else dx / dy height = 550 width = int(height * dataAspect) # Set download links for WMS, WCS or WFS and KML links = wms_links(ogc_server_settings.public_url + 'wms?', instance.alternate.encode('utf-8'), instance.bbox_string, instance.srid, height, width) for ext, name, mime, wms_url in links: Link.objects.get_or_create(resource=instance.resourcebase_ptr, name=ugettext(name), defaults=dict( extension=ext, url=wms_url, mime=mime, link_type='image', ) ) if instance.storeType == "dataStore": links = wfs_links( ogc_server_settings.public_url + 'wfs?', instance.alternate.encode('utf-8')) for ext, name, mime, wfs_url in links: if mime == 'SHAPE-ZIP': name = 'Zipped Shapefile' Link.objects.get_or_create(resource=instance.resourcebase_ptr, url=wfs_url, defaults=dict( extension=ext, name=name, mime=mime, url=wfs_url, link_type='data', ) ) gs_store_type = gs_resource.store.type.lower() if gs_resource.store.type else None geogig_repository = gs_resource.store.connection_parameters.get('geogig_repository', '') geogig_repo_name = geogig_repository.replace('geoserver://', '')