From 762f7c959b2b4c0af6126a16730aea8848399847 Mon Sep 17 00:00:00 2001 From: carderm <7568993+carderm@users.noreply.github.com> Date: Thu, 11 Nov 2021 02:48:52 +1100 Subject: [PATCH 1/2] Fix for WMS Geoserver API error. Request changed to include Files. (#17) * Removed WMS Store from href due to REST error This is a workaround for a Geoserver issue - including store name in the URL causes a failure in Geoserver (500 error) but works (200) without. For Geoserver Testing see: https://docs.geoserver.org/stable/en/api/#1.0.0/wmslayers.yaml 1. PUT for /workspaces/{workspace}/wmslayers/{wmslayer} - WORKS! 2. PUT for /workspaces/{workspace}/wmsstores/{wmsstore}/wmslayers - FAILS! Sample xml payload to enable/disable a wmslayer: true true * Fix for http_request to allow files to be uploaded. E.g. for importing shapefiles via Importer. * Fixes editing existing styles - requires recursive flag to get existing format * Fixes for creating/listing Geoserver styles with recursion. --- .gitignore | 1 + examples/layersusing.py | 2 +- src/geoserver/catalog.py | 44 +++++++++++++++++++++------------------ src/geoserver/resource.py | 4 ++-- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 72eda3a..9696627 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ include/ lib/ lib64 doc/_build/ +.idea/ diff --git a/examples/layersusing.py b/examples/layersusing.py index ff4adaa..d58e380 100644 --- a/examples/layersusing.py +++ b/examples/layersusing.py @@ -20,4 +20,4 @@ def has_the_style(l): return (l.default_style.name == style_to_check or any(s.name == style_to_check for s in l.styles)) -print [l.name for l in cat.get_layers() if has_the_style(l)] +print([l.name for l in cat.get_layers() if has_the_style(l)]) diff --git a/src/geoserver/catalog.py b/src/geoserver/catalog.py index 700023f..c3de207 100644 --- a/src/geoserver/catalog.py +++ b/src/geoserver/catalog.py @@ -141,7 +141,7 @@ def setup_connection(self, retries=3, backoff_factor=0.9): ) self.client.mount("{}://".format(parsed_url.scheme), HTTPAdapter(max_retries=retry)) - def http_request(self, url, data=None, method='get', headers={}): + def http_request(self, url, data=None, method='get', headers={}, files=None): req_method = getattr(self.client, method.lower()) if self.access_token: @@ -152,14 +152,13 @@ def http_request(self, url, data=None, method='get', headers={}): params = urlencode(params) url = "{proto}://{address}{path}?{params}".format(proto=parsed_url.scheme, address=parsed_url.netloc, path=parsed_url.path, params=params) - - resp = req_method(url, headers=headers, data=data) - else: + elif self.username and self.password: valid_uname_pw = base64.b64encode( ("%s:%s" % (self.username, self.password)).encode("utf-8")).decode("ascii") headers['Authorization'] = 'Basic {}'.format(valid_uname_pw) - resp = req_method(url, headers=headers, data=data) - return resp + + return req_method(url, headers=headers, data=data, files=files) + def get_version(self): '''obtain the version or just 2.2.x if < 2.3.x @@ -1070,11 +1069,18 @@ def get_styles(self, names=None, workspaces=None, recursive=False): Will always return an array. ''' all_styles = [] + + # Get Names first to speed up recursive queries + if names is None: + names = [] + elif isinstance(names, string_types): + names = [s.strip() for s in names.split(',') if s.strip()] + if not workspaces: # Add global styles url = "{}/styles.xml".format(self.service_url) styles = self.get_xml(url) - all_styles += self.__build_style_list(styles, recursive=recursive) + all_styles += self.__build_style_list(styles, recursive=recursive, names=names) workspaces = [] elif isinstance(workspaces, string_types): workspaces = [s.strip() for s in workspaces.split(',') if s.strip()] @@ -1098,32 +1104,30 @@ def get_styles(self, names=None, workspaces=None, recursive=False): continue else: raise FailedRequestError("Failed to get styles: {}".format(e)) - all_styles += self.__build_style_list(styles, workspace=ws, recursive=recursive) - - if names is None: - names = [] - elif isinstance(names, string_types): - names = [s.strip() for s in names.split(',') if s.strip()] + all_styles += self.__build_style_list(styles, workspace=ws, recursive=recursive, names=names) if all_styles and names: return ([style for style in all_styles if style.name in names]) return all_styles - def __build_style_list(self, styles_tree, workspace=None, recursive=False): + def __build_style_list(self, styles_tree, workspace=None, recursive=False, names=None): all_styles = [] for s in styles_tree.findall("style"): try: + style_name = s.find('name').text + if names and style_name not in names: + continue if recursive: - style_format = self.get_xml(s[1].attrib.get('href')).find('format').text - style_version = self.get_xml(s[1].attrib.get('href')).find('languageVersion').find( - 'version').text.replace('.', '')[:-1] + style_xml = self.get_xml(s[1].attrib.get('href')) + style_format = style_xml.find('format').text + style_version = style_xml.find('languageVersion').find('version').text.replace('.', '')[:-1] all_styles.append( - Style(self, s.find("name").text, _name(workspace), style_format + style_version) + Style(self, style_name, _name(workspace), style_format + style_version) ) else: all_styles.append( - Style(self, s.find('name').text, _name(workspace)) + Style(self, style_name, _name(workspace)) ) except Exception: all_styles.append( @@ -1142,7 +1146,7 @@ def get_style(self, name, workspace=None, recursive=False): return self._return_first_item(styles) def create_style(self, name, data, overwrite=False, workspace=None, style_format="sld10", raw=False): - styles = self.get_styles(names=name, workspaces=[workspace]) + styles = self.get_styles(names=name, workspaces=[workspace], recursive=True) if len(styles) > 0: style = styles[0] else: diff --git a/src/geoserver/resource.py b/src/geoserver/resource.py index 099c7e8..b4dd92e 100644 --- a/src/geoserver/resource.py +++ b/src/geoserver/resource.py @@ -275,11 +275,11 @@ def __init__(self, catalog, workspace, store, name): @property def href(self): + # Removed Store from this due to error in the Rest API when including store return urljoin( "{}/".format(self.catalog.service_url), - "workspaces/{}/wmsstores/{}/wmslayers/{}.xml".format( + "workspaces/{}/wmslayers/{}.xml".format( self.workspace.name, - self.store.name, self.name ) ) From 422a36beaf2a73f2b49b02f0d6e5d39722d58c81 Mon Sep 17 00:00:00 2001 From: Guillaume Troupel Date: Wed, 10 Nov 2021 16:49:03 +0100 Subject: [PATCH 2/2] fix python 3.9+ incompatibility (#19) * fix python 3.9+ incompatibility https://github.com/GeoNode/geoserver-restconfig/issues/18 * python 3.9+ Co-authored-by: Alessio Fabiani --- src/geoserver/layer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geoserver/layer.py b/src/geoserver/layer.py index 75dd79b..6dc9f49 100644 --- a/src/geoserver/layer.py +++ b/src/geoserver/layer.py @@ -134,7 +134,7 @@ def resource(self): if self.dom is None: self.fetch() name = self.dom.find("resource/name").text - atom_link = [n for n in self.dom.find("resource").getchildren() if 'href' in n.attrib] + atom_link = [n for n in self.dom.find("resource") if 'href' in n.attrib] ws_name = workspace_from_url(atom_link[0].get('href')) if self.gs_version >= "2.13": if ":" in name: @@ -158,7 +158,7 @@ def _resolve_style(self, element): else: style_name = element.find('name').text ws_name = None - atom_link = [n for n in element.getchildren() if 'href' in n.attrib] + atom_link = [n for n in element if 'href' in n.attrib] if atom_link and ws_name is None: ws_name = workspace_from_url(atom_link[0].get("href")) return self.catalog.get_styles(names=style_name, workspaces=ws_name)[0]