def migrate_maps_on_wms_workspace(): logger.info(f' Starting - migrate maps json urls') query = f''' select w.name, p.name from {db_schema}.publications p inner join {db_schema}.workspaces w on w.id = p.id_workspace where p.type = %s ''' params = (MAP_TYPE, ) publications = db_util.run_query(query, params) gs_url = layer_gs_util.get_gs_proxy_base_url() gs_url = gs_url if gs_url.endswith('/') else f"{gs_url}/" gs_wms_url_pattern = r'^' + re.escape( gs_url ) + r'(' + util.USERNAME_ONLY_PATTERN + r')' + r'(/(?:ows|wms|wfs).*)$' all_workspaces = workspaces.get_workspace_names() for (workspace, map) in publications: file_path = input_file.get_map_file(workspace, map) is_changed = False with open(file_path, 'r') as map_file: map_json_raw = json.load(map_file) map_json = input_file.unquote_urls(map_json_raw) for map_layer in map_json['layers']: layer_url = map_layer.get('url', None) if not layer_url: continue match = re.match(gs_wms_url_pattern, layer_url) if not match: continue layer_workspace = match.group(1) if not layer_workspace: continue if layer_workspace not in all_workspaces: logger.warning( f' Do not know workspace {layer_workspace} in map {workspace}.{map}. Not migrating this url.' ) continue layer_wms_workspace = wms.get_geoserver_workspace( layer_workspace) map_layer[ 'url'] = f'{gs_url}{layer_wms_workspace}{match.group(2)}' is_changed = True if is_changed: logger.info(f' Store new json for {workspace}.{map}') with open(file_path, 'w') as map_file: json.dump(map_json, map_file, indent=4) logger.info(f' DONE - migrate maps json urls')
def find_maps_containing_layer(layer_workspace, layer_name): from layman.layer import LAYER_TYPE from layman.layer.geoserver import util as layer_gs_util from layman.map.filesystem import input_file as map_input_file from layman.map.util import find_maps_by_grep from layman.util import get_publication_info gs_url = layer_gs_util.get_gs_proxy_base_url() gs_url = gs_url if gs_url.endswith('/') else f"{gs_url}/" gs_domain = urlparse(gs_url).hostname layer_info = get_publication_info(layer_workspace, LAYER_TYPE, layer_name, context={'keys': ['wms']}) layer_wms_workspace = layer_info.get('_wms', {}).get('workspace') # first rough filters url_pattern = fr'^\s*.?url.?:\s*.*{gs_domain}.*/geoserver(/({layer_workspace}|{layer_wms_workspace}))?/(ows|wms|wfs).*,\s*$' url_maps = find_maps_by_grep(url_pattern) layer_pattern = fr'^\s*.?(layers|LAYERS).?:\s*.*{layer_name}.*\s*$' layer_maps = find_maps_by_grep(layer_pattern) maps = url_maps.intersection(layer_maps) # verify layer for map gs_ows_url_pattern = fr'^{re.escape(gs_url)}(({layer_workspace}|{layer_wms_workspace})/)?(?:ows|wms|wfs).*$' result_maps = set() for workspace, map in maps: map_json_raw = map_input_file.get_map_json(workspace, map) map_json = map_input_file.unquote_urls(map_json_raw) for map_layer in map_json['layers']: layer_url = map_layer.get('url') if not layer_url: continue match = re.match(gs_ows_url_pattern, layer_url) if not match: continue map_layers = CaseInsensitiveDict(**map_layer.get('params', dict())).get('layers') layers = unquote(map_layers).split(',') if layer_name in layers or f'{layer_workspace}:{layer_name}' in layers or f'{layer_wms_workspace}:{layer_name}' in layers: result_maps.add((workspace, map)) return result_maps
def get_map_with_internal_layers_json(layers, *, native_extent=None, native_crs=None): if not native_extent: with app.app_context(): extents = [ layman_util.get_publication_info( workspace, process_client.LAYER_TYPE, layer, context={'keys': ['bounding_box']})['bounding_box'] for workspace, layer in layers ] native_extent = ( min([minx for minx, _, _, _ in extents]), min([miny for _, miny, _, _ in extents]), max([maxx for _, _, maxx, _ in extents]), max([maxy for _, _, _, maxy in extents]), ) native_crs = crs_def.EPSG_3857 assert native_crs with app.app_context(): extent_4326 = bbox.transform( native_extent, crs_from=native_crs, crs_to=crs_def.EPSG_4326, ) map_json = { "describedBy": "https://raw.githubusercontent.com/hslayers/map-compositions/2.0.0/schema.json", "schema_version": "2.0.0", "abstract": "Map generated for internal layers", "title": "Map of internal layers", "extent": extent_4326, "nativeExtent": native_extent, "projection": native_crs, "layers": [{ "metadata": {}, "visibility": True, "opacity": 1, "title": "Defini\u010dn\u00ed body administrativn\u00edch celk\u016f", "className": "HSLayers.Layer.WMS", "singleTile": True, "wmsMaxScale": 0, "legends": [ "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26version%3D1.3.0%26service%3DWMS%26request%3DGetLegendGraphic%26sld_version%3D1.1.0%26layer%3Ddefinicni_body_administrativnich_celku%26format%3Dimage%2Fpng%26STYLE%3Ddefault" ], "maxResolution": None, "minResolution": 0, "url": "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26", "params": { "LAYERS": "definicni_body_administrativnich_celku", "INFO_FORMAT": "application/vnd.ogc.gml", "FORMAT": "image/png", "FROMCRS": "EPSG:3857", "VERSION": "1.3.0" }, "dimensions": {} }] } gs_url = layer_gs_util.get_gs_proxy_base_url() gs_url = gs_url if gs_url.endswith('/') else f"{gs_url}/" for workspace, layer in layers: geoserver_workspace = geoserver_wms.get_geoserver_workspace(workspace) map_json['layers'].append({ "metadata": {}, "visibility": True, "opacity": 1, "title": layer, "className": "HSLayers.Layer.WMS", "singleTile": True, "url": f"{gs_url}{geoserver_workspace}/ows", "params": { "LAYERS": layer, "FORMAT": "image/png" } }) return map_json
def map_json_to_operates_on(map_json, operates_on_muuids_filter=None, editor=None): # Either caller know muuids or wants filter by editor, never both at the same time assert not operates_on_muuids_filter or not editor unquote_urls(map_json) gs_url = get_gs_proxy_base_url() gs_url = gs_url if gs_url.endswith('/') else f"{gs_url}/" gs_wms_url_pattern = r'^' + re.escape(gs_url) + r'(' + USERNAME_ONLY_PATTERN + r')' + \ settings.LAYMAN_GS_WMS_WORKSPACE_POSTFIX + r'/(?:ows|wms|wfs).*$' layman_layer_names = [] for map_layer in map_json['layers']: layer_url = map_layer.get('url', None) if not layer_url: continue # print(f"layer_url={layer_url}") match = re.match(gs_wms_url_pattern, layer_url) if not match: continue layer_username = match.group(1) if not layer_username: continue # print(f"layer_username={layer_username}") layer_names = [ n for n in map_layer.get('params', {}).get('LAYERS', '').split(',') if len(n) > 0 ] if not layer_names: continue for layername in layer_names: layman_layer_names.append((layer_username, layername)) operates_on = [] csw_url = settings.CSW_PROXY_URL for (layer_username, layername) in layman_layer_names: layer_md_info = get_publication_info(layer_username, LAYER_TYPE, layername, context={ 'keys': [ 'metadata', ], }) layer_muuid = layer_md_info.get('metadata', {}).get('identifier') if operates_on_muuids_filter is not None: if layer_muuid not in operates_on_muuids_filter: continue layer_wms_info = get_publication_info(layer_username, LAYER_TYPE, layername, context={ 'keys': [ 'wms', ], }) else: layer_wms_info = get_publication_info(layer_username, LAYER_TYPE, layername, context={ 'keys': [ 'wfs', ], 'actor_name': editor, }) if not (layer_muuid and layer_wms_info): continue layer_title = layer_wms_info['title'] layer_csw_url = f"{csw_url}?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetRecordById&OUTPUTSCHEMA=http://www.isotc211.org/2005/gmd&ID={layer_muuid}#_{layer_muuid}" operates_on.append({ 'xlink:title': layer_title, 'xlink:href': layer_csw_url, }) return operates_on
def get_map_with_internal_layers_json(layers, *, extent_3857=None): if not extent_3857: with app.app_context(): extents = [layman_util.get_publication_info(workspace, process_client.LAYER_TYPE, layer, context={'keys': ['wms', 'bounding_box']})['bounding_box'] for workspace, layer in layers] extent_3857 = (min([minx for minx, _, _, _ in extents]), min([miny for _, miny, _, _ in extents]), max([maxx for _, _, maxx, _ in extents]), min([maxy for _, _, _, maxy in extents]), ) with app.app_context(): extent_4326 = bbox.transform(extent_3857, 3857, 4326) map_json = f''' {{ "abstract": "Map generated for internal layers", "title": "Map of internal layers", "extent": [ "{extent_4326[0]}", "{extent_4326[1]}", "{extent_4326[2]}", "{extent_4326[3]}" ], "projection": "epsg:3857", "layers": [ {{ "metadata": {{}}, "visibility": true, "opacity": 1, "title": "Defini\u010dn\u00ed body administrativn\u00edch celk\u016f", "className": "HSLayers.Layer.WMS", "singleTile": true, "wmsMaxScale": 0, "legends": [ "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26version%3D1.3.0%26service%3DWMS%26request%3DGetLegendGraphic%26sld_version%3D1.1.0%26layer%3Ddefinicni_body_administrativnich_celku%26format%3Dimage%2Fpng%26STYLE%3Ddefault" ], "maxResolution": null, "minResolution": 0, "url": "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26", "params": {{ "LAYERS": "definicni_body_administrativnich_celku", "INFO_FORMAT": "application/vnd.ogc.gml", "FORMAT": "image/png", "FROMCRS": "EPSG:3857", "VERSION": "1.3.0" }}, "dimensions": {{}} }} ''' gs_url = layer_gs_util.get_gs_proxy_base_url() gs_url = gs_url if gs_url.endswith('/') else f"{gs_url}/" for workspace, layer in layers: map_json = map_json + f''', {{ "metadata": {{}}, "visibility": true, "opacity": 1, "title": "{layer}", "className": "HSLayers.Layer.WMS", "singleTile": true, "url": "{gs_url}{workspace}/ows", "params": {{ "LAYERS": "{layer}", "FORMAT": "image/png" }} }}''' map_json = map_json + ''' ] }''' return map_json