Skip to content

Commit

Permalink
Ensure Output SRS list for all QGIS layers
Browse files Browse the repository at this point in the history
  • Loading branch information
index-git committed Feb 18, 2021
1 parent 9497a54 commit b4e93ab
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- New environment variables [LAYMAN_QGIS_HOST](doc/env-settings.md#LAYMAN_QGIS_HOST), [LAYMAN_QGIS_PORT](doc/env-settings.md#LAYMAN_QGIS_PORT), and [LAYMAN_QGIS_PATH](doc/env-settings.md#LAYMAN_QGIS_PATH).
- [#154](https://github.com/jirik/layman/issues/154) For endpoints [POST Layers](doc/rest.md#post-layers) and [PATCH Layer](doc/rest.md#patch-layer), parameter *sld* is replaced by the new parameter *style* and marked as deprecated. In response to endpoints [GET Layer](doc/rest.md#get-layer) and [PATCH Layer](doc/rest.md#patch-layer), *sld* is replaced by the new *style* item and marked as deprecated.
- [#154](https://github.com/jirik/layman/issues/154) Also QGIS style file is accepted, previously only SLD file was.
- [#154](https://github.com/jirik/layman/issues/154) During startup, [LAYMAN_OUTPUT_SRS_LIST](doc/env-settings.md#LAYMAN_OUTPUT_SRS_LIST) is ensure for all QGIS layers.

## v1.9.1
2021-01-18
Expand Down
6 changes: 5 additions & 1 deletion src/layman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@

with app.app_context():
from . import upgrade

upgrade.upgrade()

app.logger.info(f'Loading Redis database')
Expand All @@ -93,6 +92,11 @@

import_authn_to_redis()

app.logger.info(f'Update SRS output list for QGIS projects')
with app.app_context():
from .layer.qgis import output_srs
output_srs.ensure_output_srs_for_all()

pipe.multi()
pipe.set(LAYMAN_DEPS_ADJUSTED_KEY, 'done')
pipe.execute()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from layman import settings
from layman import settings, app
from layman.layer.qgis import util as qgis_util, wms as qgis_wms
from test import process, process_client, geoserver_client


Expand All @@ -19,46 +20,75 @@ def register_layer_to_delete(workspace, layername):
LAYERS_TO_DELETE_AFTER_TEST.append((workspace, layername))
yield register_layer_to_delete
for workspace, layername in LAYERS_TO_DELETE_AFTER_TEST:
pass
process_client.delete_layer(workspace, layername)


@pytest.fixture(scope="module")
def ensure_layer(delete_layer_after_test):
def ensure_layer_internal(workspace, layername, file_paths=None):
def ensure_layer_internal(workspace, layername, file_paths=None, style_file=None):
if (workspace, layername) not in LAYERS_TO_DELETE_AFTER_TEST:
process_client.publish_layer(workspace, layername, file_paths=file_paths)
process_client.publish_layer(workspace, layername, file_paths=file_paths, style_file=style_file)
delete_layer_after_test(workspace, layername)
yield ensure_layer_internal


def test_custom_srs_list(ensure_layer):
workspace = 'test_custom_srs_list_workspace'
layername1 = 'test_custom_srs_list_layer1'
layername2 = 'test_custom_srs_list_layer2'
layer_sld1 = 'test_custom_srs_list_sld_layer1'
layer_sld2 = 'test_custom_srs_list_sld_layer2'
layer_qgis1 = 'test_custom_srs_list_qgis_layer1'
layer_qgis2 = 'test_custom_srs_list_qgis_layer2'
source_style_file_path = 'sample/style/funny_qml.xml'
assert settings.LAYMAN_OUTPUT_SRS_LIST != OUTPUT_SRS_LIST

process.ensure_layman_function(process.LAYMAN_DEFAULT_SETTINGS)
ensure_layer(workspace, layername1)
assert_wms_output_srs_list(workspace, layername1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layername1, settings.LAYMAN_OUTPUT_SRS_LIST)
ensure_layer(workspace, layer_sld1)
ensure_layer(workspace, layer_qgis1, style_file=source_style_file_path)

with app.app_context():
assert_gs_wms_output_srs_list(workspace, layer_sld1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layer_sld1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert not qgis_wms.get_layer_info(workspace, layer_sld1)

assert_gs_wms_output_srs_list(workspace, layer_qgis1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layer_qgis1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert_qgis_output_srs_list(workspace, layer_qgis1, settings.LAYMAN_OUTPUT_SRS_LIST)
assert_qgis_wms_output_srs_list(workspace, layer_qgis1, settings.LAYMAN_OUTPUT_SRS_LIST)

process.ensure_layman_function({
'LAYMAN_OUTPUT_SRS_LIST': ','.join([str(code) for code in OUTPUT_SRS_LIST])
})
ensure_layer(workspace, layername2)
for layername in [layername1, layername2]:
assert_wms_output_srs_list(workspace, layername, OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layername, OUTPUT_SRS_LIST)


def assert_wms_output_srs_list(workspace, layername, expected_output_srs_list):
ensure_layer(workspace, layer_sld2)
ensure_layer(workspace, layer_qgis2, style_file=source_style_file_path)
with app.app_context():
for layer in [layer_sld1, layer_sld2, ]:
assert_gs_wms_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)
assert not qgis_wms.get_layer_info(workspace, layer)
for layer in [layer_qgis1, layer_qgis2, ]:
assert_gs_wms_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)
assert_wfs_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)
assert_qgis_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)
assert_qgis_wms_output_srs_list(workspace, layer, OUTPUT_SRS_LIST)


def assert_gs_wms_output_srs_list(workspace, layername, expected_output_srs_list):
wms = geoserver_client.get_wms_capabilities(workspace)
assert layername in wms.contents
wms_layer = wms.contents[layername]
for expected_output_srs in expected_output_srs_list:
assert f"EPSG:{expected_output_srs}" in wms_layer.crsOptions


def assert_qgis_wms_output_srs_list(workspace, layer, expected_output_srs_list):
wms = qgis_wms.get_wms_capabilities(workspace, layer)
assert layer in wms.contents
wms_layer = wms.contents[layer]
for expected_output_srs in expected_output_srs_list:
assert f"EPSG:{expected_output_srs}" in wms_layer.crsOptions


def assert_wfs_output_srs_list(workspace, layername, expected_output_srs_list):
wfs = geoserver_client.get_wfs_capabilities(workspace)
full_layername = f"{workspace}:{layername}"
Expand All @@ -69,6 +99,11 @@ def assert_wfs_output_srs_list(workspace, layername, expected_output_srs_list):
assert f"urn:ogc:def:crs:EPSG::{expected_output_srs}" in crs_names


def assert_qgis_output_srs_list(workspace, layer, expected_srs_list):
with app.app_context():
assert qgis_util.get_layer_wms_crs_list_values(workspace, layer) == set(expected_srs_list)


# expected coordinates manually copied from QGIS 3.16.2 in given EPSG
# point_id 1: northernmost vertex of fountain at Moravske namesti, Brno
@pytest.mark.parametrize('point_id, epsg_code, exp_coordinates, precision', [
Expand All @@ -79,14 +114,18 @@ def assert_wfs_output_srs_list(workspace, layername, expected_output_srs_list):
(1, 32634, (179991.0748, 5458879.0878), 0.1),
(1, 5514, (-598208.8093, -1160307.4484), 0.1),
])
def test_spatial_precision(ensure_layer, point_id, epsg_code, exp_coordinates, precision):
@pytest.mark.parametrize('style_file, layer_suffix', [
(None, '_sld', ),
('sample/style/funny_qml.xml', '_qgis', ),
])
def test_spatial_precision(ensure_layer, point_id, epsg_code, exp_coordinates, precision, style_file, layer_suffix, ):
process.ensure_layman_function({
'LAYMAN_OUTPUT_SRS_LIST': ','.join([str(code) for code in OUTPUT_SRS_LIST])
})
workspace = 'test_coordinate_precision_workspace'
layername = 'test_coordinate_precision_layer'
layername = 'test_coordinate_precision_layer' + layer_suffix

ensure_layer(workspace, layername, file_paths=['sample/layman.layer/sample_point_cz.geojson'])
ensure_layer(workspace, layername, file_paths=['sample/layman.layer/sample_point_cz.geojson'], style_file=style_file)

feature_collection = geoserver_client.get_features(workspace, layername, epsg_code=epsg_code)
feature = next(f for f in feature_collection['features'] if f['properties']['point_id'] == point_id)
Expand Down
11 changes: 11 additions & 0 deletions src/layman/layer/qgis/output_srs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from . import util, wms
from layman import util as layman_util, settings


def ensure_output_srs_for_all():
layers = layman_util.get_publication_infos(style_type='qgis')
if layers:
(workspace, _, layer) = next(iter(layers.keys()))
if util.get_layer_wms_crs_list_values(workspace, layer) != settings.LAYMAN_OUTPUT_SRS_LIST:
for (workspace, _, layer) in layers.keys():
wms.save_qgs_file(workspace, layer)
13 changes: 13 additions & 0 deletions src/layman/layer/qgis/wms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from owslib.wms import WebMapService

from . import util, wms
from .. import db
Expand Down Expand Up @@ -72,3 +73,15 @@ def save_qgs_file(workspace, layer):
qgs_str = util.fill_project_template(workspace, layer, uuid, layer_qml, settings.LAYMAN_OUTPUT_SRS_LIST, layer_bbox)
with open(wms.get_layer_file_path(workspace, layer), "w") as qgs_file:
print(qgs_str, file=qgs_file)


def wms_direct(wms_url, xml=None, version=None, headers=None):
from layman.layer.geoserver.wms import VERSION
version = version or VERSION
wms = WebMapService(wms_url, xml=xml.encode('utf-8') if xml is not None else xml, version=version, headers=headers)
return wms


def get_wms_capabilities(workspace=None, layer=None, headers=None):
wms_url = get_layer_capabilities_url(workspace, layer)
return wms_direct(wms_url, headers=headers)

0 comments on commit b4e93ab

Please sign in to comment.