def config_styles(self, sld_path='files/slds/glri/*.sld'): """ Create SLDs within GeoServer. :param str sld_path: path to sld files relative to the project directory :return: list of strings reporting post/overwrite statuses :rtype: list """ catalog = Catalog(self.host, self.user, self.password, True) sld_path = os.path.join(self.abs_path, sld_path) norm_sld_path = os.path.normpath(sld_path) sld_files = glob.glob(norm_sld_path) configured_styles = [] for sld_file in sld_files: with open(sld_file, 'r') as sld: sld_filename = os.path.basename(sld_file) sld_name = os.path.splitext(sld_filename)[0] sld_content = sld.read() if catalog.get_style(sld_name) is None: catalog.create_style(sld_name, sld_content) created_sld_str = 'Created {0}\n'.format(sld_name) print(created_sld_str) configured_styles.append(created_sld_str) else: catalog.create_style(sld_name, sld_content, overwrite=True) overwrite_sld_str = 'Overwrote {0}\n'.format(sld_name) print(overwrite_sld_str) configured_styles.append(overwrite_sld_str) return configured_styles
def _create_geoserver_geonode_layer(new_table, sld_type, title, the_user, permissions): # Create the Layer in GeoServer from the table try: cat = Catalog(settings.OGC_SERVER['default']['LOCATION'] + "rest", settings.OGC_SERVER['default']['USER'], settings.OGC_SERVER['default']['PASSWORD']) ds = cat.get_store("uploaded") # name of store in WFP-Geonode cat.publish_featuretype(new_table, ds, "EPSG:4326", srs="EPSG:4326") # changing the layer's title in the title set by the user resource = cat.get_resource(new_table, workspace="geonode") resource.title = title cat.save(resource) except Exception as e: msg = "Error creating GeoServer layer for %s: %s" % (new_table, str(e)) print msg return None, msg # Create the Layer in GeoNode from the GeoServer Layer try: link_to_sld = "{location}styles/{sld_type}".format( **{ 'location': settings.OGC_SERVER['default']['LOCATION'], 'sld_type': sld_type }) r = requests.get(link_to_sld) sld = r.text sld = sld.replace( "name_of_layer", new_table ) # "name_of_layer" is set in the predefined sld in geoserver (polygon_style, line_style, point_style) cat.create_style(new_table, sld, overwrite=True) style = cat.get_style(new_table) layer = cat.get_layer(new_table) layer.default_style = style cat.save(layer) gs_slurp(owner=the_user, filter=new_table) from geonode.base.models import ResourceBase layer = ResourceBase.objects.get(title=title) geoserver_post_save(layer, ResourceBase) # assign permissions for this layer permissions_dict = json.loads(permissions) # needs to be dictionary if permissions_dict is not None and len(permissions_dict.keys()) > 0: layer.set_permissions(permissions_dict) except Exception as e: msg = "Error creating GeoNode layer for %s: %s" % (new_table, str(e)) return None, msg
def upload_style(style_name): try: cat = Catalog(GEOSERVER_REST_URL, GS_USERNAME, GS_PASSWORD) style_filename = style_name + '.sld' style_file_path = str(os.path.join(DATA_PATH, 'styles', style_filename)) with open(style_file_path, 'r') as style: cat.create_style(style_name, style.read(), overwrite=True) style.close() except: raise
def make_style(style_name, style_info): cat = Catalog(GEOSERVER_REST_URL, GS_USERNAME, GS_PASSWORD) style_dir = path('data/styles') if not style_dir.exists(): style_dir.makedirs() style_filename = style_name + '.sld' style_file_path = str(os.path.join(DATA_PATH, 'styles', style_filename)) target_field = style_info['target_field'] sld_doc = StyledLayerDescriptor() nl = sld_doc.create_namedlayer(style_name) us = nl.create_userstyle() feature_style = us.create_featuretypestyle() for x in style_info['style_classes']: elem = feature_style._node.makeelement('{%s}Rule' % SLDNode._nsmap['sld'], nsmap=SLDNode._nsmap) feature_style._node.append(elem) r = Rule(feature_style, len(feature_style._node)-1) r.Title = x['label'] f1 = Filter(r) f1.PropertyIsGreaterThanOrEqualTo = PropertyCriterion(f1, 'PropertyIsGreaterThanOrEqualTo') f1.PropertyIsGreaterThanOrEqualTo.PropertyName = target_field f1.PropertyIsGreaterThanOrEqualTo.Literal = str(round(x['min'])) f2 = Filter(r) f2.PropertyIsLessThan = PropertyCriterion(f2, 'PropertyIsLessThan') f2.PropertyIsLessThan.PropertyName = target_field f2.PropertyIsLessThan.Literal = str(round(x['max'])) r.Filter = f1 + f2 sym = PolygonSymbolizer(r) fill = Fill(sym) fill.create_cssparameter('fill', x['colour']) fill.create_cssparameter('fill-opacity', '0.5') with open(style_file_path, 'w') as style: style.write(sld_doc.as_sld(True)) style.close() with open(style_file_path, 'r') as style: cat.create_style(style_name, style.read(), overwrite=True) style.close()
def _submit_sld(self,sld_body): try: geoserver_url=config['ckanext-vectorstorer.geoserver_url'] cat = Catalog(geoserver_url+"/rest") layer = cat.get_layer(c.layer_id) default_style=layer._get_default_style() if default_style.name ==c.layer_id: cat.create_style(default_style.name, sld_body, overwrite=True) else: cat.create_style(c.layer_id, sld_body, overwrite=True) layer._set_default_style(c.layer_id) cat.save(layer) c.success=True except UploadError, e: c.sld_body=sld_body c.error=e
def _submit_sld(self,sld_body): try: geoserver_url=config['ckanext-vectorstorer.geoserver_url'] cat = Catalog(geoserver_url+"/rest") layer = cat.get_layer(c.layer_id) default_style=layer._get_default_style() if default_style.name ==c.layer_id: cat.create_style(default_style.name, sld_body, overwrite=True) else: cat.create_style(c.layer_id, sld_body, overwrite=True) layer._set_default_style(c.layer_id) cat.save(layer) c.success=True except UploadError, e: c.sld_body=sld_body c.error=e
class GsConn: def __init__(self, host, login, password, debug=False): """ Geoserver connection """ self.host = host self.login = login self.password = password self.debug = debug # Connect to server self.cat = Catalog("http://%s/geoserver/rest" % host, login, password) if self.debug is True: print "Connected to geoserver" def crate_workspace(self, name, overwrite=False): """ Creates a workspace :param name: Workspace name. :param overwrite: If True, delete existing workspace. :return: None """ workspaces = [workspace.name for workspace in self.cat.get_workspaces()] if name in workspaces and overwrite is True: # ws2del = self.cat.get_workspace(name) # self.cat.delete(ws2del, purge=True, recurse=True) return None # NOTE: If we delete the workspace then all associated layers are lost. elif name in workspaces and overwrite is False: print "ERROR: Workspace %s already exists (use overwrite=True)." % name self.cat.create_workspace(name, "http://%s/%s" % (self.host, name)) if self.debug is True: print "Workspace %s available." % name ws = self.cat.get_workspace(name) ws.enabled = True def create_pg_store(self, name, workspace, host, port, login, password, dbname, schema, overwrite=False): """ Creates datastore. :param name: Name of the datastore. :param workspace: Name of the workspace to use. :param overwrite: If True replace datastore. :return: None """ stores = [store.name for store in self.cat.get_stores()] if name in stores and overwrite is True: # st2del = self.cat.get_store(name) # self.cat.delete(st2del, purge=True, recurse=True) # self.cat.reload() return None # NOTE: If we delete store, every layers associated with are lost. elif name in stores and overwrite is False: print "ERROR: Store %s already exists (use overwrite=True)." % name ds = self.cat.create_datastore(name, workspace) ds.connection_parameters.update( host=host, port=port, user=login, passwd=password, dbtype="postgis", database=dbname, schema=schema ) self.cat.save(ds) ds = self.cat.get_store(name) if ds.enabled is False: print "ERROR: Geoserver store %s not enabled" % name if self.debug is True: print "Datastore %s created." % name def publish_pg_layer(self, layer_table, layer_name, store, srid, overwrite=True): """ """ existing_lyr = self.cat.get_layer("ma_carte:%s" % layer_table) if existing_lyr is not None: print "Layer ma_carte:%s already exists, deleting it." % layer_table self.cat.delete(existing_lyr) self.cat.reload() ds = self.cat.get_store(store) ft = self.cat.publish_featuretype(layer_table, ds, "EPSG:%s" % srid, srs="EPSG:4326") ft.projection_policy = "REPROJECT_TO_DECLARED" ft.title = layer_name self.cat.save(ft) if ft.enabled is False: print "ERROR: Layer %s %s %s is not enabled."(ft.workspace.name, ft.store.name, ft.title) if self.debug is True: print "Layer %s>%s>%s published." % (ft.workspace.name, ft.store.name, ft.title) def create_style_from_sld(self, style_name, sld_file, workspace, overwrite=True): """ """ if self.cat.get_style(style_name) is not None: print "Style %s already exists, deleting it." % style_name style2del = self.cat.get_style(style_name) self.cat.delete(style2del) self.cat.create_style( style_name, open(sld_file).read(), overwrite=overwrite ) # FIXME: if ", workspace=workspace" specified can't delete style if self.debug is True: print "Style %s created in Geoserver" % style_name def apply_style_to_layer(self, layer_name, style_name): """ Apply a geoserver styler to a layer """ gs_layer = self.cat.get_layer(layer_name) gs_style = self.cat.get_style(style_name) # FIXME: Which works better? # gs_layer.default_style = gs_style / gs_layer._set_default_style(gs_style) # FIXME: Maybe indicate workspace when saving style then name the style as "workspace:style" gs_layer._set_default_style(gs_style) self.cat.save(gs_layer) if self.debug is True: print "Style applied to %s" % layer_name
def submitFiles(): """ Send the information of the uploaded files to the Open Data Registration Tool as an encoded JSON string in a GET-request The info is stored in a list of representations, according to the Open Data Registration Tool API: https://github.com/switchonproject/sip-html5-resource-registration/wiki """ threddsAvailable = True geoserverAvailable = True # Check if Thredds server is online threddsAvailable = checkConnection(app.config['THREDDS_SERVER'], "Failed to connect to the THREDDS server at " + app.config['THREDDS_SERVER'] + \ ". NetCDF files will not be accessible using web services, only by HTTP download.") # Check if GeoServer is online geoserverAvailable = checkConnection(app.config['GEOSERVER'], "Failed to connect to the geoserver at " + app.config['GEOSERVER'] + \ ". Shapefiles will not be mapped with WMS and can not be downloaded by WFS.") datasetname = session['DATASETNAME'] datasetFoldername = session['DATASETFOLDERNAME'] generateDOI = session['GENERATEDOI'] if request.form['submitButton'] == 'previous': return redirect('/?datasetname=' + datasetFoldername) if request.form['submitButton'] == 'next': datasetDir = os.path.join(app.config['BASE_UPLOAD_FOLDER'], datasetFoldername) files = [f for f in os.listdir(datasetDir) if os.path.isfile(os.path.join(datasetDir, f)) and f not in app.config['IGNORED_FILES']] if len(files) > 0: representation = {} result = [] urlRoot = request.url_root.rstrip('/') # get the url root without the traling '/' (for string concatenation) # Store the root url of the dataset as the primary representation if there are more than 1 file if len(files) > 1: representation['name'] = datasetname representation['description'] = "File download" representation['type'] = "original data" representation['contentlocation'] = '/'.join([urlRoot, 'data', datasetFoldername]) representation['contenttype'] = "application/octet-stream" representation['function'] = "information" representation['protocol'] = "WWW:LINK-1.0-http--link" result.append(representation) # if there is only one file, store the direct link to this file if len(files) == 1: filename, fileExtension = os.path.splitext(f) # region Check if it is a zipped shapefile # if it is, ignore it (unless geoserver is unavailable), otherwise the zip file is added twice zippedShapefile = False if fileExtension == '.zip' and geoserverAvailable: zipFilePath = os.path.join(datasetDir, f) zipFile = zipfile.ZipFile(zipFilePath, 'r') filesInZip = zipFile.namelist() zipFile.close() for fileInZip in filesInZip: fileInZipExtension = os.path.splitext(fileInZip)[1] if fileInZipExtension == '.shp': zippedShapefile = True #endregion if fileExtension != '.nc' and zippedShapefile == False: representation['name'] = datasetname representation['description'] = "File download" representation['type'] = "original data" # TODO: improve file recognition if fileExtension == ".zip": representation['contenttype'] = "application/zip" else: representation['contenttype'] = "application/octet-stream" representation['contentlocation'] = '/'.join([urlRoot, 'data', datasetFoldername, f]) representation['function'] = "download" representation['protocol'] = "WWW:DOWNLOAD-1.0-http--download" result.append(representation) #region THREDDS if threddsAvailable: if app.config['DEVELOP']: threddsCatalog = '/'.join((app.config['THREDDS_SERVER'], 'netcdftest', 'catalog.xml')) else: threddsCatalog = '/'.join((app.config['THREDDS_SERVER'], datasetFoldername, 'catalog.xml')) try: opendapUrls = threddsclient.opendap_urls(threddsCatalog) for opendapUrl in opendapUrls: filepath, fileExtension = os.path.splitext(opendapUrl) filename = opendapUrl.split('/')[-1] # check if the file is a netCDF file; if yes, store OPeNDAP service url and html download url if fileExtension == '.nc': representation = {} representation['name'] = filename representation['description'] = "Netcdf file OPeNDAP service" representation['contentlocation'] = opendapUrl representation['contenttype'] = "application/x-netcdf" representation['type'] = "original data" representation['function'] = "service" representation['protocol'] = 'OPeNDAP:OPeNDAP' result.append(representation) representation = {} representation['name'] = filename representation['description'] = "HTML interface OPeNDAP service" representation['contentlocation'] = opendapUrl + ".html" representation['contenttype'] = "application/x-netcdf" representation['type'] = "original data" representation['function'] = "download" representation['protocol'] = 'WWW:DOWNLOAD-1.0-http--download' result.append(representation) representation = {} representation['name'] = filename representation['description'] = "WMS service" representation['contentlocation'] = opendapUrl.replace('dodsC', 'wms') + "?service=WMS&version=1.3.0&request=GetCapabilities" representation['contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation['protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' result.append(representation) except: app.logger.info("URL: " + threddsCatalog + " is not a THREDDS catalog") #endregion # region GEOSERVER: loop through all files to check for shapefiles if geoserverAvailable: for file in files: layerName = '' filename, fileExtension = os.path.splitext(file) if fileExtension == '.zip': zipFilePath = os.path.join(datasetDir, file) zipFile = zipfile.ZipFile(zipFilePath, 'r') filesInZip = zipFile.namelist() for fileInZip in filesInZip: fileInZipName = os.path.split(fileInZip)[1] fileInZipNoExtName, fileInZipExtension = os.path.splitext(fileInZipName) if fileInZipExtension == '.shp': # Layer name is the file without extension layerName = fileInZipNoExtName # Publish .zipped shapefile on geoserver, no subdirectories zipFile.extractall(datasetDir) for root, dirs, files in os.walk(datasetDir): for name in files: os.rename(os.path.join(root, name), os.path.join(datasetDir,name)) # create workspace r = requests.post(url= app.config['GEOSERVER'] + "/rest/workspaces", headers={'Content-type': 'text/xml'}, data="<workspace><name>" + datasetFoldername + "</name></workspace>", auth=HTTPBasicAuth(app.config['GEOSERVER_ADMIN'], app.config['GEOSERVER_PASS'])) if r.status_code > 299: # status code of 201 is success; all else is failure app.logger.error("Error in creating geoserver workspace for " + datasetFoldername + \ "; Status code: " + str(r.status_code) + ", Content: " + r.content) flash("Error in creating workspace on geoserver.") return redirect(url_for('uploadData')) # for testing purposes.. uploaded file is on local machine and can only publish data that is on the data mount of web app if app.config['DEVELOP']: shapeFile = "file://D:/sala/Downloads/sld_cookbook_polygon/sld_cookbook_polygon.shp" else: shapeFile = settings['GEOSERVER_DATA_DIR'] + "/" + datasetFoldername + "/" + fileInZipName # Publish shapefile on the geoserver; the datastore is automatically created and has the same name as the shapefile + ds r = requests.put(url=app.config['GEOSERVER'] + "/rest/workspaces/" + datasetFoldername + "/datastores/" + datasetFoldername + "_ds/external.shp", headers={'Content-type': 'text/plain'}, data='file://'+shapeFile, auth=HTTPBasicAuth(app.config['GEOSERVER_ADMIN'], app.config['GEOSERVER_PASS'])) if r.status_code > 299: app.logger.error("Error in publishing shapefile " + datasetFoldername + " on geoserver; Status code: " \ + str(r.status_code) + ", Content: " + r.content) flash("Error in publishing shapefile on geoserver.") return redirect(url_for('uploadData')) representation = {} representation['name'] = layerName representation['description'] = "WMS service" representation['contentlocation'] = app.config['GEOSERVER'] + "/" + datasetFoldername + "/" + \ "wms?service=WMS&version=1.1.0&request=GetCapabilities" representation['contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation['protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' result.append(representation) representation = {} representation['name'] = layerName representation['description'] = "WMS service" representation['contentlocation'] = app.config['GEOSERVER'] + "/" + datasetFoldername + "/" + \ "wms?service=WMS&version=1.1.0&request=GetCapabilities" representation['contenttype'] = "application/xml" representation['type'] = "aggregated data" representation['function'] = "service" representation['protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' #region Get spatial extent from getcapabilities document try: root = ET.fromstring(requests.get(representation['contentlocation']).content) latlonElem = root.find('Capability/Layer/Layer/LatLonBoundingBox') latlonDict = latlonElem.attrib minx = latlonDict['minx'] miny = latlonDict['miny'] maxx = latlonDict['maxx'] maxy = latlonDict['maxy'] # WKT representation: POLYGON((minx miny, maxx miny, maxx maxy, minx maxy, minx miny)) WKTString = 'POLYGON(({0} {1}, {2} {1}, {2} {3}, {0} {3}, {0} {1}))'.format(minx, miny, maxx, maxy) representation['wktboundingbox'] = WKTString except: app.logger.error("Error in deriving WKT bounding box from WMS getcapabilities document") #endregion result.append(representation) representation = {} representation['name'] = fileInZipNoExtName representation['description'] = "WFS service" representation['contentlocation'] = app.config['GEOSERVER'] + "/" + datasetFoldername + "/" + "ows?service=WFS&version=1.0.0&request=GetCapabilities" representation['contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation['protocol'] = "OGC:WFS-1.0.0-http-get-capabilities" result.append(representation) representation = {} representation['name'] = file representation['description'] = "Zipped shapefile" representation['contentlocation'] = '/'.join([urlRoot, 'data', datasetFoldername, file]) representation['contenttype'] = "application/zip" representation['type'] = "original data" representation['function'] = "download" representation['protocol'] = "WWW:DOWNLOAD-1.0-http--download" representation['uploadmessage'] = "deriveSpatialIndex:shp" result.append(representation) # Optional sld file (preconditions, shp uploaded, workspace created) for fileInZip in filesInZip: fileInZipName = os.path.split(fileInZip)[1] fileInZipNoExtName, fileInZipExtension = os.path.splitext(fileInZipName) if fileInZipExtension == '.sld': # for testing purposes.. uploaded file is on local machine and can only publish data that is on the data mount of web app if app.config['DEVELOP']: sldFile = "D:/sala/Downloads/sld_cookbook_polygon/sld_cookbook_polygon.sld" else: sldFile = settings['GEOSERVER_DATA_DIR'] + "/" + datasetFoldername + "/" + fileInZipName # Connect to geoserver catalogue cat = Catalog(app.config['GEOSERVER'] + "/rest", app.config['GEOSERVER_ADMIN'], password=app.config['GEOSERVER_PASS']) # Add or Overwrite with open(sldFile) as f: style=cat.create_style(fileInZipNoExtName, f.read(), overwrite=True) # Link it to the layer layer = cat.get_layer(layerName) layer._set_default_style(fileInZipNoExtName) cat.save(layer) # close zip file after looping through all files in the zip file zipFile.close() #endregion # region if generateDOI: d = DOI(files, datasetDir, datasetname, logger=app.logger) deposition_id = d.runUpload() # endregion resultString = json.dumps(result) text = urllib.quote_plus(resultString.encode('utf-8')) if generateDOI: url = app.config['METADATA_URL'] + text + '&deposition=' + deposition_id else: url = app.config['METADATA_URL'] + text # store the representation app.logger.info("Representations of the dataset: " + resultString) return redirect(url) else: flash("Please upload at least one file") return redirect(url_for('uploadData'))
class ModifyingTests(unittest.TestCase): def setUp(self): self.cat = Catalog("http://localhost:8080/geoserver/rest") def testFeatureTypeSave(self): # test saving round trip rs = self.cat.get_resource("bugsites") old_abstract = rs.abstract new_abstract = "Not the original abstract" enabled = rs.enabled # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(new_abstract, rs.abstract) self.assertEqual(enabled, rs.enabled) # Change keywords on server rs.keywords = ["bugsites", "gsconfig"] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(["bugsites", "gsconfig"], rs.keywords) self.assertEqual(enabled, rs.enabled) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual([ ("text/xml", "TC211", "http://example.com/gsconfig.test.metadata") ], rs.metadata_links) self.assertEqual(enabled, rs.enabled) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(old_abstract, rs.abstract) def testDataStoreCreate(self): ds = self.cat.create_datastore("vector_gsconfig") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) def testPublishFeatureType(self): # Use the other test and store creation to load vector data into a database # @todo maybe load directly to database? try: self.testDataStoreCreateAndThenAlsoImportData() except FailedRequestError: pass try: lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) ds = self.cat.get_store("gsconfig_import_test") # make sure it's gone self.assert_(self.cat.get_layer('import') is None) self.cat.publish_featuretype("import", ds, native_crs="EPSG:4326") # and now it's not self.assert_(self.cat.get_layer('import') is not None) finally: # tear stuff down to allow the other test to pass if we run first ds = self.cat.get_store("gsconfig_import_test") lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) self.cat.delete(ds) def testDataStoreModify(self): ds = self.cat.get_store("sf") self.assertFalse("foo" in ds.connection_parameters) ds.connection_parameters = ds.connection_parameters ds.connection_parameters["foo"] = "bar" orig_ws = ds.workspace.name self.cat.save(ds) ds = self.cat.get_store("sf") self.assertTrue("foo" in ds.connection_parameters) self.assertEqual("bar", ds.connection_parameters["foo"]) self.assertEqual(orig_ws, ds.workspace.name) @drop_table('import') def testDataStoreCreateAndThenAlsoImportData(self): ds = self.cat.create_datastore("gsconfig_import_test") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test") self.cat.add_data_to_store( ds, "import", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) def testCoverageStoreCreate(self): ds = self.cat.create_coveragestore2("coverage_gsconfig") ds.data_url = "file:data/mytiff.tiff" self.cat.save(ds) def testCoverageStoreModify(self): cs = self.cat.get_store("sfdem") self.assertEqual("GeoTIFF", cs.type) cs.type = "WorldImage" self.cat.save(cs) cs = self.cat.get_store("sfdem") self.assertEqual("WorldImage", cs.type) # not sure about order of test runs here, but it might cause problems # for other tests if this layer is misconfigured cs.type = "GeoTIFF" self.cat.save(cs) def testCoverageSave(self): # test saving round trip rs = self.cat.get_resource("Arc_Sample") old_abstract = rs.abstract new_abstract = "Not the original abstract" # # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(new_abstract, rs.abstract) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(old_abstract, rs.abstract) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual([ ("text/xml", "TC211", "http://example.com/gsconfig.test.metadata") ], rs.metadata_links) self.assertEqual(enabled, rs.enabled) srs_before = set(['EPSG:4326']) srs_after = set(['EPSG:4326', 'EPSG:3785']) formats = set( ['ARCGRID', 'ARCGRID-GZIP', 'GEOTIFF', 'PNG', 'GIF', 'TIFF']) formats_after = set(["PNG", "GIF", "TIFF"]) # set and save request_srs_list self.assertEquals(set(rs.request_srs_list), srs_before, str(rs.request_srs_list)) rs.request_srs_list = rs.request_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.request_srs_list), srs_after, str(rs.request_srs_list)) # set and save response_srs_list self.assertEquals(set(rs.response_srs_list), srs_before, str(rs.response_srs_list)) rs.response_srs_list = rs.response_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.response_srs_list), srs_after, str(rs.response_srs_list)) # set and save supported_formats self.assertEquals(set(rs.supported_formats), formats, str(rs.supported_formats)) rs.supported_formats = ["PNG", "GIF", "TIFF"] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.supported_formats), formats_after, str(rs.supported_formats)) def testWmsStoreCreate(self): ws = self.cat.create_wmsstore("wmsstore_gsconfig") ws.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" ws.type = "WMS" self.cat.save(ws) def testWmsLayer(self): self.cat.create_workspace("wmstest", "http://example.com/wmstest") wmstest = self.cat.get_workspace("wmstest") wmsstore = self.cat.create_wmsstore("wmsstore", wmstest) wmsstore.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" wmsstore.type = "WMS" self.cat.save(wmsstore) wmsstore = self.cat.get_store("wmsstore") self.assertEqual(1, len(self.cat.get_stores(wmstest))) available_layers = wmsstore.get_resources(available=True) for layer in available_layers: # sanitize the layer name - validation will fail on newer geoservers name = layer.replace(':', '_') new_layer = self.cat.create_wmslayer(wmstest, wmsstore, name, nativeName=layer) added_layers = wmsstore.get_resources() self.assertEqual(len(available_layers), len(added_layers)) changed_layer = added_layers[0] self.assertEqual(True, changed_layer.advertised) self.assertEqual(True, changed_layer.enabled) changed_layer.advertised = False changed_layer.enabled = False self.cat.save(changed_layer) self.cat._cache.clear() changed_layer = wmsstore.get_resources()[0] changed_layer.fetch() self.assertEqual(False, changed_layer.advertised) self.assertEqual(False, changed_layer.enabled) def testFeatureTypeCreate(self): shapefile_plus_sidecars = shapefile_and_friends("test/data/states") expected = { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' } self.assertEqual(len(expected), len(shapefile_plus_sidecars)) for k, v in expected.iteritems(): self.assertEqual(v, shapefile_plus_sidecars[k]) sf = self.cat.get_workspace("sf") self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) self.assert_( self.cat.get_resource("states_test", workspace=sf) is not None) self.assertRaises( ConflictingDataError, lambda: self.cat.create_featurestore( "states_test", shapefile_plus_sidecars, sf)) self.assertRaises( UploadError, lambda: self.cat.create_coveragestore( "states_raster_test", shapefile_plus_sidecars, sf)) bogus_shp = { 'shp': 'test/data/Pk50095.tif', 'shx': 'test/data/Pk50095.tif', 'dbf': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } self.assertRaises( UploadError, lambda: self.cat.create_featurestore("bogus_shp", bogus_shp, sf)) lyr = self.cat.get_layer("states_test") self.cat.delete(lyr) self.assert_(self.cat.get_layer("states_test") is None) def testCoverageCreate(self): tiffdata = { 'tiff': 'test/data/Pk50095.tif', 'tfw': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } sf = self.cat.get_workspace("sf") # TODO: Uploading WorldImage file no longer works??? # ft = self.cat.create_coveragestore("Pk50095", tiffdata, sf) # self.assert_(self.cat.get_resource("Pk50095", workspace=sf) is not None) # self.assertRaises( # ConflictingDataError, # lambda: self.cat.create_coveragestore("Pk50095", tiffdata, sf) # ) self.assertRaises( UploadError, lambda: self.cat.create_featurestore( "Pk50095_vector", tiffdata, sf)) bogus_tiff = { 'tiff': 'test/data/states.shp', 'tfw': 'test/data/states.shx', 'prj': 'test/data/states.prj' } self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster", bogus_tiff)) def testLayerSave(self): # test saving round trip lyr = self.cat.get_layer("states") old_attribution = lyr.attribution new_attribution = "Not the original attribution" # change attribution on server lyr.attribution = new_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(new_attribution, lyr.attribution) # Restore attribution lyr.attribution = old_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(old_attribution, lyr.attribution) self.assertEqual(lyr.default_style.name, "population") old_default_style = lyr.default_style lyr.default_style = (s for s in lyr.styles if s.name == "pophatch").next() lyr.styles = [old_default_style] self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(lyr.default_style.name, "pophatch") self.assertEqual([s.name for s in lyr.styles], ["population"]) def testStyles(self): # upload new style, verify existence self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Fred", fred.sld_title) # replace style, verify changes self.cat.create_style("fred", open("test/ted.sld").read(), overwrite=True) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Ted", fred.sld_title) # delete style, verify non-existence self.cat.delete(fred, purge=True) self.assert_(self.cat.get_style("fred") is None) # attempt creating new style self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assertEqual("Fred", fred.sld_title) # verify it can be found via URL and check the name f = self.cat.get_style_by_url(fred.href) self.assert_(f is not None) self.assertEqual(f.name, fred.name) def testWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="blarny") self.assert_(jed is None) jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) jed = self.cat.get_style("topp:jed") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) # replace style, verify changes self.cat.create_style("jed", open("test/ted.sld").read(), overwrite=True, workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Ted", jed.sld_title) # delete style, verify non-existence self.cat.delete(jed, purge=True) self.assert_(self.cat.get_style("jed", workspace="topp") is None) # attempt creating new style self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assertEqual("Fred", jed.sld_title) # verify it can be found via URL and check the full name f = self.cat.get_style_by_url(jed.href) self.assert_(f is not None) self.assertEqual(f.fqn, jed.fqn) def testLayerWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("ned", open("test/fred.sld").read(), overwrite=True, workspace="topp") self.cat.create_style("zed", open("test/ted.sld").read(), overwrite=True, workspace="topp") ned = self.cat.get_style("ned", workspace="topp") zed = self.cat.get_style("zed", workspace="topp") self.assert_(ned is not None) self.assert_(zed is not None) lyr = self.cat.get_layer("states") lyr.default_style = ned lyr.styles = [zed] self.cat.save(lyr) self.assertEqual("topp:ned", lyr.default_style) self.assertEqual([zed], lyr.styles) lyr.refresh() self.assertEqual("topp:ned", lyr.default_style.fqn) self.assertEqual([zed.fqn], [s.fqn for s in lyr.styles]) def testWorkspaceCreate(self): ws = self.cat.get_workspace("acme") self.assertEqual(None, ws) self.cat.create_workspace("acme", "http://example.com/acme") ws = self.cat.get_workspace("acme") self.assertEqual("acme", ws.name) def testWorkspaceDelete(self): self.cat.create_workspace("foo", "http://example.com/foo") ws = self.cat.get_workspace("foo") self.cat.delete(ws) ws = self.cat.get_workspace("foo") self.assert_(ws is None) def testWorkspaceDefault(self): # save orig orig = self.cat.get_default_workspace() neu = self.cat.create_workspace("neu", "http://example.com/neu") try: # make sure setting it works self.cat.set_default_workspace("neu") ws = self.cat.get_default_workspace() self.assertEqual('neu', ws.name) finally: # cleanup and reset to the way things were self.cat.delete(neu) self.cat.set_default_workspace(orig.name) ws = self.cat.get_default_workspace() self.assertEqual(orig.name, ws.name) def testFeatureTypeDelete(self): pass def testCoverageDelete(self): pass def testDataStoreDelete(self): states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) states.enabled = False self.assert_(states.enabled == False) self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == False) states.enabled = True self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) def testLayerGroupSave(self): tas = self.cat.get_layergroup("tasmania") self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads', 'tasmania_cities' ], tas.layers) self.assertEqual(tas.styles, [None, None, None, None], tas.styles) tas.layers = tas.layers[:-1] tas.styles = tas.styles[:-1] self.cat.save(tas) # this verifies the local state self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads' ], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) # force a refresh to check the remote state tas.refresh() self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads' ], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) def testTimeDimension(self): sf = self.cat.get_workspace("sf") files = shapefile_and_friends( os.path.join(gisdata.GOOD_DATA, "time", "boxes_with_end_date")) self.cat.create_featurestore("boxes_with_end_date", files, sf) get_resource = lambda: self.cat._cache.clear() or self.cat.get_layer( 'boxes_with_end_date').resource # configure time as LIST resource = get_resource() timeInfo = DimensionInfo("time", "true", "LIST", None, "ISO8601", None, attribute="date") resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual("LIST", timeInfo.presentation) self.assertEqual(True, timeInfo.enabled) self.assertEqual("date", timeInfo.attribute) self.assertEqual("ISO8601", timeInfo.units) # disable time dimension timeInfo = resource.metadata['time'] timeInfo.enabled = False # since this is an xml property, it won't get written unless we modify it resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(False, timeInfo.enabled) # configure with interval, end_attribute and enable again timeInfo.enabled = True timeInfo.presentation = 'DISCRETE_INTERVAL' timeInfo.resolution = '3 days' timeInfo.end_attribute = 'enddate' resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(True, timeInfo.enabled) self.assertEqual('DISCRETE_INTERVAL', timeInfo.presentation) self.assertEqual('3 days', timeInfo.resolution_str()) self.assertEqual('enddate', timeInfo.end_attribute) def testImageMosaic(self): # testing the mosaic creation name = 'cea_mosaic' data = open('test/data/mosaic/cea.zip', 'rb') self.cat.create_imagemosaic(name, data) # get the layer resource back self.cat._cache.clear() resource = self.cat.get_layer(name).resource self.assert_(resource is not None) # delete granule from mosaic coverage = name store = name granule_id = name + '.1' self.cat.mosaic_delete_granule(coverage, store, granule_id)
def add_to_geoserver(self): # Inspired (copied :) ) from https://groups.google.com/forum/#!msg/geonode-users/R-u57r8aECw/AuEpydZayfIJ # TODO : check license # We connect to the catalog gsUrl = settings.OGC_SERVER['default']['LOCATION'] + "rest" gsUser = settings.OGC_SERVER['default']['USER'] gsPassword = settings.OGC_SERVER['default']['PASSWORD'] cat = Catalog(gsUrl, gsUser, gsPassword) if cat is None: raise Exception('unable to instantiate geoserver catalog') # We get the workspace ws = cat.get_workspace(settings.DEFAULT_WORKSPACE) if ws is None: raise Exception('workspace %s not found in geoserver' % settings.DEFAULT_WORKSPACE) # We get or create the datastore store = cat.get_store(self.datastore_name, ws) if store is None: store = cat.create_datastore(self.datastore_name, ws) store.connection_parameters.update(host="postgres", port="5432", database="postgres", user="******", passwd="postgres", schema='offline_osm', dbtype="postgis") cat.save(store) if store is None: raise Exception('datastore %s not found in geoserver' % self.datastore_name) # We get or create each layer then register it into geonode for layer in Command.layers: layername = layer["name"] self.stdout.write('Adding {} to geoserver...'.format(layername)) layer_exists = (not cat.get_layer(layername) is None) if not layer_exists or not self.options['no_overwrite']: self.stdout.write( ' layer does not exists or no_overwrite unset, we add...') ft = cat.publish_featuretype(layername, store, 'EPSG:4326', srs='EPSG:4326') if ft is None: raise Exception('unable to publish layer %s' % layername) ft.title = 'OpenStreetMap Offline - ' + layername.split( '_')[-1] ft.abstract = 'This is an automated extract of the OpenStreetMap database. It is available offline. It is intended to be used as a background layer, but the data can also server analysis purposes.' cat.save(ft) self.stdout.write( ' adding the style for {}...'.format(layername)) # We get or create the workspace style_path = os.path.join(os.path.dirname(__file__), '..', '..', 'styles', layer["style_name"]) if not os.path.exists(style_path): self.stdout.write( ' The file {} does not exist. No style will be applied for {}.' .format(style_path, layername)) else: cat.create_style(layer["style_name"], open(style_path, 'r').read(), overwrite=True, workspace=settings.DEFAULT_WORKSPACE, raw=True) style = cat.get_style(layer["style_name"], ws) if style is None: raise Exception('style not found (%s)' % (layer["style_name"])) publishing = cat.get_layer(layername) if publishing is None: raise Exception('layer not found (%s)' % layerName) publishing.default_style = style cat.save(publishing) self.stdout.write( ' registering {} into geonode...'.format(layername)) resource = cat.get_resource(layername, store, ws) if resource is None: raise Exception('resource not found (%s)' % layername) layer, created = Layer.objects.get_or_create(name=layername) layer.workspace = ws.name layer.store = store.name layer.storeType = store.resource_type layer.typename = "%s:%s" % (ws.name.encode('utf-8'), resource.name.encode('utf-8')) layer.title = resource.title layer.abstract = resource.abstract layer.temporal_extent_start = self.import_timestamp layer.temporal_extent_end = self.import_timestamp try: layer.save() except TypeError as e: # We ignore a specific error in Geonode resourcebase_post_save when settings.SITEURL has no host (relative URL) self.stdout.write( 'TODO : report Geonode exception in resourcebase_post_save when settings.SITEURL has no host (relative URL) : ' + str(e)) pass if created: layer.set_default_permissions() else: self.stdout.write(' layer already exists, we skip.') # We get or create the laygroup self.stdout.write('Adding layergroup to geoserver...') layername = 'offline_osm' layergroup_exists = (not cat.get_layergroup(layername) is None) if not layer_exists or not self.options['no_overwrite']: self.stdout.write( ' layer does not exists or no_overwrite unset, we add...') layergroup = cat.get_layergroup( layername, workspace=settings.DEFAULT_WORKSPACE) if layergroup is None: layergroup = cat.create_layergroup( layername, layers=layernames, workspace=settings.DEFAULT_WORKSPACE) if layergroup is None: raise Exception('unable to publish layer %s' % layername) layergroup.title = 'OpenStreetMap Offline' layergroup.abstract = 'This is an automated extract of the OpenStreetMap database. It is available offline. It is intended to be used as a background layer, but the data can also server analysis purposes.' cat.save(layergroup) else: self.stdout.write(' layergroup already exists, we skip.') # TODO : can we add layergroups to Geonode ? self.stdout.write( "laygroup won't be added to geonode (not supported yet)")
class GeoserverHelper: def __init__(self, geoserverUrl = "", geoserverUserName = "", geoserverPW = "", geoserverWorkSpace = "", postgreIP = "", postgreUserName = "", postgrePW = ""): """use the constructor given arguments if used""" self.geoserverUrl = geoserverUrl if geoserverUrl != "" else GEOSERVERURL self.geoserverUserName = geoserverUserName if geoserverUserName != "" else GEOSERVERUSERNAME self.geoserverPW = geoserverPW if geoserverPW != "" else GEOSERVERPW self.geoserverWorkSpace = geoserverWorkSpace if geoserverWorkSpace != "" else "crc" self.postgreIP = postgreIP if postgreIP != "" else POSTGREIP self.postgreUserName = postgreUserName if postgreUserName != "" else POSTGREUSERNAME self.postgrePW = postgrePW if postgrePW != "" else POSTGREPW if self.geoserverUrl[-1] != '/': raise Exception("GeoserverUrl must end with a slash ('/')") self.catalog = Catalog(self.geoserverUrl+"rest/") self.catalog.http.add_credentials(self.geoserverUserName,self.geoserverPW) try: workspaces = self.catalog.get_workspaces() except: e = sys.exc_info()[0] print e self.cWorkSpace = self.catalog.get_workspace(self.geoserverWorkSpace) def getLayers(self): return self.cWorkSpace.catalog.get_layers() def insertShapeIntoPostGis(self, shapeFile, databaseName, tableName, encoding=3857): '''returns the returnCode of the execution of the insert script, e.g: helper.insertShapeIntoPostGis('/home/c815/gsTest/test.shp','crc','testingHelper2')''' if not os.path.isfile(shapeFile): print "Shape file not found" return -1 cmds = "PGPASSWORD={pgPW} ./createWSFTFromSHP.sh -s {shapeFileF} -d {databaseNameF} -t {tableNameF} -u {postgreUsername} -i {postgreIP}".format(pgPW=self.postgrePW, shapeFileF=shapeFile,databaseNameF=databaseName, tableNameF=tableName, postgreUsername=self.postgreUserName, postgreIP=self.postgreIP) return subprocess.call(cmds, shell=True) def uploadShapeFile(self, shapeFile, storeName): shpPlusSidcars = geoserver.util.shapefile_and_friends(shapeFile[:-3]) shpPlusSidcars self.ft = self.catalog.create_featurestore(storeName, shpPlusSidcars, self.cWorkSpace) def getStyles(self): return self.catalog.get_styles() def uploadStyleFile(self, sldFile, styleName, overWrite, workSpace = None): f = open(sldFile,'r') styleSrc = f.read() uploadStyle(styleSrc, styleName, overWrite, workSpace) f.close() def uploadStyle(self, sldSrc, styleName, overWrite, workSpace = None): self.catalog.create_style(styleName,sldSrc, overWrite, workSpace) def publishPostGISLayer(self,postGISLayerName, storeName, crs='EPSG:3857'): '''cat.publish_featuretype('testingstuff',crcStore,native_crs='EPSG:3857')''' store = self.catalog.get_store(storeName) if store != None: self.catalog.publish_featuretype(postGISLayerName, store, crs) def setDefaultStyleForLayer(self, layerName, styleName): l = self.catalog.get_layer(layerName) sNames = [ i.name for i in self.getStyles() ] if styleName not in sNames: split = styleName.split(':') if len(split) == 2: workSpace = styleName.split(':')[0] newStyleName = styleName.split(':')[1] else: return -1 style = self.catalog.get_style(newStyleName, workSpace) if style is None: return -1 if l != None: l._set_default_style(styleName) self.catalog.save(l) return 0 def createPostGISDataStore(self, storeName, postGisPassword, postGisUser, postGisHost, postGisDatabase, workSpace = None): #check if connection parameter are valid try: conn = psycopg2.connect("dbname='{dbName}' user='******' host='{Host}' password='******'".format(dbName=postGisDatabase, dbUser=postGisUser, Host=postGisHost, password=postGisPassword)) except: return False w = self.catalog.create_datastore(storeName, workSpace) template = Template("""{'validate connections': 'true', 'port': '5432', 'Support on the fly geometry simplification': 'true', 'create database': 'false', 'dbtype': 'postgis', 'Connection timeout': '20', 'namespace': 'http://www.crcproject.com', 'Max connection idle time': '300', 'Expose primary keys': 'false', 'min connections': '1', 'Max open prepared statements':'50', 'passwd': '$passwd', 'encode functions': 'false', 'max connections': '10', 'Evictor tests per run': '3', 'Loose bbox': 'true', 'Evictor run periodicity': '300', 'Estimated extends': 'true', 'database': '$database', 'fetch size': '1000', 'Test while idle': 'true', 'host': '$host', 'preparedStatements': 'false', 'schema': 'public', 'user': '******'}""") dic = ast.literal_eval(template.substitute( passwd=postGisPassword, user=postGisUser, host=postGisHost, database=postGisDatabase)) #'passwd': 'crypt1:Bsaz2AUI8T+6Pj43krA7kg==', #'user': '******'} #'database': 'crc', #'host': 'localhost', w.connection_parameters = dic self.catalog.save(w) return True
else: minx = min(minx, float(bbox[0])) maxx = max(maxx, float(bbox[1])) miny = min(miny, float(bbox[2])) maxy = max(maxy, float(bbox[3])) if proj != layer.resource.projection: print 'projection mismatch...' sys.exit(1) # if there is a style with the same name, then add and apply it if os.path.isfile(shp + '.sld'): style = cat.get_style(shp) sld = open(shp + '.sld').read() if style is None: print 'adding style...' cat.create_style(shp, sld, False) else: print 'updating style...' cat.create_style(shp, sld, True) style = cat.get_style(shp) layer.default_style = style cat.save(layer) styles.append(shp) else: styles.append(cat.get_layer(shp).default_style.name) # create a layer group lg = cat.get_layergroup(lg_name) if lg is None: lg = cat.create_layergroup(lg_name)
if r_create_layer.status_code == 201 and _checkUpload(): logging.info('Succecssfully uploaded Zipfile') else: logging.error('Failed to upload NetCDF File') exit(1) os.remove(output.filename) # create New Styles from prebuild XML Files styleDir = cfg['general']['workdir'] + '/outputFiles/' + projectName + '/styles/' styles = [] for _r, _d, files in os.walk(styleDir): logging.info("Uploading " + str(len(files)) + " styles") for f in files: with open(styleDir + f, 'r') as style: styleName = f.rstrip('.xml') cat.create_style(styleName, style.read(), workspace=workspace, overwrite=True) styles.append(workspace + ':' + styleName) break # assign styles to created layers and enable timeDimension layers = cat.get_layers() for layer in layers: # if layer.dom is not None: if layer.name.startswith(workspace): # GetStyleName layerName = layer.resource.name # Set Default Style (timeIndependend) layer.default_style = workspace + ":" + layerName layer.styles = [s for s in styles if s.startswith(workspace + ":" + layerName)] cat.save(layer) # get coverage to activate time Dimension
import glob, os from geoserver.catalog import Catalog os.chdir("sld") cat = Catalog("http://localhost:48080/minresource-minesatlas-gws/rest") for file in glob.glob("*.sld"): with open(file) as f: sld_name = os.path.splitext(file)[0] cat.create_style(sld_name, f.read(), overwrite=True)
def create_geoserver_layer(name, user, srid, overwrite=False, title=None, abstract=None, charset='UTF-8'): if "geonode.geoserver" in settings.INSTALLED_APPS: _user, _password = ogc_server_settings.credentials # # Step 2. Check that it is uploading to the same resource type as # the existing resource logger.info( '>>> Step 2. Make sure we are not trying to overwrite a ' 'existing resource named [%s] with the wrong type', name) the_layer_type = "vector" # Get a short handle to the gsconfig geoserver catalog cat = Catalog(ogc_server_settings.internal_rest, _user, _password) workspace = cat.get_default_workspace() # Check if the store exists in geoserver try: store = get_store(cat, name, workspace=workspace) except FailedRequestError as e: # There is no store, ergo the road is clear pass else: # If we get a store, we do the following: resources = store.get_resources() # If the store is empty, we just delete it. if len(resources) == 0: cat.delete(store) else: # If our resource is already configured in the store it needs # to have the right resource type for resource in resources: if resource.name == name: msg = 'Name already in use and overwrite is False' assert overwrite, msg existing_type = resource.resource_type if existing_type != the_layer_type: msg = ('Type of uploaded file %s (%s) ' 'does not match type of existing ' 'resource type ' '%s' % (name, the_layer_type, existing_type)) logger.info(msg) raise GeoNodeException(msg) logger.debug('Creating vector layer: [%s]', name) ds = create_feature_store(cat, workspace) gs_resource = gs_catalog.publish_featuretype(name, ds, "EPSG:" + str(srid)) # # Step 7. Create the style and assign it to the created resource # # FIXME: Put this in gsconfig.py logger.info('>>> Step 7. Creating style for [%s]' % name) publishing = cat.get_layer(name) create_style() sld = get_sld_for(gs_catalog, publishing) style = None if sld is not None: try: cat.create_style(name, sld) style = cat.get_style(name) except geoserver.catalog.ConflictingDataError as e: msg = ('There was already a style named %s in GeoServer, ' 'try to use: "%s"' % (name + "_layer", str(e))) logger.warn(msg) e.args = (msg, ) try: cat.create_style(name + '_layer', sld) style = cat.get_style(name + "_layer") except geoserver.catalog.ConflictingDataError as e: style = cat.get_style('point') msg = ('There was already a style named %s in GeoServer, ' 'cannot overwrite: "%s"' % (name, str(e))) logger.error(msg) e.args = (msg, ) # FIXME: Should we use the fully qualified typename? publishing.default_style = style cat.save(publishing) return gs_resource
class GeoserverLayers(object): def __init__(self, gs_apirest, username, password): try: self.__catalog = Catalog(gs_apirest, username=username, password=password) except Exception as err: print("Geoserver API Rest Error: {0}".format(err)) def __createSldStyle(self, sldpath, stylename, ovwrt=False): try: styles_list = [st.name for st in self.__catalog.get_styles()] if ovwrt or not stylename in styles_list: with open(sldpath) as f: self.__catalog.create_style(stylename, f.read(), overwrite=ovwrt) else: print("This style already exists...") except Exception as err: print("Geoserver API Rest Error creating new style: {0}".format(err)) def __rmvResources(self, rsrc): """ Removing resources """ self.__catalog.delete(rsrc) self.__catalog.reload() def rmvStyle(self, stylename): """ Remove style """ try: style = self.__catalog.get_style(stylename) self.__rmvResources(style) except Exception as err: print("Geoserver API Rest Error removing style: {0}".format(err)) def rmvDataStore(self, ds_store): """ Remove DataStore (with his layer) """ try: lay_rm = self.__catalog.get_layer(ds_store) self.__rmvResources(lay_rm) str_rm = self.__catalog.get_store(ds_store) self.__rmvResources(str_rm) except Exception as err: print("Geoserver API Rest Error removing data store: {0}".format(err)) def createGeoserverWMSLayer(self, data, ws_name, ds_name, stylename, sldpath, debug=False): """ Create Geoserver WMS layer Status codes: 2 : "Geoserver layer successfully created" -1 : "Workspace does not exist" -2 : "Datastore already exists" -3 : "Error creating Geoserver layer" -4 : "File missing" """ try: if not self.__catalog.get_workspace(ws_name): print("Workspace does not exist") return -1 ds_list = [i.name for i in self.__catalog.get_stores()] if ds_name in ds_list: print("Datastore already exists") return -2 ds = self.__catalog.create_datastore(ds_name, ws_name) ft = self.__catalog.create_featurestore(ds_name, workspace=ws_name,data=data) print("Geoserver layer successfully created...") self.__createSldStyle(sldpath, stylename) lyr = self.__catalog.get_layer(ds_name) lyr.enabled = True lyr.default_style = stylename self.__catalog.save(lyr) if debug: rsrc = self.__catalog.get_resource(ds_name, workspace=ws_name) print("Data Store XML: {}".format(rsrc.href)) return 2 except Exception as err: print("Geoserver API Rest Error creating new layer: {0}".format(err)) return -3
def publishGeoserver(appdef, progress): viewCrs = appdef["Settings"]["App view CRS"] usesGeoServer = False for applayer in appdef["Layers"]: if applayer.method != METHOD_FILE: if applayer.layer.type() == applayer.layer.VectorLayer and applayer.layer.providerType().lower() != "wfs": usesGeoServer = True if not usesGeoServer: return progress.setText("Publishing to GeoServer") progress.setProgress(0) geoserverUrl = appdef["Deploy"]["GeoServer url"] + "/rest" geoserverPassword = appdef["Deploy"]["GeoServer password"] geoserverUsername = appdef["Deploy"]["GeoServer username"] workspaceName = appdef["Deploy"]["GeoServer workspace"] dsName = "ds_" + workspaceName host = appdef["Deploy"]["PostGIS host"] port = appdef["Deploy"]["PostGIS port"] postgisUsername = appdef["Deploy"]["PostGIS username"] postgisPassword = appdef["Deploy"]["PostGIS password"] database = appdef["Deploy"]["PostGIS database"] schema = appdef["Deploy"]["PostGIS schema"] catalog = Catalog(geoserverUrl, geoserverUsername, geoserverPassword) workspace = catalog.get_workspace(workspaceName) if workspace is None: workspace = catalog.create_workspace(workspaceName, workspaceName) try: store = catalog.get_store(dsName, workspace) resources = store.get_resources() for resource in resources: layers = catalog.get_layers(resource) for layer in layers: catalog.delete(layer) catalog.delete(resource) catalog.delete(store) except Exception: pass try: store = catalog.get_store(dsName, workspace) except FailedRequestError: store = None for i, applayer in enumerate(appdef["Layers"]): layer = applayer.layer if applayer.method != METHOD_FILE and applayer.method != METHOD_DIRECT: name = safeName(layer.name()) sld, icons = getGsCompatibleSld(layer) if sld is not None: catalog.create_style(name, sld, True) uploadIcons(icons, geoserverUsername, geoserverPassword, catalog.gs_base_url) if layer.type() == layer.VectorLayer: if applayer.method == METHOD_WFS_POSTGIS or applayer.method == METHOD_WMS_POSTGIS: if store is None: store = catalog.create_datastore(dsName, workspace) store.connection_parameters.update( host=host, port=str(port), database=database, user=postgisUsername, schema=schema, passwd=postgisPassword, dbtype="postgis") catalog.save(store) catalog.publish_featuretype(name, store, layer.crs().authid()) else: path = getDataFromLayer(layer, viewCrs) catalog.create_featurestore(name, path, workspace=workspace, overwrite=True) gslayer = catalog.get_layer(name) r = gslayer.resource r.dirty['srs'] = viewCrs catalog.save(r) elif layer.type() == layer.RasterLayer: path = getDataFromLayer(layer, viewCrs) catalog.create_coveragestore(name, path, workspace=workspace, overwrite=True) if sld is not None: publishing = catalog.get_layer(name) publishing.default_style = catalog.get_style(name) catalog.save(publishing) progress.setProgress(int((i+1)*100.0/len(appdef["Layers"])))
class ModifyingTests(unittest.TestCase): def setUp(self): self.cat = Catalog("http://localhost:8080/geoserver/rest") def testFeatureTypeSave(self): # test saving round trip rs = self.cat.get_resource("bugsites") old_abstract = rs.abstract new_abstract = "Not the original abstract" enabled = rs.enabled # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(new_abstract, rs.abstract) self.assertEqual(enabled, rs.enabled) # Change keywords on server rs.keywords = ["bugsites", "gsconfig"] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(["bugsites", "gsconfig"], rs.keywords) self.assertEqual(enabled, rs.enabled) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(old_abstract, rs.abstract) def testDataStoreCreate(self): ds = self.cat.create_datastore("vector_gsconfig") ds.connection_parameters.update( host="localhost", port="5432", database="db", user="******", passwd="password", dbtype="postgis") self.cat.save(ds) def testDataStoreModify(self): ds = self.cat.get_store("sf") self.assertFalse("foo" in ds.connection_parameters) ds.connection_parameters = ds.connection_parameters ds.connection_parameters["foo"] = "bar" orig_ws = ds.workspace.name self.cat.save(ds) ds = self.cat.get_store("sf") self.assertTrue("foo" in ds.connection_parameters) self.assertEqual("bar", ds.connection_parameters["foo"]) self.assertEqual(orig_ws, ds.workspace.name) def testDataStoreCreateAndThenAlsoImportData(self): ds = self.cat.create_datastore("gsconfig_import_test") ds.connection_parameters.update( host="localhost", port="5432", database="db", user="******", passwd="password", dbtype="postgis") self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test") self.cat.add_data_to_store(ds, "import", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) def testCoverageStoreCreate(self): ds = self.cat.create_coveragestore2("coverage_gsconfig") ds.data_url = "file:data/mytiff.tiff" self.cat.save(ds) def testCoverageStoreModify(self): cs = self.cat.get_store("sfdem") self.assertEqual("GeoTIFF", cs.type) cs.type = "WorldImage" self.cat.save(cs) cs = self.cat.get_store("sfdem") self.assertEqual("WorldImage", cs.type) # not sure about order of test runs here, but it might cause problems # for other tests if this layer is misconfigured cs.type = "GeoTIFF" self.cat.save(cs) def testCoverageSave(self): # test saving round trip rs = self.cat.get_resource("Arc_Sample") old_abstract = rs.abstract new_abstract = "Not the original abstract" # # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(new_abstract, rs.abstract) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(old_abstract, rs.abstract) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) srs_before = set(['EPSG:4326']) srs_after = set(['EPSG:4326', 'EPSG:3785']) formats = set(['ARCGRID', 'ARCGRID-GZIP', 'GEOTIFF', 'PNG', 'GIF', 'TIFF']) formats_after = set(["PNG", "GIF", "TIFF"]) # set and save request_srs_list self.assertEquals(set(rs.request_srs_list), srs_before, str(rs.request_srs_list)) rs.request_srs_list = rs.request_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.request_srs_list), srs_after, str(rs.request_srs_list)) # set and save response_srs_list self.assertEquals(set(rs.response_srs_list), srs_before, str(rs.response_srs_list)) rs.response_srs_list = rs.response_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.response_srs_list), srs_after, str(rs.response_srs_list)) # set and save supported_formats self.assertEquals(set(rs.supported_formats), formats, str(rs.supported_formats)) rs.supported_formats = ["PNG", "GIF", "TIFF"] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.supported_formats), formats_after, str(rs.supported_formats)) def testFeatureTypeCreate(self): shapefile_plus_sidecars = shapefile_and_friends("test/data/states") expected = { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' } self.assertEqual(len(expected), len(shapefile_plus_sidecars)) for k, v in expected.iteritems(): self.assertEqual(v, shapefile_plus_sidecars[k]) sf = self.cat.get_workspace("sf") self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) self.assert_(self.cat.get_resource("states_test", workspace=sf) is not None) self.assertRaises( ConflictingDataError, lambda: self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) ) self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster_test", shapefile_plus_sidecars, sf) ) bogus_shp = { 'shp': 'test/data/Pk50095.tif', 'shx': 'test/data/Pk50095.tif', 'dbf': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } self.assertRaises( UploadError, lambda: self.cat.create_featurestore("bogus_shp", bogus_shp, sf) ) lyr = self.cat.get_layer("states_test") self.cat.delete(lyr) self.assert_(self.cat.get_layer("states_test") is None) def testCoverageCreate(self): tiffdata = { 'tiff': 'test/data/Pk50095.tif', 'tfw': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } sf = self.cat.get_workspace("sf") # TODO: Uploading WorldImage file no longer works??? # ft = self.cat.create_coveragestore("Pk50095", tiffdata, sf) # self.assert_(self.cat.get_resource("Pk50095", workspace=sf) is not None) # self.assertRaises( # ConflictingDataError, # lambda: self.cat.create_coveragestore("Pk50095", tiffdata, sf) # ) self.assertRaises( UploadError, lambda: self.cat.create_featurestore("Pk50095_vector", tiffdata, sf) ) bogus_tiff = { 'tiff': 'test/data/states.shp', 'tfw': 'test/data/states.shx', 'prj': 'test/data/states.prj' } self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster", bogus_tiff) ) def testLayerSave(self): # test saving round trip lyr = self.cat.get_layer("states") old_attribution = lyr.attribution new_attribution = "Not the original attribution" # change attribution on server lyr.attribution = new_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(new_attribution, lyr.attribution) # Restore attribution lyr.attribution = old_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(old_attribution, lyr.attribution) self.assertEqual(lyr.default_style.name, "population") old_default_style = lyr.default_style lyr.default_style = (s for s in lyr.styles if s.name == "pophatch").next() lyr.styles = [old_default_style] self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(lyr.default_style.name, "pophatch") self.assertEqual([s.name for s in lyr.styles], ["population"]) def testStyles(self): # upload new style, verify existence self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Fred", fred.sld_title) # replace style, verify changes self.cat.create_style("fred", open("test/ted.sld").read(), overwrite=True) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Ted", fred.sld_title) # delete style, verify non-existence self.cat.delete(fred, purge=True) self.assert_(self.cat.get_style("fred") is None) # attempt creating new style self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assertEqual("Fred", fred.sld_title) def testWorkspaceCreate(self): ws = self.cat.get_workspace("acme") self.assertEqual(None, ws) self.cat.create_workspace("acme", "http://example.com/acme") ws = self.cat.get_workspace("acme") self.assertEqual("acme", ws.name) def testWorkspaceDelete(self): self.cat.create_workspace("foo", "http://example.com/foo") ws = self.cat.get_workspace("foo") self.cat.delete(ws) ws = self.cat.get_workspace("foo") self.assert_(ws is None) def testFeatureTypeDelete(self): pass def testCoverageDelete(self): pass def testDataStoreDelete(self): states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) states.enabled = False self.assert_(states.enabled == False) self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == False) states.enabled = True self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) def testLayerGroupSave(self): tas = self.cat.get_layergroup("tasmania") self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads', 'tasmania_cities'], tas.layers) self.assertEqual(tas.styles, [None, None, None, None], tas.styles) tas.layers = tas.layers[:-1] tas.styles = tas.styles[:-1] self.cat.save(tas) self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads'], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles)
class GsConn(): def __init__(self, host, login, password, debug=False): """ Geoserver connection """ self.host = host self.login = login self.password = password self.debug = debug # Connect to server self.cat = Catalog("http://%s/geoserver/rest" % host, login, password) if self.debug is True: print "Connected to geoserver" def crate_workspace(self, name, uri, overwrite=False): """ Creates a workspace :param name: Workspace name. :param overwrite: If True, delete existing workspace. :return: None """ workspaces = [ workspace.name for workspace in self.cat.get_workspaces() ] if name in workspaces and overwrite is True: # ws2del = self.cat.get_workspace(name) # self.cat.delete(ws2del, purge=True, recurse=True) return None # NOTE: If we delete the workspace then all associated layers are lost. elif name in workspaces and overwrite is False: print "ERROR: Workspace %s already exists (use overwrite=True)." % name self.cat.create_workspace(name, uri) if self.debug is True: print "Workspace %s available." % name ws = self.cat.get_workspace(name) ws.enabled = True def create_pg_store(self, name, workspace, host, port, login, password, dbname, schema, overwrite=False): """ Creates datastore. :param name: Name of the datastore. :param workspace: Name of the workspace to use. :param overwrite: If True replace datastore. :return: None """ stores = [store.name for store in self.cat.get_stores()] if name in stores and overwrite is True: # st2del = self.cat.get_store(name) # self.cat.delete(st2del, purge=True, recurse=True) # self.cat.reload() return None # NOTE: If we delete store, every layers associated with are lost. elif name in stores and overwrite is False: print "ERROR: Store %s already exists (use overwrite=True)." % name ds = self.cat.create_datastore(name, workspace) ds.connection_parameters.update(host=host, port=port, user=login, passwd=password, dbtype='postgis', database=dbname, schema=schema) self.cat.save(ds) ds = self.cat.get_store(name) if ds.enabled is False: print "ERROR: Geoserver store %s not enabled" % name if self.debug is True: print "Datastore %s created." % name def publish_pg_layer(self, layer_table, layer_name, store, srid, overwrite=True): """ """ existing_lyr = self.cat.get_layer("participatubes:%s" % layer_table) if existing_lyr is not None: print "Layer participatubes:%s already exists, deleting it." % layer_table self.cat.delete(existing_lyr) self.cat.reload() ds = self.cat.get_store(store) ft = self.cat.publish_featuretype(layer_table, ds, 'EPSG:%s' % srid, srs='EPSG:4326') ft.projection_policy = "REPROJECT_TO_DECLARED" ft.title = layer_name self.cat.save(ft) if ft.enabled is False: print "ERROR: Layer %s %s %s is not enabled." (ft.workspace.name, ft.store.name, ft.title) if self.debug is True: print "Layer %s>%s>%s published." % (ft.workspace.name, ft.store.name, ft.title) def create_style_from_sld(self, style_name, sld_file, workspace, overwrite=True): """ """ if self.cat.get_style(style_name) is not None: print "Style %s already exists, deleting it." % style_name style2del = self.cat.get_style(style_name) self.cat.delete(style2del) self.cat.create_style( style_name, open(sld_file).read(), overwrite=overwrite ) # FIXME: if ", workspace=workspace" specified can't delete style if self.debug is True: print "Style %s created in Geoserver" % style_name def apply_style_to_layer(self, layer_name, style_name): """ Apply a geoserver styler to a layer """ gs_layer = self.cat.get_layer(layer_name) gs_style = self.cat.get_style(style_name) # FIXME: Which works better? # gs_layer.default_style = gs_style / gs_layer._set_default_style(gs_style) # FIXME: Maybe indicate workspace when saving style then name the style as "workspace:style" gs_layer._set_default_style(gs_style) self.cat.save(gs_layer) if self.debug is True: print "Style applied to %s" % layer_name
class ModifyingTests(unittest.TestCase): def setUp(self): self.cat = Catalog(GSPARAMS['GSURL'], username=GSPARAMS['GSUSER'], password=GSPARAMS['GSPASSWORD']) def testFeatureTypeSave(self): # test saving round trip rs = self.cat.get_resource("bugsites") old_abstract = rs.abstract new_abstract = "Not the original abstract" enabled = rs.enabled # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(new_abstract, rs.abstract) self.assertEqual(enabled, rs.enabled) # Change keywords on server rs.keywords = ["bugsites", "gsconfig"] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(["bugsites", "gsconfig"], rs.keywords) self.assertEqual(enabled, rs.enabled) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual([ ("text/xml", "TC211", "http://example.com/gsconfig.test.metadata") ], rs.metadata_links) self.assertEqual(enabled, rs.enabled) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(old_abstract, rs.abstract) def testDataStoreCreate(self): ds = self.cat.create_datastore("vector_gsconfig") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) def testPublishFeatureType(self): # Use the other test and store creation to load vector data into a database # @todo maybe load directly to database? try: self.testDataStoreCreateAndThenAlsoImportData() except FailedRequestError: pass try: lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) ds = self.cat.get_store("gsconfig_import_test") # make sure it's gone self.assertIsNone(self.cat.get_layer('import')) self.cat.publish_featuretype("import", ds, native_crs="EPSG:4326") # and now it's not self.assertIsNotNone(self.cat.get_layer('import')) finally: # tear stuff down to allow the other test to pass if we run first ds = self.cat.get_store("gsconfig_import_test") lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. try: if lyr: self.cat.delete(lyr) self.cat.delete(lyr.resource) if ds: self.cat.delete(ds) except Exception: pass def testDataStoreModify(self): ds = self.cat.get_store("sf") self.assertFalse("foo" in ds.connection_parameters) ds.connection_parameters = ds.connection_parameters ds.connection_parameters["foo"] = "bar" orig_ws = ds.workspace.name self.cat.save(ds) ds = self.cat.get_store("sf") self.assertTrue("foo" in ds.connection_parameters) self.assertEqual("bar", ds.connection_parameters["foo"]) self.assertEqual(orig_ws, ds.workspace.name) @drop_table('import') def testDataStoreCreateAndThenAlsoImportData(self): ds = self.cat.create_datastore("gsconfig_import_test") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test") self.cat.add_data_to_store( ds, "import", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) @drop_table('import2') def testVirtualTables(self): ds = self.cat.create_datastore("gsconfig_import_test2") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test2") self.cat.add_data_to_store( ds, "import2", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) store = self.cat.get_store("gsconfig_import_test2") geom = JDBCVirtualTableGeometry('the_geom', 'MultiPolygon', '4326') ft_name = 'my_jdbc_vt_test' epsg_code = 'EPSG:4326' sql = "select * from import2 where 'STATE_NAME' = 'Illinois'" keyColumn = None parameters = None jdbc_vt = JDBCVirtualTable(ft_name, sql, 'false', geom, keyColumn, parameters) self.cat.publish_featuretype(ft_name, store, epsg_code, jdbc_virtual_table=jdbc_vt) # DISABLED; this test works only in the very particular case # "mytiff.tiff" is already present into the GEOSERVER_DATA_DIR # def testCoverageStoreCreate(self): # ds = self.cat.create_coveragestore2("coverage_gsconfig") # ds.data_url = "file:test/data/mytiff.tiff" # self.cat.save(ds) def testCoverageStoreModify(self): cs = self.cat.get_store("sfdem") self.assertEqual("GeoTIFF", cs.type) cs.type = "WorldImage" self.cat.save(cs) cs = self.cat.get_store("sfdem") self.assertEqual("WorldImage", cs.type) # not sure about order of test runs here, but it might cause problems # for other tests if this layer is misconfigured cs.type = "GeoTIFF" self.cat.save(cs) def testCoverageSave(self): # test saving round trip rs = self.cat.get_resource("Arc_Sample") old_abstract = rs.abstract new_abstract = "Not the original abstract" # # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(new_abstract, rs.abstract) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(old_abstract, rs.abstract) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual([ ("text/xml", "TC211", "http://example.com/gsconfig.test.metadata") ], rs.metadata_links) self.assertEqual(enabled, rs.enabled) srs_before = set(['EPSG:4326']) srs_after = set(['EPSG:4326', 'EPSG:3785']) formats = set( ['ARCGRID', 'ARCGRID-GZIP', 'GEOTIFF', 'PNG', 'GIF', 'TIFF']) formats_after = set(["PNG", "GIF", "TIFF"]) # set and save request_srs_list self.assertEqual(set(rs.request_srs_list), srs_before, str(rs.request_srs_list)) rs.request_srs_list = rs.request_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(set(rs.request_srs_list), srs_after, str(rs.request_srs_list)) # set and save response_srs_list self.assertEqual(set(rs.response_srs_list), srs_before, str(rs.response_srs_list)) rs.response_srs_list = rs.response_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(set(rs.response_srs_list), srs_after, str(rs.response_srs_list)) # set and save supported_formats self.assertEqual(set(rs.supported_formats), formats, str(rs.supported_formats)) rs.supported_formats = ["PNG", "GIF", "TIFF"] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(set(rs.supported_formats), formats_after, str(rs.supported_formats)) def testWmsStoreCreate(self): ws = self.cat.create_wmsstore("wmsstore_gsconfig") ws.capabilitiesURL = "http://mesonet.agron.iastate.edu/cgi-bin/wms/iowa/rainfall.cgi?VERSION=1.1.1&REQUEST=GetCapabilities&SERVICE=WMS&" # noqa: E501 ws.type = "WMS" self.cat.save(ws) def testWmsLayer(self): self.cat.create_workspace("wmstest", "http://example.com/wmstest") wmstest = self.cat.get_workspace("wmstest") wmsstore = self.cat.create_wmsstore("wmsstore", wmstest) wmsstore.capabilitiesURL = "http://mesonet.agron.iastate.edu/cgi-bin/wms/iowa/rainfall.cgi?VERSION=1.1.1&REQUEST=GetCapabilities&SERVICE=WMS&" # noqa: E501 wmsstore.type = "WMS" self.cat.save(wmsstore) wmsstore = self.cat.get_store("wmsstore") self.assertEqual(1, len(self.cat.get_stores(workspace=wmstest))) available_layers = wmsstore.get_resources(available=True) for layer in available_layers: # sanitize the layer name - validation will fail on newer geoservers name = layer.replace(':', '_') self.cat.create_wmslayer(wmstest, wmsstore, name, nativeName=layer) added_layers = wmsstore.get_resources() self.assertEqual(len(available_layers), len(added_layers)) changed_layer = added_layers[0] self.assertEqual(True, changed_layer.advertised) self.assertEqual(True, changed_layer.enabled) changed_layer.advertised = False changed_layer.enabled = False self.cat.save(changed_layer) self.cat._cache.clear() changed_layer = wmsstore.get_resources()[0] changed_layer.fetch() self.assertEqual(False, changed_layer.advertised) self.assertEqual(False, changed_layer.enabled) # Testing projection and projection policy changes changed_layer.projection = "EPSG:900913" changed_layer.projection_policy = "REPROJECT_TO_DECLARED" self.cat.save(changed_layer) self.cat._cache.clear() layer = self.cat.get_layer(changed_layer.name) self.assertEqual(layer.resource.projection_policy, changed_layer.projection_policy) self.assertEqual(layer.resource.projection, changed_layer.projection) def testFeatureTypeCreate(self): shapefile_plus_sidecars = shapefile_and_friends("test/data/states") expected = { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' } self.assertEqual(len(expected), len(shapefile_plus_sidecars)) for k, v in expected.items(): self.assertEqual(v, shapefile_plus_sidecars[k]) sf = self.cat.get_workspace("sf") self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) self.assertIsNotNone(self.cat.get_resource("states_test", workspace=sf)) self.assertRaises( ConflictingDataError, lambda: self.cat.create_featurestore( "states_test", shapefile_plus_sidecars, sf)) self.assertRaises( UploadError, lambda: self.cat.create_coveragestore( "states_raster_test", shapefile_plus_sidecars, sf)) bogus_shp = { 'shp': 'test/data/Pk50095.tif', 'shx': 'test/data/Pk50095.tif', 'dbf': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } self.assertRaises( UploadError, lambda: self.cat.create_featurestore("bogus_shp", bogus_shp, sf)) lyr = self.cat.get_layer("states_test") self.cat.delete(lyr) self.assertIsNone(self.cat.get_layer("states_test")) def testCoverageCreate(self): tiffdata = { 'tiff': 'test/data/Pk50095.tif', 'tfw': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } sf = self.cat.get_workspace("sf") self.cat.create_coveragestore("Pk50095", tiffdata, sf) self.assertIsNotNone(self.cat.get_resource("Pk50095", workspace=sf)) self.assertRaises( ConflictingDataError, lambda: self.cat.create_coveragestore("Pk50095", tiffdata, sf)) self.assertRaises( UploadError, lambda: self.cat.create_featurestore( "Pk50095_vector", tiffdata, sf)) bogus_tiff = { 'tiff': 'test/data/states.shp', 'tfw': 'test/data/states.shx', 'prj': 'test/data/states.prj' } self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster", bogus_tiff)) self.cat.create_coveragestore_external_geotiff( "Pk50095_ext", 'file:test/data/Pk50095.tif', sf) def testLayerSave(self): # test saving round trip lyr = self.cat.get_layer("states") old_attribution = lyr.attribution new_attribution = { 'title': 'Not the original attribution', 'width': '123', 'height': '321', 'href': 'http://www.georchestra.org', 'url': 'https://www.cigalsace.org/portail/cigal/documents/page/mentions-legales/Logo_geOrchestra.jpg', 'type': 'image/jpeg' } # change attribution on server lyr.attribution = new_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(new_attribution, lyr.attribution) # Restore attribution lyr.attribution = old_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(old_attribution, lyr.attribution) self.assertEqual(lyr.default_style.name, "population") old_default_style = lyr.default_style lyr.default_style = next( (s for s in lyr.styles if s.name == "pophatch")) lyr.styles = [old_default_style] self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(lyr.default_style.name, "pophatch") self.assertEqual([s.name for s in lyr.styles], ["population"]) def testStyles(self): # check count before tests (upload) count = len(self.cat.get_styles()) # upload new style, verify existence with open("test/fred.sld") as fred_sld: self.cat.create_style("fred", fred_sld.read()) fred = self.cat.get_style("fred") self.assertIsNotNone(fred) self.assertEqual("Fred", fred.sld_title) # replace style, verify changes with open("test/ted.sld") as ted_sld: self.cat.create_style("fred", ted_sld.read(), overwrite=True) fred = self.cat.get_style("fred") self.assertIsNotNone(fred) self.assertEqual("Ted", fred.sld_title) # delete style, verify non-existence self.cat.delete(fred, purge=True) self.assertIsNone(self.cat.get_style("fred")) # attempt creating new style with open("test/fred.sld") as fred_sld: self.cat.create_style("fred", fred_sld.read()) fred = self.cat.get_style("fred") self.assertEqual("Fred", fred.sld_title) # verify it can be found via URL and check the name f = self.cat.get_style_by_url(fred.href) self.assertIsNotNone(f) self.assertEqual(f.name, fred.name) # compare count after upload self.assertEqual(count + 1, len(self.cat.get_styles())) # attempt creating a new style without "title" with open("test/notitle.sld") as notitle_sld: self.cat.create_style("notitle", notitle_sld.read()) notitle = self.cat.get_style("notitle") self.assertEqual(None, notitle.sld_title) def testWorkspaceStyles(self): # upload new style, verify existence with open("test/fred.sld") as fred_sld: self.cat.create_style("jed", fred_sld.read(), workspace="topp") jed = self.cat.get_style("jed", workspace="blarny") self.assertIsNone(jed) jed = self.cat.get_style("jed", workspace="topp") self.assertIsNotNone(jed) self.assertEqual("Fred", jed.sld_title) jed = self.cat.get_style("topp:jed") self.assertIsNotNone(jed) self.assertEqual("Fred", jed.sld_title) # replace style, verify changes with open("test/ted.sld") as ted_sld: self.cat.create_style("jed", ted_sld.read(), overwrite=True, workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assertIsNotNone(jed) self.assertEqual("Ted", jed.sld_title) # delete style, verify non-existence self.cat.delete(jed, purge=True) self.assertIsNone(self.cat.get_style("jed", workspace="topp")) # attempt creating new style with open("test/fred.sld") as fred_sld: self.cat.create_style("jed", fred_sld.read(), workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assertEqual("Fred", jed.sld_title) # verify it can be found via URL and check the full name f = self.cat.get_style_by_url(jed.href) self.assertIsNotNone(f) self.assertEqual(f.fqn, jed.fqn) def testLayerWorkspaceStyles(self): # upload new style, verify existence with open("test/fred.sld") as fred_sld: self.cat.create_style("ned", fred_sld.read(), overwrite=True, workspace="topp") with open("test/fred.sld") as ted_sld: self.cat.create_style("zed", ted_sld.read(), overwrite=True, workspace="topp") ned = self.cat.get_style("ned", workspace="topp") zed = self.cat.get_style("zed", workspace="topp") self.assertIsNotNone(ned) self.assertIsNotNone(zed) lyr = self.cat.get_layer("states") lyr.default_style = ned lyr.styles = [zed] self.cat.save(lyr) self.assertEqual("topp:ned", lyr.default_style) self.assertEqual([zed], lyr.styles) lyr.refresh() if lyr.default_style is not None: self.assertEqual("topp:ned", lyr.default_style.fqn) self.assertEqual([zed.fqn], [s.fqn for s in lyr.styles]) def testWorkspaceCreate(self): ws = self.cat.get_workspace("acme") self.assertEqual(None, ws) self.cat.create_workspace("acme", "http://example.com/acme") ws = self.cat.get_workspace("acme") self.assertEqual("acme", ws.name) def testWorkspaceDelete(self): self.cat.create_workspace("foo", "http://example.com/foo") ws = self.cat.get_workspace("foo") self.cat.delete(ws) ws = self.cat.get_workspace("foo") self.assertIsNone(ws) def testWorkspaceDefault(self): # save orig orig = self.cat.get_default_workspace() neu = self.cat.create_workspace("neu", "http://example.com/neu") try: # make sure setting it works self.cat.set_default_workspace("neu") ws = self.cat.get_default_workspace() self.assertEqual('neu', ws.name) finally: # cleanup and reset to the way things were self.cat.delete(neu) self.cat.set_default_workspace(orig.name) ws = self.cat.get_default_workspace() self.assertEqual(orig.name, ws.name) def testFeatureTypeDelete(self): pass def testCoverageDelete(self): pass def testDataStoreDelete(self): states = self.cat.get_store('states_shapefile') self.assertTrue(states.enabled) states.enabled = False self.assertFalse(states.enabled) self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assertFalse(states.enabled) states.enabled = True self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assertTrue(states.enabled) def testLayerGroupSave(self): tas = self.cat.get_layergroup("tasmania") self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads', 'tasmania_cities' ], tas.layers) self.assertEqual(tas.styles, [None, None, None, None], tas.styles) tas.layers = tas.layers[:-1] tas.styles = tas.styles[:-1] self.cat.save(tas) # this verifies the local state self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads' ], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) # force a refresh to check the remote state tas.refresh() self.assertEqual(tas.layers, [ 'tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads' ], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) def testImageMosaic(self): """ Test case for Issue #110 """ # testing the mosaic creation name = 'cea_mosaic' with open('test/data/mosaic/cea.zip', 'rb') as data: self.cat.create_imagemosaic(name, data) # get the layer resource back self.cat._cache.clear() resource = self.cat.get_layer(name).resource self.assertIsNotNone(resource) # delete granule from mosaic coverage = name store = self.cat.get_store(name) granules = self.cat.list_granules(coverage, store) self.assertEqual(1, len(granules['features'])) granule_id = name + '.1' self.cat.mosaic_delete_granule(coverage, store, granule_id) granules = self.cat.list_granules(coverage, store) self.assertEqual(0, len(granules['features'])) """ testing external Image mosaic creation """ name = 'cea_mosaic_external' path = 'test/data/mosaic/external' self.cat.create_imagemosaic(name, path, workspace='topp') self.cat._cache.clear() resource = self.cat.get_layer("external").resource self.assertIsNotNone(resource) # add granule to mosaic granule_path = 'test/data/mosaic/granules/cea_20150102.tif' self.cat.add_granule(granule_path, name, workspace='topp') granules = self.cat.list_granules("external", name, 'topp') self.assertEqual(2, len(granules['features'])) # add external granule to mosaic granule_path = os.path.join( os.getcwd(), 'test/data/mosaic/granules/cea_20150103.zip') self.cat.add_granule(granule_path, name, workspace='topp') granules = self.cat.list_granules("external", name, 'topp') self.assertEqual(3, len(granules['features'])) # Delete store store = self.cat.get_store(name) self.cat.delete(store, purge=True, recurse=True) self.cat._cache.clear() def testTimeDimension(self): sf = self.cat.get_workspace("sf") files = shapefile_and_friends( os.path.join(gisdata.GOOD_DATA, "time", "boxes_with_end_date")) self.cat.create_featurestore("boxes_with_end_date", files, sf) get_resource = lambda: self.cat._cache.clear() or self.cat.get_layer( 'boxes_with_end_date').resource # noqa: E501 # configure time as LIST resource = get_resource() timeInfo = DimensionInfo("time", "true", "LIST", None, "ISO8601", None, attribute="date") resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual("LIST", timeInfo.presentation) self.assertEqual(True, timeInfo.enabled) self.assertEqual("date", timeInfo.attribute) self.assertEqual("ISO8601", timeInfo.units) # disable time dimension timeInfo = resource.metadata['time'] timeInfo.enabled = False # since this is an xml property, it won't get written unless we modify it resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(False, timeInfo.enabled) # configure with interval, end_attribute and enable again timeInfo.enabled = True timeInfo.presentation = 'DISCRETE_INTERVAL' timeInfo.resolution = '3 days' timeInfo.end_attribute = 'enddate' resource.metadata = {'time': timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(True, timeInfo.enabled) self.assertEqual('DISCRETE_INTERVAL', timeInfo.presentation) self.assertEqual('3 days', timeInfo.resolution_str()) self.assertEqual('enddate', timeInfo.end_attribute)
def resolve(layer, style): if style is not None: return (layer, style) else: return (layer, demo.get_layer(layer).default_style.name) g = demo.get_layergroup("groupname") resolved = [resolve(l, s) for (l, s) in zip(g.layers, g.styles)] # upload all styles to live for (l, s) in resolved: wayne_style = prefix + s style_on_server = live.get_style(wayne_style) sld = demo.get_style(s).sld_body if style_on_server is None: live.create_style(wayne_style, sld) else: style_on_server.update_body(sld) backup_layernames = {} # check that all requisite layers exist! for (l, s) in resolved: assert live.get_layer(l) is not None or l in backup_layernames, l lyrs = [backup_layernames.get(x[0], x[0]) for x in resolved] stls = [(prefix + x[1]) for x in resolved] wayne_group = live.get_layergroup(groupname) if wayne_group is None: wayne_group = live.create_layergroup(groupname) wayne_group.layers = lyrs
class ModifyingTests(unittest.TestCase): def setUp(self): self.cat = Catalog(GSPARAMS['GSURL'], username=GSPARAMS['GSUSER'], password=GSPARAMS['GSPASSWORD']) def testFeatureTypeSave(self): # test saving round trip rs = self.cat.get_resource("bugsites") old_abstract = rs.abstract new_abstract = "Not the original abstract" enabled = rs.enabled # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(new_abstract, rs.abstract) self.assertEqual(enabled, rs.enabled) # Change keywords on server rs.keywords = ["bugsites", "gsconfig"] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(["bugsites", "gsconfig"], rs.keywords) self.assertEqual(enabled, rs.enabled) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(old_abstract, rs.abstract) def testDataStoreCreate(self): ds = self.cat.create_datastore("vector_gsconfig") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) def testPublishFeatureType(self): # Use the other test and store creation to load vector data into a database # @todo maybe load directly to database? try: self.testDataStoreCreateAndThenAlsoImportData() except FailedRequestError: pass try: lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) ds = self.cat.get_store("gsconfig_import_test") # make sure it's gone self.assert_(self.cat.get_layer('import') is None) self.cat.publish_featuretype("import", ds, native_crs="EPSG:4326") # and now it's not self.assert_(self.cat.get_layer('import') is not None) finally: # tear stuff down to allow the other test to pass if we run first ds = self.cat.get_store("gsconfig_import_test") lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. try: if lyr: self.cat.delete(lyr) self.cat.delete(lyr.resource) if ds: self.cat.delete(ds) except: pass def testDataStoreModify(self): ds = self.cat.get_store("sf") self.assertFalse("foo" in ds.connection_parameters) ds.connection_parameters = ds.connection_parameters ds.connection_parameters["foo"] = "bar" orig_ws = ds.workspace.name self.cat.save(ds) ds = self.cat.get_store("sf") self.assertTrue("foo" in ds.connection_parameters) self.assertEqual("bar", ds.connection_parameters["foo"]) self.assertEqual(orig_ws, ds.workspace.name) @drop_table('import') def testDataStoreCreateAndThenAlsoImportData(self): ds = self.cat.create_datastore("gsconfig_import_test") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test") self.cat.add_data_to_store(ds, "import", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) @drop_table('import2') def testVirtualTables(self): ds = self.cat.create_datastore("gsconfig_import_test2") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test2") self.cat.add_data_to_store(ds, "import2", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) store = self.cat.get_store("gsconfig_import_test2") geom = JDBCVirtualTableGeometry('the_geom','MultiPolygon','4326') ft_name = 'my_jdbc_vt_test' epsg_code = 'EPSG:4326' sql = "select * from import2 where 'STATE_NAME' = 'Illinois'" keyColumn = None parameters = None jdbc_vt = JDBCVirtualTable(ft_name, sql, 'false', geom, keyColumn, parameters) ft = self.cat.publish_featuretype(ft_name, store, epsg_code, jdbc_virtual_table=jdbc_vt) # DISABLED; this test works only in the very particular case # "mytiff.tiff" is already present into the GEOSERVER_DATA_DIR # def testCoverageStoreCreate(self): # ds = self.cat.create_coveragestore2("coverage_gsconfig") # ds.data_url = "file:test/data/mytiff.tiff" # self.cat.save(ds) def testCoverageStoreModify(self): cs = self.cat.get_store("sfdem") self.assertEqual("GeoTIFF", cs.type) cs.type = "WorldImage" self.cat.save(cs) cs = self.cat.get_store("sfdem") self.assertEqual("WorldImage", cs.type) # not sure about order of test runs here, but it might cause problems # for other tests if this layer is misconfigured cs.type = "GeoTIFF" self.cat.save(cs) def testCoverageSave(self): # test saving round trip rs = self.cat.get_resource("Arc_Sample") old_abstract = rs.abstract new_abstract = "Not the original abstract" # # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(new_abstract, rs.abstract) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(old_abstract, rs.abstract) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) srs_before = set(['EPSG:4326']) srs_after = set(['EPSG:4326', 'EPSG:3785']) formats = set(['ARCGRID', 'ARCGRID-GZIP', 'GEOTIFF', 'PNG', 'GIF', 'TIFF']) formats_after = set(["PNG", "GIF", "TIFF"]) # set and save request_srs_list self.assertEquals(set(rs.request_srs_list), srs_before, str(rs.request_srs_list)) rs.request_srs_list = rs.request_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.request_srs_list), srs_after, str(rs.request_srs_list)) # set and save response_srs_list self.assertEquals(set(rs.response_srs_list), srs_before, str(rs.response_srs_list)) rs.response_srs_list = rs.response_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.response_srs_list), srs_after, str(rs.response_srs_list)) # set and save supported_formats self.assertEquals(set(rs.supported_formats), formats, str(rs.supported_formats)) rs.supported_formats = ["PNG", "GIF", "TIFF"] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.supported_formats), formats_after, str(rs.supported_formats)) def testWmsStoreCreate(self): ws = self.cat.create_wmsstore("wmsstore_gsconfig") ws.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" ws.type = "WMS" self.cat.save(ws) def testWmsLayer(self): self.cat.create_workspace("wmstest", "http://example.com/wmstest") wmstest = self.cat.get_workspace("wmstest") wmsstore = self.cat.create_wmsstore("wmsstore", wmstest) wmsstore.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" wmsstore.type = "WMS" self.cat.save(wmsstore) wmsstore = self.cat.get_store("wmsstore") self.assertEqual(1, len(self.cat.get_stores(wmstest))) available_layers = wmsstore.get_resources(available=True) for layer in available_layers: # sanitize the layer name - validation will fail on newer geoservers name = layer.replace(':', '_') new_layer = self.cat.create_wmslayer(wmstest, wmsstore, name, nativeName=layer) added_layers = wmsstore.get_resources() self.assertEqual(len(available_layers), len(added_layers)) changed_layer = added_layers[0] self.assertEqual(True, changed_layer.advertised) self.assertEqual(True, changed_layer.enabled) changed_layer.advertised = False changed_layer.enabled = False self.cat.save(changed_layer) self.cat._cache.clear() changed_layer = wmsstore.get_resources()[0] changed_layer.fetch() self.assertEqual(False, changed_layer.advertised) self.assertEqual(False, changed_layer.enabled) # Testing projection and projection policy changes changed_layer.projection = "EPSG:900913" changed_layer.projection_policy = "REPROJECT_TO_DECLARED" self.cat.save(changed_layer) self.cat._cache.clear() layer = self.cat.get_layer(changed_layer.name) self.assertEqual(layer.resource.projection_policy, changed_layer.projection_policy) self.assertEqual(layer.resource.projection, changed_layer.projection) def testFeatureTypeCreate(self): shapefile_plus_sidecars = shapefile_and_friends("test/data/states") expected = { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' } self.assertEqual(len(expected), len(shapefile_plus_sidecars)) for k, v in expected.iteritems(): self.assertEqual(v, shapefile_plus_sidecars[k]) sf = self.cat.get_workspace("sf") self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) self.assert_(self.cat.get_resource("states_test", workspace=sf) is not None) self.assertRaises( ConflictingDataError, lambda: self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) ) self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster_test", shapefile_plus_sidecars, sf) ) bogus_shp = { 'shp': 'test/data/Pk50095.tif', 'shx': 'test/data/Pk50095.tif', 'dbf': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } self.assertRaises( UploadError, lambda: self.cat.create_featurestore("bogus_shp", bogus_shp, sf) ) lyr = self.cat.get_layer("states_test") self.cat.delete(lyr) self.assert_(self.cat.get_layer("states_test") is None) def testCoverageCreate(self): tiffdata = { 'tiff': 'test/data/Pk50095.tif', 'tfw': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } sf = self.cat.get_workspace("sf") ft = self.cat.create_coveragestore("Pk50095", tiffdata, sf) self.assert_(self.cat.get_resource("Pk50095", workspace=sf) is not None) self.assertRaises( ConflictingDataError, lambda: self.cat.create_coveragestore("Pk50095", tiffdata, sf) ) self.assertRaises( UploadError, lambda: self.cat.create_featurestore("Pk50095_vector", tiffdata, sf) ) bogus_tiff = { 'tiff': 'test/data/states.shp', 'tfw': 'test/data/states.shx', 'prj': 'test/data/states.prj' } self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster", bogus_tiff) ) ft_ext = self.cat.create_coveragestore_external_geotiff("Pk50095_ext", 'file:test/data/Pk50095.tif', sf) def testLayerSave(self): # test saving round trip lyr = self.cat.get_layer("states") old_attribution = lyr.attribution new_attribution = { 'title': 'Not the original attribution', 'width': '123', 'height': '321', 'href': 'http://www.georchestra.org', 'url': 'https://www.cigalsace.org/portail/cigal/documents/page/mentions-legales/Logo_geOrchestra.jpg', 'type': 'image/jpeg' } # change attribution on server lyr.attribution = new_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(new_attribution, lyr.attribution) # Restore attribution lyr.attribution = old_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(old_attribution, lyr.attribution) self.assertEqual(lyr.default_style.name, "population") old_default_style = lyr.default_style lyr.default_style = (s for s in lyr.styles if s.name == "pophatch").next() lyr.styles = [old_default_style] self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(lyr.default_style.name, "pophatch") self.assertEqual([s.name for s in lyr.styles], ["population"]) def testStyles(self): # check count before tests (upload) count = len(self.cat.get_styles()) # upload new style, verify existence self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Fred", fred.sld_title) # replace style, verify changes self.cat.create_style("fred", open("test/ted.sld").read(), overwrite=True) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Ted", fred.sld_title) # delete style, verify non-existence self.cat.delete(fred, purge=True) self.assert_(self.cat.get_style("fred") is None) # attempt creating new style self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assertEqual("Fred", fred.sld_title) # verify it can be found via URL and check the name f = self.cat.get_style_by_url(fred.href) self.assert_(f is not None) self.assertEqual(f.name, fred.name) # compare count after upload self.assertEqual(count +1, len(self.cat.get_styles())) # attempt creating a new style without "title" self.cat.create_style("notitle", open("test/notitle.sld").read()) notitle = self.cat.get_style("notitle") self.assertEqual(None, notitle.sld_title) def testWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="blarny") self.assert_(jed is None) jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) jed = self.cat.get_style("topp:jed") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) # replace style, verify changes self.cat.create_style("jed", open("test/ted.sld").read(), overwrite=True, workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Ted", jed.sld_title) # delete style, verify non-existence self.cat.delete(jed, purge=True) self.assert_(self.cat.get_style("jed", workspace="topp") is None) # attempt creating new style self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assertEqual("Fred", jed.sld_title) # verify it can be found via URL and check the full name f = self.cat.get_style_by_url(jed.href) self.assert_(f is not None) self.assertEqual(f.fqn, jed.fqn) def testLayerWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("ned", open("test/fred.sld").read(), overwrite=True, workspace="topp") self.cat.create_style("zed", open("test/ted.sld").read(), overwrite=True, workspace="topp") ned = self.cat.get_style("ned", workspace="topp") zed = self.cat.get_style("zed", workspace="topp") self.assert_(ned is not None) self.assert_(zed is not None) lyr = self.cat.get_layer("states") lyr.default_style = ned lyr.styles = [zed] self.cat.save(lyr) self.assertEqual("topp:ned", lyr.default_style) self.assertEqual([zed], lyr.styles) lyr.refresh() self.assertEqual("topp:ned", lyr.default_style.fqn) self.assertEqual([zed.fqn], [s.fqn for s in lyr.styles]) def testWorkspaceCreate(self): ws = self.cat.get_workspace("acme") self.assertEqual(None, ws) self.cat.create_workspace("acme", "http://example.com/acme") ws = self.cat.get_workspace("acme") self.assertEqual("acme", ws.name) def testWorkspaceDelete(self): self.cat.create_workspace("foo", "http://example.com/foo") ws = self.cat.get_workspace("foo") self.cat.delete(ws) ws = self.cat.get_workspace("foo") self.assert_(ws is None) def testWorkspaceDefault(self): # save orig orig = self.cat.get_default_workspace() neu = self.cat.create_workspace("neu", "http://example.com/neu") try: # make sure setting it works self.cat.set_default_workspace("neu") ws = self.cat.get_default_workspace() self.assertEqual('neu', ws.name) finally: # cleanup and reset to the way things were self.cat.delete(neu) self.cat.set_default_workspace(orig.name) ws = self.cat.get_default_workspace() self.assertEqual(orig.name, ws.name) def testFeatureTypeDelete(self): pass def testCoverageDelete(self): pass def testDataStoreDelete(self): states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) states.enabled = False self.assert_(states.enabled == False) self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == False) states.enabled = True self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) def testLayerGroupSave(self): tas = self.cat.get_layergroup("tasmania") self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads', 'tasmania_cities'], tas.layers) self.assertEqual(tas.styles, [None, None, None, None], tas.styles) tas.layers = tas.layers[:-1] tas.styles = tas.styles[:-1] self.cat.save(tas) # this verifies the local state self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads'], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) # force a refresh to check the remote state tas.refresh() self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads'], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) def testImageMosaic(self): """ Test case for Issue #110 """ # testing the mosaic creation name = 'cea_mosaic' data = open('test/data/mosaic/cea.zip', 'rb') self.cat.create_imagemosaic(name, data) # get the layer resource back self.cat._cache.clear() resource = self.cat.get_layer(name).resource self.assert_(resource is not None) # delete granule from mosaic coverage = name store = self.cat.get_store(name) granule_id = name + '.1' self.cat.mosaic_delete_granule(coverage, store, granule_id) def testTimeDimension(self): sf = self.cat.get_workspace("sf") files = shapefile_and_friends(os.path.join(gisdata.GOOD_DATA, "time", "boxes_with_end_date")) self.cat.create_featurestore("boxes_with_end_date", files, sf) get_resource = lambda: self.cat._cache.clear() or self.cat.get_layer('boxes_with_end_date').resource # configure time as LIST resource = get_resource() timeInfo = DimensionInfo("time", "true", "LIST", None, "ISO8601", None, attribute="date") resource.metadata = {'time':timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual("LIST", timeInfo.presentation) self.assertEqual(True, timeInfo.enabled) self.assertEqual("date", timeInfo.attribute) self.assertEqual("ISO8601", timeInfo.units) # disable time dimension timeInfo = resource.metadata['time'] timeInfo.enabled = False # since this is an xml property, it won't get written unless we modify it resource.metadata = {'time' : timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(False, timeInfo.enabled) # configure with interval, end_attribute and enable again timeInfo.enabled = True timeInfo.presentation = 'DISCRETE_INTERVAL' timeInfo.resolution = '3 days' timeInfo.end_attribute = 'enddate' resource.metadata = {'time' : timeInfo} self.cat.save(resource) # and verify resource = get_resource() timeInfo = resource.metadata['time'] self.assertEqual(True, timeInfo.enabled) self.assertEqual('DISCRETE_INTERVAL', timeInfo.presentation) self.assertEqual('3 days', timeInfo.resolution_str()) self.assertEqual('enddate', timeInfo.end_attribute)
class GeoserverHelper: def __init__(self, geoserverUrl="", geoserverUserName="", geoserverPW="", geoserverWorkSpace="", postgreIP="", postgreUserName="", postgrePW=""): """use the constructor given arguments if used""" self.geoserverUrl = geoserverUrl if geoserverUrl != "" else GEOSERVERURL self.geoserverUserName = geoserverUserName if geoserverUserName != "" else GEOSERVERUSERNAME self.geoserverPW = geoserverPW if geoserverPW != "" else GEOSERVERPW self.geoserverWorkSpace = geoserverWorkSpace if geoserverWorkSpace != "" else "crc" self.postgreIP = postgreIP if postgreIP != "" else POSTGREIP self.postgreUserName = postgreUserName if postgreUserName != "" else POSTGREUSERNAME self.postgrePW = postgrePW if postgrePW != "" else POSTGREPW if self.geoserverUrl[-1] != '/': raise Exception("GeoserverUrl must end with a slash ('/')") self.catalog = Catalog(self.geoserverUrl + "rest/") self.catalog.http.add_credentials(self.geoserverUserName, self.geoserverPW) try: workspaces = self.catalog.get_workspaces() except: e = sys.exc_info()[0] print e self.cWorkSpace = self.catalog.get_workspace(self.geoserverWorkSpace) def getLayers(self): return self.cWorkSpace.catalog.get_layers() def insertShapeIntoPostGis(self, shapeFile, databaseName, tableName, encoding=3857): '''returns the returnCode of the execution of the insert script, e.g: helper.insertShapeIntoPostGis('/home/c815/gsTest/test.shp','crc','testingHelper2')''' if not os.path.isfile(shapeFile): print "Shape file not found" return -1 cmds = "PGPASSWORD={pgPW} ./createWSFTFromSHP.sh -s {shapeFileF} -d {databaseNameF} -t {tableNameF} -u {postgreUsername} -i {postgreIP}".format( pgPW=self.postgrePW, shapeFileF=shapeFile, databaseNameF=databaseName, tableNameF=tableName, postgreUsername=self.postgreUserName, postgreIP=self.postgreIP) return subprocess.call(cmds, shell=True) def uploadShapeFile(self, shapeFile, storeName): shpPlusSidcars = geoserver.util.shapefile_and_friends(shapeFile[:-3]) shpPlusSidcars self.ft = self.catalog.create_featurestore(storeName, shpPlusSidcars, self.cWorkSpace) def getStyles(self): return self.catalog.get_styles() def uploadStyleFile(self, sldFile, styleName, overWrite, workSpace=None): f = open(sldFile, 'r') styleSrc = f.read() uploadStyle(styleSrc, styleName, overWrite, workSpace) f.close() def uploadStyle(self, sldSrc, styleName, overWrite, workSpace=None): self.catalog.create_style(styleName, sldSrc, overWrite, workSpace) def publishPostGISLayer(self, postGISLayerName, storeName, crs='EPSG:3857'): '''cat.publish_featuretype('testingstuff',crcStore,native_crs='EPSG:3857')''' store = self.catalog.get_store(storeName) if store != None: self.catalog.publish_featuretype(postGISLayerName, store, crs) def setDefaultStyleForLayer(self, layerName, styleName): l = self.catalog.get_layer(layerName) sNames = [i.name for i in self.getStyles()] if styleName not in sNames: split = styleName.split(':') if len(split) == 2: workSpace = styleName.split(':')[0] newStyleName = styleName.split(':')[1] else: return -1 style = self.catalog.get_style(newStyleName, workSpace) if style is None: return -1 if l != None: l._set_default_style(styleName) self.catalog.save(l) return 0 def createPostGISDataStore(self, storeName, postGisPassword, postGisUser, postGisHost, postGisDatabase, workSpace=None): #check if connection parameter are valid try: conn = psycopg2.connect( "dbname='{dbName}' user='******' host='{Host}' password='******'" .format(dbName=postGisDatabase, dbUser=postGisUser, Host=postGisHost, password=postGisPassword)) except: return False w = self.catalog.create_datastore(storeName, workSpace) template = Template( """{'validate connections': 'true', 'port': '5432', 'Support on the fly geometry simplification': 'true', 'create database': 'false', 'dbtype': 'postgis', 'Connection timeout': '20', 'namespace': 'http://www.crcproject.com', 'Max connection idle time': '300', 'Expose primary keys': 'false', 'min connections': '1', 'Max open prepared statements':'50', 'passwd': '$passwd', 'encode functions': 'false', 'max connections': '10', 'Evictor tests per run': '3', 'Loose bbox': 'true', 'Evictor run periodicity': '300', 'Estimated extends': 'true', 'database': '$database', 'fetch size': '1000', 'Test while idle': 'true', 'host': '$host', 'preparedStatements': 'false', 'schema': 'public', 'user': '******'}""") dic = ast.literal_eval( template.substitute(passwd=postGisPassword, user=postGisUser, host=postGisHost, database=postGisDatabase)) #'passwd': 'crypt1:Bsaz2AUI8T+6Pj43krA7kg==', #'user': '******'} #'database': 'crc', #'host': 'localhost', w.connection_parameters = dic self.catalog.save(w) return True
def submitFiles(): """ Send the information of the uploaded files to the Open Data Registration Tool as an encoded JSON string in a GET-request The info is stored in a list of representations, according to the Open Data Registration Tool API: https://github.com/switchonproject/sip-html5-resource-registration/wiki """ threddsAvailable = True geoserverAvailable = True # Check if Thredds server is online threddsAvailable = checkConnection(app.config['THREDDS_SERVER'], "Failed to connect to the THREDDS server at " + app.config['THREDDS_SERVER'] + \ ". NetCDF files will not be accessible using web services, only by HTTP download.") # Check if GeoServer is online geoserverAvailable = checkConnection(app.config['GEOSERVER'], "Failed to connect to the geoserver at " + app.config['GEOSERVER'] + \ ". Shapefiles will not be mapped with WMS and can not be downloaded by WFS.") datasetname = session['DATASETNAME'] datasetFoldername = session['DATASETFOLDERNAME'] generateDOI = session['GENERATEDOI'] if request.form['submitButton'] == 'previous': return redirect('/?datasetname=' + datasetFoldername) if request.form['submitButton'] == 'next': datasetDir = os.path.join(app.config['BASE_UPLOAD_FOLDER'], datasetFoldername) files = [ f for f in os.listdir(datasetDir) if os.path.isfile(os.path.join(datasetDir, f)) and f not in app.config['IGNORED_FILES'] ] if len(files) > 0: representation = {} result = [] urlRoot = request.url_root.rstrip( '/' ) # get the url root without the traling '/' (for string concatenation) # Store the root url of the dataset as the primary representation if there are more than 1 file if len(files) > 1: representation['name'] = datasetname representation['description'] = "File download" representation['type'] = "original data" representation['contentlocation'] = '/'.join( [urlRoot, 'data', datasetFoldername]) representation['contenttype'] = "application/octet-stream" representation['function'] = "information" representation['protocol'] = "WWW:LINK-1.0-http--link" result.append(representation) # if there is only one file, store the direct link to this file if len(files) == 1: filename, fileExtension = os.path.splitext(f) # region Check if it is a zipped shapefile # if it is, ignore it (unless geoserver is unavailable), otherwise the zip file is added twice zippedShapefile = False if fileExtension == '.zip' and geoserverAvailable: zipFilePath = os.path.join(datasetDir, f) zipFile = zipfile.ZipFile(zipFilePath, 'r') filesInZip = zipFile.namelist() zipFile.close() for fileInZip in filesInZip: fileInZipExtension = os.path.splitext(fileInZip)[1] if fileInZipExtension == '.shp': zippedShapefile = True #endregion if fileExtension != '.nc' and zippedShapefile == False: representation['name'] = datasetname representation['description'] = "File download" representation['type'] = "original data" # TODO: improve file recognition if fileExtension == ".zip": representation['contenttype'] = "application/zip" else: representation[ 'contenttype'] = "application/octet-stream" representation['contentlocation'] = '/'.join( [urlRoot, 'data', datasetFoldername, f]) representation['function'] = "download" representation[ 'protocol'] = "WWW:DOWNLOAD-1.0-http--download" result.append(representation) #region THREDDS if threddsAvailable: if app.config['DEVELOP']: threddsCatalog = '/'.join((app.config['THREDDS_SERVER'], 'netcdftest', 'catalog.xml')) else: threddsCatalog = '/'.join( (app.config['THREDDS_SERVER'], datasetFoldername, 'catalog.xml')) try: opendapUrls = threddsclient.opendap_urls(threddsCatalog) for opendapUrl in opendapUrls: filepath, fileExtension = os.path.splitext(opendapUrl) filename = opendapUrl.split('/')[-1] # check if the file is a netCDF file; if yes, store OPeNDAP service url and html download url if fileExtension == '.nc': representation = {} representation['name'] = filename representation[ 'description'] = "Netcdf file OPeNDAP service" representation['contentlocation'] = opendapUrl representation[ 'contenttype'] = "application/x-netcdf" representation['type'] = "original data" representation['function'] = "service" representation['protocol'] = 'OPeNDAP:OPeNDAP' result.append(representation) representation = {} representation['name'] = filename representation[ 'description'] = "HTML interface OPeNDAP service" representation[ 'contentlocation'] = opendapUrl + ".html" representation[ 'contenttype'] = "application/x-netcdf" representation['type'] = "original data" representation['function'] = "download" representation[ 'protocol'] = 'WWW:DOWNLOAD-1.0-http--download' result.append(representation) representation = {} representation['name'] = filename representation['description'] = "WMS service" representation[ 'contentlocation'] = opendapUrl.replace( 'dodsC', 'wms' ) + "?service=WMS&version=1.3.0&request=GetCapabilities" representation['contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation[ 'protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' result.append(representation) except: app.logger.info("URL: " + threddsCatalog + " is not a THREDDS catalog") #endregion # region GEOSERVER: loop through all files to check for shapefiles if geoserverAvailable: for file in files: layerName = '' filename, fileExtension = os.path.splitext(file) if fileExtension == '.zip': zipFilePath = os.path.join(datasetDir, file) zipFile = zipfile.ZipFile(zipFilePath, 'r') filesInZip = zipFile.namelist() for fileInZip in filesInZip: fileInZipName = os.path.split(fileInZip)[1] fileInZipNoExtName, fileInZipExtension = os.path.splitext( fileInZipName) if fileInZipExtension == '.shp': # Layer name is the file without extension layerName = fileInZipNoExtName # Publish .zipped shapefile on geoserver, no subdirectories zipFile.extractall(datasetDir) for root, dirs, files in os.walk(datasetDir): for name in files: os.rename( os.path.join(root, name), os.path.join(datasetDir, name)) # create workspace r = requests.post( url=app.config['GEOSERVER'] + "/rest/workspaces", headers={'Content-type': 'text/xml'}, data="<workspace><name>" + datasetFoldername + "</name></workspace>", auth=HTTPBasicAuth( app.config['GEOSERVER_ADMIN'], app.config['GEOSERVER_PASS'])) if r.status_code > 299: # status code of 201 is success; all else is failure app.logger.error("Error in creating geoserver workspace for " + datasetFoldername + \ "; Status code: " + str(r.status_code) + ", Content: " + r.content) flash( "Error in creating workspace on geoserver." ) return redirect(url_for('uploadData')) # for testing purposes.. uploaded file is on local machine and can only publish data that is on the data mount of web app if app.config['DEVELOP']: shapeFile = "file://D:/sala/Downloads/sld_cookbook_polygon/sld_cookbook_polygon.shp" else: shapeFile = settings[ 'GEOSERVER_DATA_DIR'] + "/" + datasetFoldername + "/" + fileInZipName # Publish shapefile on the geoserver; the datastore is automatically created and has the same name as the shapefile + ds r = requests.put( url=app.config['GEOSERVER'] + "/rest/workspaces/" + datasetFoldername + "/datastores/" + datasetFoldername + "_ds/external.shp", headers={'Content-type': 'text/plain'}, data='file://' + shapeFile, auth=HTTPBasicAuth( app.config['GEOSERVER_ADMIN'], app.config['GEOSERVER_PASS'])) if r.status_code > 299: app.logger.error("Error in publishing shapefile " + datasetFoldername + " on geoserver; Status code: " \ + str(r.status_code) + ", Content: " + r.content) flash( "Error in publishing shapefile on geoserver." ) return redirect(url_for('uploadData')) representation = {} representation['name'] = layerName representation['description'] = "WMS service" representation['contentlocation'] = app.config['GEOSERVER'] + "/" + datasetFoldername + "/" + \ "wms?service=WMS&version=1.1.0&request=GetCapabilities" representation[ 'contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation[ 'protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' result.append(representation) representation = {} representation['name'] = layerName representation['description'] = "WMS service" representation['contentlocation'] = app.config['GEOSERVER'] + "/" + datasetFoldername + "/" + \ "wms?service=WMS&version=1.1.0&request=GetCapabilities" representation[ 'contenttype'] = "application/xml" representation['type'] = "aggregated data" representation['function'] = "service" representation[ 'protocol'] = 'OGC:WMS-1.1.1-http-get-capabilities' #region Get spatial extent from getcapabilities document try: root = ET.fromstring( requests.get( representation['contentlocation']). content) latlonElem = root.find( 'Capability/Layer/Layer/LatLonBoundingBox' ) latlonDict = latlonElem.attrib minx = latlonDict['minx'] miny = latlonDict['miny'] maxx = latlonDict['maxx'] maxy = latlonDict['maxy'] # WKT representation: POLYGON((minx miny, maxx miny, maxx maxy, minx maxy, minx miny)) WKTString = 'POLYGON(({0} {1}, {2} {1}, {2} {3}, {0} {3}, {0} {1}))'.format( minx, miny, maxx, maxy) representation[ 'wktboundingbox'] = WKTString except: app.logger.error( "Error in deriving WKT bounding box from WMS getcapabilities document" ) #endregion result.append(representation) representation = {} representation['name'] = fileInZipNoExtName representation['description'] = "WFS service" representation['contentlocation'] = app.config[ 'GEOSERVER'] + "/" + datasetFoldername + "/" + "ows?service=WFS&version=1.0.0&request=GetCapabilities" representation[ 'contenttype'] = "application/xml" representation['type'] = "original data" representation['function'] = "service" representation[ 'protocol'] = "OGC:WFS-1.0.0-http-get-capabilities" result.append(representation) representation = {} representation['name'] = file representation[ 'description'] = "Zipped shapefile" representation['contentlocation'] = '/'.join( [urlRoot, 'data', datasetFoldername, file]) representation[ 'contenttype'] = "application/zip" representation['type'] = "original data" representation['function'] = "download" representation[ 'protocol'] = "WWW:DOWNLOAD-1.0-http--download" representation[ 'uploadmessage'] = "deriveSpatialIndex:shp" result.append(representation) # Optional sld file (preconditions, shp uploaded, workspace created) for fileInZip in filesInZip: fileInZipName = os.path.split(fileInZip)[1] fileInZipNoExtName, fileInZipExtension = os.path.splitext( fileInZipName) if fileInZipExtension == '.sld': # for testing purposes.. uploaded file is on local machine and can only publish data that is on the data mount of web app if app.config['DEVELOP']: sldFile = "D:/sala/Downloads/sld_cookbook_polygon/sld_cookbook_polygon.sld" else: sldFile = settings[ 'GEOSERVER_DATA_DIR'] + "/" + datasetFoldername + "/" + fileInZipName # Connect to geoserver catalogue cat = Catalog( app.config['GEOSERVER'] + "/rest", app.config['GEOSERVER_ADMIN'], password=app.config['GEOSERVER_PASS']) # Add or Overwrite with open(sldFile) as f: style = cat.create_style( fileInZipNoExtName, f.read(), overwrite=True) # Link it to the layer layer = cat.get_layer(layerName) layer._set_default_style(fileInZipNoExtName) cat.save(layer) # close zip file after looping through all files in the zip file zipFile.close() #endregion # region if generateDOI: d = DOI(files, datasetDir, datasetname, logger=app.logger) deposition_id = d.runUpload() # endregion resultString = json.dumps(result) text = urllib.quote_plus(resultString.encode('utf-8')) if generateDOI: url = app.config[ 'METADATA_URL'] + text + '&deposition=' + deposition_id else: url = app.config['METADATA_URL'] + text # store the representation app.logger.info("Representations of the dataset: " + resultString) return redirect(url) else: flash("Please upload at least one file") return redirect(url_for('uploadData'))
class wrap_geoserver: """ Geoserver (gsconfig) wrapper """ def __init__(self, geoserver_name, username=username, password=password, easy=False): if geoserver_name in list(REST.keys()): self.path = REST[geoserver_name] else: self.path = geoserver_name self.wms = self.path.replace("rest/", "wms") self.name = geoserver_name self.catalog = Catalog(self.path, username, password) if not easy: self.layers = [] self.layer_names = [] for layer in self.catalog.get_layers(): self.layers.append(layer) self.layer_names.append(layer.name) self.stores = [store for store in self.catalog.get_stores()] self.store_names = [store.name for store in self.stores] styles = [] self.workspaces = [] self.workspace_names = [] for workspace in self.catalog.get_workspaces(): styles = styles + self.catalog.get_styles(workspace) self.workspace_names.append(workspace._name) self.workspaces.append(workspace) self.styles = styles + [ style for style in self.catalog.get_styles() ] self.style_names = [style.name for style in self.styles] def unpack(self, workspace_name, store_type="datastore"): layers_and_styles = {} features = [] workspace = self.get_workspace(workspace_name) if store_type == "datastore": store_url = workspace.datastore_url elif store_type == "coveragestore": store_url = workspace.coveragestore_url else: print("No correct store given") for datastore in tqdm(get(store_url, "name")): url = "{}workspaces/{}/datastores/{}".format( self.path, workspace.name, datastore) features = features + get(url, between_quotes=True) for feature in features: layer_name = os.path.basename(feature).split(".")[0] self.get_layer(self.get_slug(workspace.name, layer_name)) layers_and_styles[layer_name] = self.layer.default_style setattr(self, workspace_name + "_data", layers_and_styles) return layers_and_styles def get_layer(self, layer, easy=False): self.layer = self.catalog.get_layer(layer) if not easy: self.resource = self.layer.resource self.layer_name = self.layer.resource.name self.sld_name = self.layer.default_style.name self.sld_body = self.layer.default_style.sld_body self.layer_latlon_bbox = self.layer.resource.latlon_bbox self.layer_title = self.layer.resource.title self.layer_abstract = self.layer.resource.abstract def get_store(self, layer): self.store = self.layer.resource._store def get_resource(self): self.resource = self.catalog.get_resource(self.layer.name, self.store) def get_workspace(self, workspace_name): self.workspace = self.catalog.get_workspace(workspace_name) self.workspace_name = self.workspace._name return self.workspace def write_abstract(self, data, load_resource=True): if load_resource: self.get_resource() self.resource.abstract = data self.catalog.save(self.resource) def write_title(self, title): self.resource.title = title self.catalog.save(self.resource) def get_connection_parameters(self): self.get_resource() return self.resource.store.connection_parameters def create_workspace(self, workspace_name): workspace_exists = workspace_name in self.workspace_names if not workspace_exists: self.workspace = self.catalog.create_workspace(workspace_name) else: print("workspace already exists, using existing workspace") self.workspace = self.catalog.get_workspace(workspace_name) self.workspace_name = workspace_name def create_postgis_datastore(self, store_name, workspace_name, pg_data): try: self.store = self.catalog.get_store(store_name, self.workspace_name) print("store within workspace exists, using existing store") except Exception as e: print(e) ds = self.catalog.create_datastore(store_name, workspace_name) ds.connection_parameters.update( host=pg_data["host"], port=pg_data["port"], database=pg_data["database"], user=pg_data["username"], passwd=pg_data["password"], dbtype="postgis", schema="public", ) self.save(ds) self.store = self.catalog.get_store(store_name, self.workspace_name) self.store_name = store_name def publish_layer(self, layer_name, workspace_name, overwrite=False, epsg="3857", reload=False): layer_exists = layer_name in self.layer_names # if layer_name in self.workspace_layers[workspace_name]: slug = self.get_slug(workspace_name, layer_name) if overwrite and layer_exists: print("Layer exists, deleting layer") try: self.layer = self.catalog.get_layer(slug) self.delete(self.layer) self.reload() layer_exists = False except Exception as e: print(e) print("Layer does not exist in workspace") layer_exists = False if not layer_exists: feature_type = self.catalog.publish_featuretype( layer_name, self.store, "EPSG:{}".format(str(epsg)), srs="EPSG:{}".format(str(epsg)), ) self.save(feature_type) self.feature_type = feature_type else: print("layer already exists, using existing layer") if reload: self.get_layer(slug) self.layer_name = layer_name def publish_layergroup(self, name, layers, styles=(), bounds=None, workspace=None): layer_group = self.catalog.create_layergroup(name, layers, styles, bounds, workspace) self.save(layer_group) def save(self, save_object): return self.catalog.save(save_object) def close(self): self.catalog = None def delete(self, delete_object): self.catalog.delete(delete_object) def reload(self): self.catalog.reload() def upload_shapefile(self, layer_name, shapefile_path): path = shapefile_path.split(".shp")[0] shapefile = shapefile_and_friends(path) ft = self.catalog.create_featurestore(layer_name, shapefile, self.workspace) self.save(ft) def upload_sld(self, sld_name, workspace_name, sld, overwrite=True): style_exists = sld_name in self.style_names if overwrite and style_exists: print("Overwriting style") style = self.catalog.get_style(sld_name, workspace_name) self.delete(style) self.reload() style_exists = False if not style_exists: try: self.catalog.create_style(sld_name, sld, False, workspace_name, "sld11") except Exception as e: print(e) style = self.catalog.get_style(sld_name, workspace_name) self.delete(style) self.reload() self.catalog.create_style(sld_name, sld, False, workspace_name, "sld10") self.style_name = sld_name else: if style_exists: print("Style already exists, using current style") self.style_name = sld_name def set_sld_for_layer(self, workspace_name=None, style_name=None, use_custom=False): if not use_custom: workspace_name = self.workspace_name style_name = self.style_name self.style_slug = self.get_slug(workspace_name, style_name) else: if workspace_name is None: self.style_slug = style_name else: self.style_slug = self.get_slug(workspace_name, style_name) self.style = self.catalog.get_style(self.style_slug) print("Setting {} for {}".format(self.style.name, self.layer.name)) self.layer.default_style = self.style self.save(self.layer) def get_slug(self, workspace, name): return "{}:{}".format(workspace, name) def get_slug_data(self, slug): workspace_name = slug.split(":")[0] layer_name = slug.split(":")[1] return workspace_name, layer_name def get_sld(self, layer_slug=None): if layer_slug is None: self.style = self.catalog.get_style(self.layer_slug) else: self.style = self.catalog.get_style(layer_slug) self.sld_body = self.style.sld_body return self.sld_body def get_layer_workspace(self, layer_name): return self.catalog.get_layer(layer_name).resource.workspace.name
if style is not None and style: return (layer, style) else: return (layer, demo.get_layer(layer).default_style.name) g = demo.get_layergroup("groupname") resolved = [resolve(l, s) for (l, s) in zip(g.layers, g.styles)] # upload all styles to live for (l, s) in resolved: wayne_style = prefix + s style_on_server = live.get_style(wayne_style) sld = demo.get_style(s).sld_body if style_on_server is None: live.create_style(wayne_style, sld) else: style_on_server.update_body(sld) backup_layernames = {} # check that all requisite layers exist! for (l, s) in resolved: assert live.get_layer(l) is not None or l in backup_layernames, l lyrs = [backup_layernames.get(x[0], x[0]) for x in resolved] stls = [(prefix + x[1]) for x in resolved] wayne_group = live.get_layergroup(groupname) if wayne_group is None: wayne_group = live.create_layergroup(groupname) wayne_group.layers = lyrs
class ModifyingTests(unittest.TestCase): def setUp(self): self.cat = Catalog("http://localhost:8080/geoserver/rest") def testFeatureTypeSave(self): # test saving round trip rs = self.cat.get_resource("bugsites") old_abstract = rs.abstract new_abstract = "Not the original abstract" enabled = rs.enabled # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(new_abstract, rs.abstract) self.assertEqual(enabled, rs.enabled) # Change keywords on server rs.keywords = ["bugsites", "gsconfig"] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(["bugsites", "gsconfig"], rs.keywords) self.assertEqual(enabled, rs.enabled) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("bugsites") self.assertEqual(old_abstract, rs.abstract) def testDataStoreCreate(self): ds = self.cat.create_datastore("vector_gsconfig") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) def testPublishFeatureType(self): # Use the other test and store creation to load vector data into a database # @todo maybe load directly to database? try: self.testDataStoreCreateAndThenAlsoImportData() except FailedRequestError: pass try: lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) ds = self.cat.get_store("gsconfig_import_test") # make sure it's gone self.assert_(self.cat.get_layer('import') is None) self.cat.publish_featuretype("import", ds, native_crs="EPSG:4326") # and now it's not self.assert_(self.cat.get_layer('import') is not None) finally: # tear stuff down to allow the other test to pass if we run first ds = self.cat.get_store("gsconfig_import_test") lyr = self.cat.get_layer('import') # Delete the existing layer and resource to allow republishing. self.cat.delete(lyr) self.cat.delete(lyr.resource) self.cat.delete(ds) def testDataStoreModify(self): ds = self.cat.get_store("sf") self.assertFalse("foo" in ds.connection_parameters) ds.connection_parameters = ds.connection_parameters ds.connection_parameters["foo"] = "bar" orig_ws = ds.workspace.name self.cat.save(ds) ds = self.cat.get_store("sf") self.assertTrue("foo" in ds.connection_parameters) self.assertEqual("bar", ds.connection_parameters["foo"]) self.assertEqual(orig_ws, ds.workspace.name) @drop_table('import') def testDataStoreCreateAndThenAlsoImportData(self): ds = self.cat.create_datastore("gsconfig_import_test") ds.connection_parameters.update(**DBPARAMS) self.cat.save(ds) ds = self.cat.get_store("gsconfig_import_test") self.cat.add_data_to_store(ds, "import", { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' }) def testCoverageStoreCreate(self): ds = self.cat.create_coveragestore2("coverage_gsconfig") ds.data_url = "file:data/mytiff.tiff" self.cat.save(ds) def testCoverageStoreModify(self): cs = self.cat.get_store("sfdem") self.assertEqual("GeoTIFF", cs.type) cs.type = "WorldImage" self.cat.save(cs) cs = self.cat.get_store("sfdem") self.assertEqual("WorldImage", cs.type) # not sure about order of test runs here, but it might cause problems # for other tests if this layer is misconfigured cs.type = "GeoTIFF" self.cat.save(cs) def testCoverageSave(self): # test saving round trip rs = self.cat.get_resource("Arc_Sample") old_abstract = rs.abstract new_abstract = "Not the original abstract" # # Change abstract on server rs.abstract = new_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(new_abstract, rs.abstract) # Restore abstract rs.abstract = old_abstract self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual(old_abstract, rs.abstract) # Change metadata links on server rs.metadata_links = [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")] enabled = rs.enabled self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEqual( [("text/xml", "TC211", "http://example.com/gsconfig.test.metadata")], rs.metadata_links) self.assertEqual(enabled, rs.enabled) srs_before = set(['EPSG:4326']) srs_after = set(['EPSG:4326', 'EPSG:3785']) formats = set(['ARCGRID', 'ARCGRID-GZIP', 'GEOTIFF', 'PNG', 'GIF', 'TIFF']) formats_after = set(["PNG", "GIF", "TIFF"]) # set and save request_srs_list self.assertEquals(set(rs.request_srs_list), srs_before, str(rs.request_srs_list)) rs.request_srs_list = rs.request_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.request_srs_list), srs_after, str(rs.request_srs_list)) # set and save response_srs_list self.assertEquals(set(rs.response_srs_list), srs_before, str(rs.response_srs_list)) rs.response_srs_list = rs.response_srs_list + ['EPSG:3785'] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.response_srs_list), srs_after, str(rs.response_srs_list)) # set and save supported_formats self.assertEquals(set(rs.supported_formats), formats, str(rs.supported_formats)) rs.supported_formats = ["PNG", "GIF", "TIFF"] self.cat.save(rs) rs = self.cat.get_resource("Arc_Sample") self.assertEquals(set(rs.supported_formats), formats_after, str(rs.supported_formats)) def testWmsStoreCreate(self): ws = self.cat.create_wmsstore("wmsstore_gsconfig") ws.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" ws.type = "WMS" self.cat.save(ws) def testWmsLayer(self): self.cat.create_workspace("wmstest", "http://example.com/wmstest") wmstest = self.cat.get_workspace("wmstest") wmsstore = self.cat.create_wmsstore("wmsstore", wmstest) wmsstore.capabilitiesURL = "http://suite.opengeo.org/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities" wmsstore.type = "WMS" self.cat.save(wmsstore) wmsstore = self.cat.get_store("wmsstore") self.assertEqual(1, len(self.cat.get_stores(wmstest))) available_layers = wmsstore.get_resources(available=True) for layer in available_layers: new_layer = self.cat.create_wmslayer(wmstest, wmsstore, layer) added_layers = wmsstore.get_resources() self.assertEqual(len(available_layers), len(added_layers)) def testFeatureTypeCreate(self): shapefile_plus_sidecars = shapefile_and_friends("test/data/states") expected = { 'shp': 'test/data/states.shp', 'shx': 'test/data/states.shx', 'dbf': 'test/data/states.dbf', 'prj': 'test/data/states.prj' } self.assertEqual(len(expected), len(shapefile_plus_sidecars)) for k, v in expected.iteritems(): self.assertEqual(v, shapefile_plus_sidecars[k]) sf = self.cat.get_workspace("sf") self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) self.assert_(self.cat.get_resource("states_test", workspace=sf) is not None) self.assertRaises( ConflictingDataError, lambda: self.cat.create_featurestore("states_test", shapefile_plus_sidecars, sf) ) self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster_test", shapefile_plus_sidecars, sf) ) bogus_shp = { 'shp': 'test/data/Pk50095.tif', 'shx': 'test/data/Pk50095.tif', 'dbf': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } self.assertRaises( UploadError, lambda: self.cat.create_featurestore("bogus_shp", bogus_shp, sf) ) lyr = self.cat.get_layer("states_test") self.cat.delete(lyr) self.assert_(self.cat.get_layer("states_test") is None) def testCoverageCreate(self): tiffdata = { 'tiff': 'test/data/Pk50095.tif', 'tfw': 'test/data/Pk50095.tfw', 'prj': 'test/data/Pk50095.prj' } sf = self.cat.get_workspace("sf") # TODO: Uploading WorldImage file no longer works??? # ft = self.cat.create_coveragestore("Pk50095", tiffdata, sf) # self.assert_(self.cat.get_resource("Pk50095", workspace=sf) is not None) # self.assertRaises( # ConflictingDataError, # lambda: self.cat.create_coveragestore("Pk50095", tiffdata, sf) # ) self.assertRaises( UploadError, lambda: self.cat.create_featurestore("Pk50095_vector", tiffdata, sf) ) bogus_tiff = { 'tiff': 'test/data/states.shp', 'tfw': 'test/data/states.shx', 'prj': 'test/data/states.prj' } self.assertRaises( UploadError, lambda: self.cat.create_coveragestore("states_raster", bogus_tiff) ) def testLayerSave(self): # test saving round trip lyr = self.cat.get_layer("states") old_attribution = lyr.attribution new_attribution = "Not the original attribution" # change attribution on server lyr.attribution = new_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(new_attribution, lyr.attribution) # Restore attribution lyr.attribution = old_attribution self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(old_attribution, lyr.attribution) self.assertEqual(lyr.default_style.name, "population") old_default_style = lyr.default_style lyr.default_style = (s for s in lyr.styles if s.name == "pophatch").next() lyr.styles = [old_default_style] self.cat.save(lyr) lyr = self.cat.get_layer("states") self.assertEqual(lyr.default_style.name, "pophatch") self.assertEqual([s.name for s in lyr.styles], ["population"]) def testStyles(self): # upload new style, verify existence self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Fred", fred.sld_title) # replace style, verify changes self.cat.create_style("fred", open("test/ted.sld").read(), overwrite=True) fred = self.cat.get_style("fred") self.assert_(fred is not None) self.assertEqual("Ted", fred.sld_title) # delete style, verify non-existence self.cat.delete(fred, purge=True) self.assert_(self.cat.get_style("fred") is None) # attempt creating new style self.cat.create_style("fred", open("test/fred.sld").read()) fred = self.cat.get_style("fred") self.assertEqual("Fred", fred.sld_title) # verify it can be found via URL and check the name f = self.cat.get_style_by_url(fred.href) self.assert_(f is not None) self.assertEqual(f.name, fred.name) def testWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="blarny") self.assert_(jed is None) jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) jed = self.cat.get_style("topp:jed") self.assert_(jed is not None) self.assertEqual("Fred", jed.sld_title) # replace style, verify changes self.cat.create_style("jed", open("test/ted.sld").read(), overwrite=True, workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assert_(jed is not None) self.assertEqual("Ted", jed.sld_title) # delete style, verify non-existence self.cat.delete(jed, purge=True) self.assert_(self.cat.get_style("jed", workspace="topp") is None) # attempt creating new style self.cat.create_style("jed", open("test/fred.sld").read(), workspace="topp") jed = self.cat.get_style("jed", workspace="topp") self.assertEqual("Fred", jed.sld_title) # verify it can be found via URL and check the full name f = self.cat.get_style_by_url(jed.href) self.assert_(f is not None) self.assertEqual(f.fqn, jed.fqn) def testLayerWorkspaceStyles(self): # upload new style, verify existence self.cat.create_style("ned", open("test/fred.sld").read(), overwrite=True, workspace="topp") self.cat.create_style("zed", open("test/ted.sld").read(), overwrite=True, workspace="topp") ned = self.cat.get_style("ned", workspace="topp") zed = self.cat.get_style("zed", workspace="topp") self.assert_(ned is not None) self.assert_(zed is not None) lyr = self.cat.get_layer("states") lyr.default_style = ned lyr.styles = [zed] self.cat.save(lyr) self.assertEqual("topp:ned", lyr.default_style) self.assertEqual([zed], lyr.styles) lyr.refresh() self.assertEqual("topp:ned", lyr.default_style.fqn) self.assertEqual([zed.fqn], [s.fqn for s in lyr.styles]) def testWorkspaceCreate(self): ws = self.cat.get_workspace("acme") self.assertEqual(None, ws) self.cat.create_workspace("acme", "http://example.com/acme") ws = self.cat.get_workspace("acme") self.assertEqual("acme", ws.name) def testWorkspaceDelete(self): self.cat.create_workspace("foo", "http://example.com/foo") ws = self.cat.get_workspace("foo") self.cat.delete(ws) ws = self.cat.get_workspace("foo") self.assert_(ws is None) def testWorkspaceDefault(self): # save orig orig = self.cat.get_default_workspace() neu = self.cat.create_workspace("neu", "http://example.com/neu") try: # make sure setting it works self.cat.set_default_workspace("neu") ws = self.cat.get_default_workspace() self.assertEqual('neu', ws.name) finally: # cleanup and reset to the way things were self.cat.delete(neu) self.cat.set_default_workspace(orig.name) ws = self.cat.get_default_workspace() self.assertEqual(orig.name, ws.name) def testFeatureTypeDelete(self): pass def testCoverageDelete(self): pass def testDataStoreDelete(self): states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) states.enabled = False self.assert_(states.enabled == False) self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == False) states.enabled = True self.cat.save(states) states = self.cat.get_store('states_shapefile') self.assert_(states.enabled == True) def testLayerGroupSave(self): tas = self.cat.get_layergroup("tasmania") self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads', 'tasmania_cities'], tas.layers) self.assertEqual(tas.styles, [None, None, None, None], tas.styles) tas.layers = tas.layers[:-1] tas.styles = tas.styles[:-1] self.cat.save(tas) # this verifies the local state self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads'], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles) # force a refresh to check the remote state tas.refresh() self.assertEqual(tas.layers, ['tasmania_state_boundaries', 'tasmania_water_bodies', 'tasmania_roads'], tas.layers) self.assertEqual(tas.styles, [None, None, None], tas.styles)