Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop removing default values from SLD styles (e.g. WellKnownName=square) #928

Merged
merged 5 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- requests to [WMS](doc/endpoints.md#web-map-service) and [WFS](doc/endpoints.md#web-feature-service) endpoints
- [#868](https://github.com/LayerManager/layman/issues/868) Responses to [GET Workspace Layer Metadata Comparison](doc/rest.md#get-workspace-layer-metadata-comparison) and [GET Workspace Map Metadata Comparison](doc/rest.md#get-workspace-map-metadata-comparison) do not respect [HTTP header `X-Forwarded-Prefix`](doc/client-proxy.md#x-forwarded-prefix-http-header) of the request intentionally, in order to keep URLs in canonical form.
- [#868](https://github.com/LayerManager/layman/issues/868) Relations between map and [internal layers](doc/models.md#internal-map-layer) are updated in `map_layer` table when calling [POST Workspace Maps](doc/rest.md#post-workspace-maps), [PATCH Workspace Map](doc/rest.md#patch-workspace-map), [DELETE Workspace Map](doc/rest.md#delete-workspace-map), and [DELETE Workspace Maps](doc/rest.md#delete-workspace-maps).
- [#927](https://github.com/LayerManager/layman/issues/927) Send styles to GeoServer with [`raw`](https://docs.geoserver.org/2.21.x/en/user/rest/api/styles.html#raw) param set to `True`.
- [#880](https://github.com/LayerManager/layman/issues/880) Use Docker Compose v2 (`docker compose`) in Makefile without `compatibility` flag and remove `Makefile_docker-compose_v1` file. Docker containers are named according to Docker Compose v2 and may have different name after upgrade.
- [#765](https://github.com/LayerManager/layman/issues/765) Stop saving OAuth2 claims in filesystem, use prime DB schema only.
- [#893](https://github.com/LayerManager/layman/issues/893) It is possible to specify logging level by new environment variable [LAYMAN_LOGLEVEL](doc/env-settings.md#LAYMAN_LOGLEVEL). Default level is `INFO`.
Expand Down
17 changes: 5 additions & 12 deletions src/geoserver/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,24 +368,15 @@ def post_workspace_sld_style(geoserver_workspace, layername, sld_file, launder_f
)
response.raise_for_status()
sld_file = io.BytesIO(response.content)
response = requests.post(
get_workspace_style_url(geoserver_workspace),
data=f"<style><name>{layername}</name><filename>{layername}.sld</filename></style>",
headers=headers_xml,
auth=GS_AUTH,
timeout=GS_REST_TIMEOUT,
)
response.raise_for_status()

tree = ET.parse(sld_file)
root = tree.getroot()
if 'version' in root.attrib and root.attrib['version'] == '1.1.0':
sld_content_type = 'application/vnd.ogc.se+xml'
else:
sld_content_type = 'application/vnd.ogc.sld+xml'

propertname_els = tree.findall('.//{http://www.opengis.net/ogc}PropertyName')
if launder_function:
propertname_els = tree.findall('.//{http://www.opengis.net/ogc}PropertyName')
for element in propertname_els:
element.text = launder_function(element.text)

Expand All @@ -397,14 +388,16 @@ def post_workspace_sld_style(geoserver_workspace, layername, sld_file, launder_f
)
sld_file.seek(0)

response = requests.put(
get_workspace_style_url(geoserver_workspace, layername),
response = requests.post(
get_workspace_style_url(geoserver_workspace),
data=sld_file.read(),
headers={
'Accept': 'application/json',
'Content-type': sld_content_type,
},
auth=GS_AUTH,
params={'raw': True,
'name': layername, },
timeout=GS_REST_TIMEOUT,
)
if response.status_code == 400:
Expand Down
22 changes: 14 additions & 8 deletions src/layman/layer/filesystem/input_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,20 @@ def get_layer_file(workspace, layername):

def get_style_type_from_file_storage(file_storage):
if file_storage:
xml = file_storage.read()
file_storage.seek(0)
xml_tree = etree.fromstring(xml)
root_tag = xml_tree.tag
root_attribute = etree.QName(root_tag).localname
result = next((sd for sd in layer.STYLE_TYPES_DEF if sd.root_element == root_attribute), None)
if not result:
raise LaymanError(46)
try:
xml = file_storage.read()
file_storage.seek(0)
xml_tree = etree.fromstring(xml)
root_tag = xml_tree.tag
root_attribute = etree.QName(root_tag).localname
result = next((sd for sd in layer.STYLE_TYPES_DEF if sd.root_element == root_attribute), None)
if not result:
raise LaymanError(46, {
'message': f"Unknown root element.",
'expected': f"Root element is one of {[sd.root_element for sd in layer.STYLE_TYPES_DEF if sd.root_element]}",
})
except etree.XMLSyntaxError as exc:
raise LaymanError(46, "Unable to parse style file.",) from exc
else:
result = layer.NO_STYLE_DEF
return result
15 changes: 10 additions & 5 deletions src/layman/layer/filesystem/input_style_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import lxml
import pytest
from werkzeug.datastructures import FileStorage

Expand All @@ -23,15 +22,21 @@ def test_get_style_type_from_xml_file(file_path,
assert detected_type.code == expected_type


@pytest.mark.parametrize('file_path, expected_error, expected_code', [
('sample/style/no_style.xml', LaymanError, 46),
('test_tools/data/thumbnail/countries_wms_blue.png', lxml.etree.XMLSyntaxError, 4),
@pytest.mark.parametrize('file_path, expected_error, expected_code, expected_data', [
('sample/style/no_style.xml', LaymanError, 46, {
'message': 'Unknown root element.',
'expected': "Root element is one of ['StyledLayerDescriptor', 'qgis']",
}),
('sample/style/generic-invalid.xml', LaymanError, 46, 'Unable to parse style file.'),
('test_tools/data/thumbnail/countries_wms_blue.png', LaymanError, 46, 'Unable to parse style file.'),
])
def test_get_style_type_from_xml_file_errors(file_path,
expected_error,
expected_code):
expected_code,
expected_data):
with pytest.raises(expected_error) as exc_info:
with open(file_path, 'rb') as file:
file = FileStorage(file)
input_style.get_style_type_from_file_storage(file)
assert exc_info.value.code == expected_code
assert exc_info.value.data == expected_data
1 change: 1 addition & 0 deletions src/micka/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'srv': 'http://www.isotc211.org/2005/srv',
'soap': 'http://www.w3.org/2003/05/soap-envelope',
'hs': 'http://www.hsrs.cz/micka',
'sld': "http://www.opengis.net/sld"
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from lxml import etree as ET
import requests

from geoserver import util as gs_util
from micka import NAMESPACES
from test_tools import process_client
from tests import Publication
from tests.dynamic_data import base_test


class TestPublication(base_test.TestSingleRestPublication):
workspace = 'dynamic_test_workspace_sld_wellknownname'
publication_type = process_client.LAYER_TYPE
layername = 'layer_sld_wellknownname'

def test_sld_wellknownname(self, ):
self.post_publication(Publication(self.workspace, self.publication_type, self.layername))
response = requests.get(
gs_util.get_workspace_style_url(self.workspace + '_wms', self.layername),
auth=gs_util.GS_AUTH,
headers=gs_util.headers_sld['1.0.0'],
timeout=gs_util.GS_REST_TIMEOUT,
)
parser = ET.XMLParser(remove_blank_text=True)
resp_tree = ET.fromstring(response.content, parser=parser)
response_wkn = resp_tree.xpath('//sld:WellKnownName', namespaces=NAMESPACES)
assert len(response_wkn) == 1, f'{ET.tostring(resp_tree, encoding="unicode", pretty_print=True)}'
response_wkn = response_wkn[0]
assert response_wkn.text == 'square'
Loading