def delete_attribute(request): if request.method == 'POST': layer_name = request.POST.get('layer_name', None) attribute_name = request.POST.get('attribute_name', None) # 1. Delete attribute Process connection_string = create_connection_string() lam = LayerAttributeManager(connection_string) # try: lam.delete_attribute(str(layer_name), str(attribute_name)) # except Exception as e: # print('Error while deleteing attribute!', e) # json_response = {"status": False, # "message": "Error while deleting attribute!"} # return JsonResponse(json_response, status=500) # 2. Recalculate attributes in GeoServer recalculate_geoserver_layer_attributes(layer_name, attrs=[attribute_name]) # TODO: find another solution hence this will affect the other processes in the same time! # TODO: Refresh geoserver could be a less frequent process, so it is okay to keep that way, however an that handles reset and reload geoserver catalog will be great! # Refresh and reset geoserver datastores! refresh_geoserver() # 3. Set Attributes in GeoNode layer = Layer.objects.get(name=layer_name) set_attributes_from_geoserver(layer, overwrite=True) return JsonResponse({'success': True}, status=200)
def attributes_sats_refresh(request): from geonode.geoserver.helpers import set_attributes_from_geoserver uuid = request.POST['uuid'] resource = get_object_or_404(ResourceBase, uuid=uuid) can_change_data = request.user.has_perm('change_resourcebase', resource) layer = Layer.objects.get(id=resource.id) if layer and can_change_data: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) return HttpResponse(json.dumps({ 'success': 'ok', 'message': 'Attributes/Stats Refreshed Successfully!' }), status=200, content_type='text/plain') else: return HttpResponse(json.dumps({ 'success': 'false', 'message': 'You cannot modify this resource!' }), status=200, content_type='text/plain')
def test_set_attributes_from_geoserver(self): """Test attributes syncronization """ # upload a shapefile shp_file = os.path.join( gisdata.VECTOR_DATA, 'san_andres_y_providencia_poi.shp') layer = file_upload(shp_file) # set attributes for resource for attribute in layer.attribute_set.all(): attribute.attribute_label = '%s_label' % attribute.attribute attribute.description = '%s_description' % attribute.attribute attribute.save() # sync the attributes with GeoServer set_attributes_from_geoserver(layer) # tests if everything is synced properly for attribute in layer.attribute_set.all(): self.assertEquals( attribute.attribute_label, '%s_label' % attribute.attribute ) self.assertEquals( attribute.description, '%s_description' % attribute.attribute )
def sync_geonode_layers(ignore_errors, filter, username): layers = Layer.objects.all().order_by('name') if filter: layers = layers.filter(name__icontains=filter) if username: layers = layers.filter(owner__username=username) layers_count = layers.count() count = 0 layer_errors = [] for layer in layers: try: count += 1 print 'Syncing layer %s/%s: %s' % (count, layers_count, layer.name) # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) layer.set_permissions(perm_spec) # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) layer.save() except Exception: layer_errors.append(layer.alternate) exception_type, error, traceback = sys.exc_info() print exception_type, error, traceback if ignore_errors: pass else: print 'Stopping process because --ignore-errors was not set and an error was found.' return print 'There are %s layers which could not be updated because of errors' % len( layer_errors) for layer_error in layer_errors: print layer_error
def sync_geonode_layers(ignore_errors, filter, username): layers = Layer.objects.all().order_by('name') if filter: layers = layers.filter(name__icontains=filter) if username: layers = layers.filter(owner__username=username) layers_count = layers.count() count = 0 layer_errors = [] for layer in layers: try: count += 1 print 'Syncing layer %s/%s: %s' % (count, layers_count, layer.name) # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) layer.set_permissions(perm_spec) # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) layer.save() except Exception: layer_errors.append(layer.alternate) exception_type, error, traceback = sys.exc_info() print exception_type, error, traceback if ignore_errors: pass else: print 'Stopping process because --ignore-errors was not set and an error was found.' return print 'There are %s layers which could not be updated because of errors' % len(layer_errors) for layer_error in layer_errors: print layer_error
def test_logic(request): connection_string = create_connection_string() lam = LayerAttributeManager(connection_string) layer_name = 'b6' attributes = lam.get_attributes(layer_name=layer_name) index = lam.add_attribute( layer_name, 'test_string', 4, ) index = lam.add_attribute( layer_name, 'test_real', 2, ) index = lam.add_attribute( layer_name, 'test_integer', 0, ) recalculate_geoserver_layer_attributes(layer_name) layer = Layer.objects.get(name=layer_name) set_attributes_from_geoserver(layer, overwrite=True) return render(request, template_name="%s/index.html" % APP_NAME, context={ 'message': 'Hello from %s' % APP_NAME, 'app_name': APP_NAME })
def publish(self, layername): resource = gs_catalog.get_resource(layername, store=self.store, workspace=self.workspace) if not resource: raise Exception("Cannot Find Layer In Geoserver") name = resource.name logger.error(resource.__dict__) the_store = resource.store workspace = the_store.workspace layer = None try: logger.warning("=========> Creating the Layer in Django") layer, created = Layer.objects.get_or_create( name=name, workspace=workspace.name, defaults={ "store": the_store.name, "storeType": the_store.resource_type, "alternate": "%s:%s" % (workspace.name, resource.name), "title": (resource.title or 'No title provided'), "abstract": (resource.abstract or _('No abstract provided')), "owner": self.owner, "uuid": str(uuid.uuid4()), "bbox_x0": Decimal(resource.native_bbox[0]), "bbox_x1": Decimal(resource.native_bbox[1]), "bbox_y0": Decimal(resource.native_bbox[2]), "bbox_y1": Decimal(resource.native_bbox[3]), "srid": resource.projection }) logger.warning("=========> Settting permissions") # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) layer.set_permissions(perm_spec) logger.warning("=========> Settting Attributes") # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) layer.save() logger.warning("=========> Fixing Metadata Links") # Fix metadata links if the ip has changed if layer.link_set.metadata().count() > 0: if not created and settings.SITEURL \ not in layer.link_set.metadata()[0].url: layer.link_set.metadata().delete() layer.save() metadata_links = [] for link in layer.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) resource.metadata_links = metadata_links gs_catalog.save(resource) except Exception as e: logger.error(e.message) exception_type, error, traceback = sys.exc_info() else: if layer: layer.set_default_permissions() return layer
def sync_geonode_layers(ignore_errors, filter, username, removeduplicates, updatepermissions, updatethumbnails, updateattributes, updatebbox): layers = Layer.objects.all().order_by('name') if filter: layers = layers.filter(name__icontains=filter) if username: layers = layers.filter(owner__username=username) layers_count = layers.count() count = 0 layer_errors = [] for layer in layers: try: count += 1 print(f"Syncing layer {count}/{layers_count}: {layer.name}") if updatepermissions: print("Syncing permissions...") # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) # re-sync GeoFence security rules layer.set_permissions(perm_spec) if updateattributes: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) if updatethumbnails: print("Regenerating thumbnails...") create_gs_thumbnail(layer, overwrite=True, check_bbox=False) if removeduplicates: # remove duplicates print("Removing duplicate links...") remove_duplicate_links(layer) if updatebbox: print("Regenerating BBOX...") sync_instance_with_geoserver(layer.id, updatemetadata=False, updatebbox=True) except (Exception, RuntimeError): layer_errors.append(layer.alternate) exception_type, error, traceback = sys.exc_info() print(exception_type, error, traceback) if ignore_errors: pass else: import traceback traceback.print_exc() print("Stopping process because --ignore-errors was not set and an error was found.") return print(f"There are {len(layer_errors)} layers which could not be updated because of errors") for layer_error in layer_errors: print(layer_error)
def sync_geonode_layers(ignore_errors, filter, username, updatepermissions, updatethumbnails, updateattributes): layers = Layer.objects.all().order_by('name') if filter: layers = layers.filter(name__icontains=filter) if username: layers = layers.filter(owner__username=username) layers_count = layers.count() count = 0 layer_errors = [] for layer in layers: try: count += 1 print("Syncing layer {}/{}: {}".format(count, layers_count, layer.name)) if updatepermissions: print("Syncing permissions...") # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) # re-sync GeoFence security rules layer.set_permissions(perm_spec) if updateattributes: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) if updatethumbnails: print("Regenerating thumbnails...") layer.save() except Exception: layer_errors.append(layer.alternate) exception_type, error, traceback = sys.exc_info() print(exception_type, error, traceback) if ignore_errors: pass else: import traceback traceback.print_exc() print( "Stopping process because --ignore-errors was not set and an error was found." ) return print("There are {} layers which could not be updated because of errors". format(len(layer_errors))) for layer_error in layer_errors: print(layer_error)
def test_set_attributes_from_geoserver(self): """Test attributes syncronization """ # upload a shapefile shp_file = os.path.join( gisdata.VECTOR_DATA, 'san_andres_y_providencia_poi.shp') layer = file_upload(shp_file) try: # set attributes for resource for attribute in layer.attribute_set.all(): attribute.attribute_label = '%s_label' % attribute.attribute attribute.description = '%s_description' % attribute.attribute attribute.save() # sync the attributes with GeoServer set_attributes_from_geoserver(layer) # tests if everything is synced properly for attribute in layer.attribute_set.all(): self.assertEqual( attribute.attribute_label, '%s_label' % attribute.attribute ) self.assertEqual( attribute.description, '%s_description' % attribute.attribute ) links = Link.objects.filter(resource=layer.resourcebase_ptr) self.assertIsNotNone(links) self.assertTrue(len(links) > 7) original_data_links = [ll for ll in links if 'original' == ll.link_type] self.assertEqual(len(original_data_links), 1) resp = self.client.get(original_data_links[0].url) self.assertEqual(resp.status_code, 200) finally: # Clean up and completely delete the layers layer.delete()
def _create_layer(self, geonode_service, **resource_fields): # bear in mind that in ``geonode.layers.models`` there is a # ``pre_save_layer`` function handler that is connected to the # ``pre_save`` signal for the Layer model. This handler does a check # for common fields (such as abstract and title) and adds # sensible default values keywords = resource_fields.pop("keywords") or [] geonode_layer = Layer(owner=geonode_service.owner, remote_service=geonode_service, uuid=str(uuid4()), **resource_fields) geonode_layer.full_clean() try: geonode_layer.save(notify=True) except Exception as e: logger.error(e) geonode_layer.keywords.add(*keywords) geonode_layer.set_default_permissions() set_attributes_from_geoserver(geonode_layer) return geonode_layer
def attributes_sats_refresh(request): from geonode.geoserver.helpers import set_attributes_from_geoserver uuid = request.POST['uuid'] resource = get_object_or_404(ResourceBase, uuid=uuid) can_change_data = request.user.has_perm( 'change_resourcebase', resource) layer = Layer.objects.get(id=resource.id) if layer and can_change_data: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) return HttpResponse( json.dumps({'success': 'ok', 'message': 'Attributes/Stats Refreshed Successfully!'}), status=200, content_type='text/plain' ) else: return HttpResponse( json.dumps({'success': 'false', 'message': 'You cannot modify this resource!'}), status=200, content_type='text/plain' )
def test_set_attributes_from_geoserver(self): """Test attributes syncronization """ layer = Layer.objects.all().first() create_layer_data(layer.resourcebase_ptr_id) try: # set attributes for resource for attribute in layer.attribute_set.all(): attribute.attribute_label = f'{attribute.attribute}_label' attribute.description = f'{attribute.attribute}_description' attribute.save() # tests if everything is synced properly for attribute in layer.attribute_set.all(): self.assertEqual( attribute.attribute_label, f'{attribute.attribute}_label' ) self.assertEqual( attribute.description, f'{attribute.attribute}_description' ) # sync the attributes with GeoServer # since on geoserver are empty, we expect that now the layer # does not have any attribute set_attributes_from_geoserver(layer) links = Link.objects.filter(resource=layer.resourcebase_ptr) self.assertIsNotNone(links) self.assertTrue(len(links) >= 7) original_data_links = [ll for ll in links if 'original' == ll.link_type] self.assertEqual(len(original_data_links), 0) finally: # Clean up and completely delete the layers layer.delete()
def _create_layer(self, geonode_service, **resource_fields): # bear in mind that in ``geonode.layers.models`` there is a # ``pre_save_layer`` function handler that is connected to the # ``pre_save`` signal for the Layer model. This handler does a check # for common fields (such as abstract and title) and adds # sensible default values keywords = resource_fields.pop("keywords") or [] geonode_layer = Layer( owner=geonode_service.owner, remote_service=geonode_service, uuid=str(uuid4()), **resource_fields ) srid = geonode_layer.srid bbox_polygon = geonode_layer.bbox_polygon geonode_layer.full_clean() geonode_layer.save(notify=True) geonode_layer.keywords.add(*keywords) geonode_layer.set_default_permissions() try: set_attributes_from_geoserver(geonode_layer) except Exception as e: logger.error(e) if bbox_polygon and srid: try: # Dealing with the BBOX: this is a trick to let GeoDjango storing original coordinates Layer.objects.filter(id=geonode_layer.id).update( bbox_polygon=bbox_polygon, srid='EPSG:4326') match = re.match(r'^(EPSG:)?(?P<srid>\d{4,6})$', str(srid)) bbox_polygon.srid = int(match.group('srid')) if match else 4326 Layer.objects.filter(id=geonode_layer.id).update( ll_bbox_polygon=bbox_polygon, srid=srid) except Exception as e: logger.error(e) # Refresh from DB geonode_layer.refresh_from_db() return geonode_layer
def test_save_and_delete_signals(self): """Test that GeoServer Signals methods work as espected""" layers = Layer.objects.all()[:2].values_list('id', flat=True) test_perm_layer = Layer.objects.get(id=layers[0]) self.client.login(username='******', password='******') if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.signals import (geoserver_pre_delete, geoserver_post_save, geoserver_post_save_local) # Handle Layer Save and Upload Signals geoserver_post_save(test_perm_layer, sender=Layer) geoserver_post_save_local(test_perm_layer) # Check instance bbox and links self.assertIsNotNone(test_perm_layer.bbox) self.assertIsNotNone(test_perm_layer.srid) self.assertIsNotNone(test_perm_layer.link_set) self.assertEquals(len(test_perm_layer.link_set.all()), 7) # Layer Manipulation from geonode.geoserver.upload import geoserver_upload from geonode.geoserver.signals import gs_catalog from geonode.geoserver.helpers import ( check_geoserver_is_up, get_sld_for, fixup_style, set_layer_style, get_store, set_attributes_from_geoserver, set_styles, create_gs_thumbnail, cleanup) check_geoserver_is_up() admin_user = get_user_model().objects.get(username="******") saved_layer = geoserver_upload( test_perm_layer, os.path.join(gisdata.VECTOR_DATA, "san_andres_y_providencia_poi.shp"), admin_user, test_perm_layer.name, overwrite=True) self.assertIsNotNone(saved_layer) _log(saved_layer) workspace, name = test_perm_layer.alternate.split(':') self.assertIsNotNone(workspace) self.assertIsNotNone(name) ws = gs_catalog.get_workspace(workspace) self.assertIsNotNone(ws) store = get_store(gs_catalog, name, workspace=ws) _log("1. ------------ %s " % store) self.assertIsNotNone(store) # Save layer attributes set_attributes_from_geoserver(test_perm_layer) # Save layer styles set_styles(test_perm_layer, gs_catalog) # set SLD sld = test_perm_layer.default_style.sld_body if test_perm_layer.default_style else None if sld: _log("2. ------------ %s " % sld) set_layer_style(test_perm_layer, test_perm_layer.alternate, sld) fixup_style(gs_catalog, test_perm_layer.alternate, None) self.assertIsNone(get_sld_for(gs_catalog, test_perm_layer)) _log("3. ------------ %s " % get_sld_for(gs_catalog, test_perm_layer)) create_gs_thumbnail(test_perm_layer, overwrite=True) self.assertIsNotNone(test_perm_layer.get_thumbnail_url()) self.assertTrue(test_perm_layer.has_thumbnail()) # Handle Layer Delete Signals geoserver_pre_delete(test_perm_layer, sender=Layer) # Check instance has been removed from GeoServer also from geonode.geoserver.views import get_layer_capabilities self.assertIsNone(get_layer_capabilities(test_perm_layer)) # Cleaning Up test_perm_layer.delete() cleanup(test_perm_layer.name, test_perm_layer.uuid)
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 attributes_sats_refresh(request): from geonode.geoserver.helpers import gs_catalog, set_attributes_from_geoserver uuid = request.POST['uuid'] resource = get_object_or_404(ResourceBase, uuid=uuid) can_change_data = request.user.has_perm('change_resourcebase', resource) layer = Layer.objects.get(id=resource.id) if layer and can_change_data: try: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=False) gs_resource = gs_catalog.get_resource(name=layer.name, store=layer.store, workspace=layer.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource( name=layer.name, workspace=layer.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource(name=layer.name) if not gs_resource: return HttpResponse(json.dumps({ 'success': 'false', 'message': f'Error trying to fetch the resource "{layer.store}" from GeoServer!' }), status=302, content_type='text/plain') bbox = gs_resource.native_bbox ll_bbox = gs_resource.latlon_bbox try: layer.set_bbox_polygon([bbox[0], bbox[2], bbox[1], bbox[3]], gs_resource.projection) except GeoNodeException as e: if not ll_bbox: raise else: logger.exception(e) layer.srid = 'EPSG:4326' layer.set_ll_bbox_polygon( [ll_bbox[0], ll_bbox[2], ll_bbox[1], ll_bbox[3]]) layer.save() except Exception as e: # traceback.print_exc() return HttpResponse(json.dumps({ 'success': 'false', 'message': f'Exception occurred: "{str(e)}"' }), status=302, content_type='text/plain') return HttpResponse(json.dumps({ 'success': 'ok', 'message': _('Attributes/Stats Refreshed Successfully!') }), status=200, content_type='text/plain') else: return HttpResponse(json.dumps({ 'success': 'false', 'message': _('You cannot modify this resource!') }), status=200, content_type='text/plain')
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_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', ) ) 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() # 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. """ # 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_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 publish_resource_geonode(store, resource_name, workspace_name='geonode', execute_signals=True, user="******", verbosity=1, permissions=None, ignore_errors=True): output = { 'stats': { 'failed': 0, 'updated': 0, 'created': 0, 'deleted': 0, }, 'layers': [], 'deleted_layers': [] } cat = gs_catalog owner = get_valid_user(user) workspace = cat.get_workspace(workspace_name) store = get_store(cat, store, workspace=workspace) if store is None: rsc = [] else: resources = cat.get_resources(stores=[store]) rsc = [k for k in resources if '%s' % (k.name) in resource_name] for resource in rsc: name = resource.name the_store = resource.store workspace = the_store.workspace try: layer, created = Layer.objects.get_or_create( name=name, workspace=workspace.name, defaults={ # "workspace": workspace.name, "store": the_store.name, "storeType": the_store.resource_type, "alternate": "%s:%s" % (workspace.name, resource.name), "title": resource.title or 'No title provided', "abstract": resource.abstract or u"{}".format(_('No abstract provided')), "owner": owner, "uuid": str(uuid.uuid4()) }) # print("laayer", layer) # print("created", created) layer.bbox_x0 = Decimal(resource.native_bbox[0]) layer.bbox_x1 = Decimal(resource.native_bbox[1]) layer.bbox_y0 = Decimal(resource.native_bbox[2]) layer.bbox_y1 = Decimal(resource.native_bbox[3]) layer.srid = resource.projection # sync permissions in GeoFence perm_spec = json.loads(_perms_info_json(layer)) layer.set_permissions(perm_spec) # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) # in some cases we need to explicitily save the resource to execute the signals # (for sure when running updatelayers) if execute_signals: layer.save() # Fix metadata links if the ip has changed if layer.link_set.metadata().count() > 0: if not created and settings.SITEURL not in layer.link_set.metadata( )[0].url: layer.link_set.metadata().delete() layer.save() metadata_links = [] for link in layer.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) resource.metadata_links = metadata_links cat.save(resource) except Exception as e: print("ERROR: ", e) if ignore_errors: status = 'failed' exception_type, error, traceback = sys.exc_info() else: if verbosity > 0: msg = "Stopping process because --ignore-errors was not set and an error was found." print(msg, file=sys.stderr) raise_( Exception, Exception("Failed to process {}".format(resource.name), e), sys.exc_info()[2]) else: if created: if not permissions: layer.set_default_permissions() else: layer.set_permissions(permissions) status = 'created' output['stats']['created'] += 1 else: status = 'updated' output['stats']['updated'] += 1
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://', '')
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: logger.debug(" -------------------------------------------------- ") bbox = gs_resource.native_bbox logger.debug(bbox) logger.debug(" -------------------------------------------------- ") # 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() + "/" elif instance.bbox_x0 and instance.bbox_x1 and instance.bbox_y0 and instance.bbox_y1: # Guessing 'EPSG:4326' by default instance.srid = 'EPSG:4326' 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' 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 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 # Refresh and create the instance default links layer = Layer.objects.get(id=instance.id) set_resource_default_links(instance, layer, prune=True) # 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) # 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 attributes_sats_refresh(request): from geonode.geoserver.helpers import gs_catalog, set_attributes_from_geoserver uuid = request.POST['uuid'] resource = get_object_or_404(ResourceBase, uuid=uuid) can_change_data = request.user.has_perm('change_resourcebase', resource) layer = Layer.objects.get(id=resource.id) if layer and can_change_data: try: # recalculate the layer statistics set_attributes_from_geoserver(layer, overwrite=True) gs_resource = gs_catalog.get_resource(name=layer.name, store=layer.store, workspace=layer.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource( name=layer.name, workspace=layer.workspace) if not gs_resource: gs_resource = gs_catalog.get_resource(name=layer.name) if not gs_resource: return HttpResponse(json.dumps({ 'success': 'false', 'message': 'Error trying to fetch the resource "%s" from GeoServer!' % layer.store }), status=302, content_type='text/plain') from decimal import Decimal layer.bbox_x0 = Decimal(gs_resource.native_bbox[0]) layer.bbox_x1 = Decimal(gs_resource.native_bbox[1]) layer.bbox_y0 = Decimal(gs_resource.native_bbox[2]) layer.bbox_y1 = Decimal(gs_resource.native_bbox[3]) layer.srid = gs_resource.projection layer.save() except Exception as e: # traceback.print_exc() return HttpResponse(json.dumps({ 'success': 'false', 'message': 'Exception occurred: "%s"' % str(e) }), status=302, content_type='text/plain') return HttpResponse(json.dumps({ 'success': 'ok', 'message': _('Attributes/Stats Refreshed Successfully!') }), status=200, content_type='text/plain') else: return HttpResponse(json.dumps({ 'success': 'false', 'message': _('You cannot modify this resource!') }), status=200, content_type='text/plain')
'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) try: # update the elastic search index for the object after post_save triggers have fired. update_es_index(sender, sender.objects.get(id=instance.id)) update_es_index(MapStory, MapStory.objects.get(id=instance.story.id)) except: pass
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_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_local(instance, *args, **kwargs): """Send information to geoserver. The attributes sent include: * Title * Abstract * Name * Keywords * Metadata Links, * Point of Contact name and url """ instance.refresh_from_db() # 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 _tries = 0 _max_tries = getattr(ogc_server_settings, "MAX_RETRIES", 2) # 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) def fetch_gs_resource(values, tries): try: gs_resource = gs_catalog.get_resource( name=instance.name, store=instance.store, workspace=instance.workspace) except Exception: try: gs_resource = gs_catalog.get_resource( name=instance.alternate, store=instance.store, workspace=instance.workspace) except Exception: try: gs_resource = gs_catalog.get_resource( name=instance.alternate or instance.typename) except Exception: gs_resource = None 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) if tries >= _max_tries: # raise GeoNodeException(msg) return (values, None) gs_resource = None sleep(3.00) return (values, gs_resource) while not gs_resource and _tries < _max_tries: values, gs_resource = fetch_gs_resource(values, _tries) _tries += 1 # Get metadata links metadata_links = [] for link in instance.link_set.metadata(): metadata_links.append((link.mime, link.name, link.url)) if gs_resource: logger.debug("Found geoserver resource for this layer: %s" % instance.name) 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 = get_user_model().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) else: msg = "There isn't a geoserver resource for this layer: %s" % instance.name logger.warn(msg) 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) # Invalidate GeoWebCache for the updated resource try: _stylefilterparams_geowebcache_layer(instance.alternate) _invalidate_geowebcache_layer(instance.alternate) except Exception: pass if instance.storeType == "remoteStore": return if gs_resource: """Get information from geoserver. The attributes retrieved include: * Bounding Box * SRID * Download links (WMS, WCS or WFS and KML) * Styles (SLD) """ try: instance.abstract = gs_resource.abstract or '' except Exception as e: logger.exception(e) instance.abstract = '' 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 Exception as e: logger.exception(e) if instance.srid: instance.srid_url = "http://www.spatialreference.org/ref/" + \ instance.srid.replace(':', '/').lower() + "/" elif instance.bbox_x0 and instance.bbox_x1 and instance.bbox_y0 and instance.bbox_y1: # Guessing 'EPSG:4326' by default instance.srid = 'EPSG:4326' else: raise GeoNodeException("Invalid Projection. Layer is missing CRS!") # Iterate over values from geoserver. if gs_resource: 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 gs_resource: try: if settings.RESOURCE_PUBLISHING: if instance.is_published != gs_resource.advertised: if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True): gs_resource.advertised = 'true' gs_catalog.save(gs_resource) if not settings.FREETEXT_KEYWORDS_READONLY: # AF: Warning - this won't allow people to have empty keywords on GeoNode 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) if any(instance.keyword_list()): keywords = instance.keyword_list() gs_resource.keywords = [kw 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): gs_catalog.save(gs_resource) except Exception 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() # Updating the Catalogue catalogue_post_save(instance=instance, sender=instance.__class__) # store the resource to avoid another geoserver call in the post_save if gs_resource: instance.gs_resource = gs_resource # 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 gs_resource: logger.debug("... Creating Default Resource Links for Layer [%s]" % (instance.alternate)) set_resource_default_links(instance, instance, prune=True) if 'update_fields' in kwargs and kwargs['update_fields'] is not None and \ 'thumbnail_url' in kwargs['update_fields']: logger.debug("... Creating Thumbnail for Layer [%s]" % (instance.alternate)) create_gs_thumbnail(instance, overwrite=True) # Updating HAYSTACK Indexes if needed if settings.HAYSTACK_SEARCH: from django.core.management import call_command call_command('update_index')
def test_save_and_delete_signals(self): """Test that GeoServer Signals methods work as espected""" layers = Layer.objects.all()[:2].values_list('id', flat=True) test_perm_layer = Layer.objects.get(id=layers[0]) self.client.login(username='******', password='******') if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.signals import (geoserver_pre_delete, geoserver_post_save, geoserver_post_save_local) # Handle Layer Save and Upload Signals geoserver_post_save(test_perm_layer, sender=Layer) geoserver_post_save_local(test_perm_layer) # Check instance bbox and links self.assertIsNotNone(test_perm_layer.bbox) self.assertIsNotNone(test_perm_layer.srid) self.assertIsNotNone(test_perm_layer.link_set) self.assertEquals(len(test_perm_layer.link_set.all()), 9) # Layer Manipulation from geonode.geoserver.upload import geoserver_upload from geonode.geoserver.signals import gs_catalog from geonode.geoserver.helpers import (check_geoserver_is_up, get_sld_for, fixup_style, set_layer_style, get_store, set_attributes_from_geoserver, set_styles, create_gs_thumbnail, cleanup) check_geoserver_is_up() admin_user = get_user_model().objects.get(username="******") saved_layer = geoserver_upload( test_perm_layer, os.path.join( gisdata.VECTOR_DATA, "san_andres_y_providencia_poi.shp"), admin_user, test_perm_layer.name, overwrite=True ) self.assertIsNotNone(saved_layer) _log(saved_layer) workspace, name = test_perm_layer.alternate.split(':') self.assertIsNotNone(workspace) self.assertIsNotNone(name) ws = gs_catalog.get_workspace(workspace) self.assertIsNotNone(ws) store = get_store(gs_catalog, name, workspace=ws) _log("1. ------------ %s " % store) self.assertIsNotNone(store) # Save layer attributes set_attributes_from_geoserver(test_perm_layer) # Save layer styles set_styles(test_perm_layer, gs_catalog) # set SLD sld = test_perm_layer.default_style.sld_body if test_perm_layer.default_style else None if sld: _log("2. ------------ %s " % sld) set_layer_style(test_perm_layer, test_perm_layer.alternate, sld) fixup_style(gs_catalog, test_perm_layer.alternate, None) self.assertIsNone(get_sld_for(gs_catalog, test_perm_layer)) _log("3. ------------ %s " % get_sld_for(gs_catalog, test_perm_layer)) create_gs_thumbnail(test_perm_layer, overwrite=True) self.assertIsNotNone(test_perm_layer.get_thumbnail_url()) self.assertTrue(test_perm_layer.has_thumbnail()) # Handle Layer Delete Signals geoserver_pre_delete(test_perm_layer, sender=Layer) # Check instance has been removed from GeoServer also from geonode.geoserver.views import get_layer_capabilities self.assertIsNone(get_layer_capabilities(test_perm_layer)) # Cleaning Up test_perm_layer.delete() cleanup(test_perm_layer.name, test_perm_layer.uuid)