From 102edbe23330a22110720e0362bc5b85ce3415b1 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Fri, 15 Nov 2024 16:27:11 +0200 Subject: [PATCH 01/15] fixing error when reloading a default style or metadata --- .../gui/geonode_map_layer_config_widget.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index d6e9884..22d4abb 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -314,8 +314,7 @@ def _apply_metadata(self) -> None: dataset = self.get_dataset() updated_metadata = populate_metadata(self.layer.metadata(), dataset) self.layer.setMetadata(updated_metadata) - layer_properties_dialog = self._get_layer_properties_dialog() - layer_properties_dialog.syncToLayer() + self._get_layer_properties_dialog(self.layer) # FIXME: rather use the api_client to perform the metadata upload def upload_metadata(self) -> None: @@ -433,8 +432,7 @@ def _apply_sld(self) -> None: dataset.default_style.sld, sld_load_error_msg ) if sld_load_result: - layer_properties_dialog = self._get_layer_properties_dialog() - layer_properties_dialog.syncToLayer() + self._get_layer_properties_dialog(self.layer) else: self._show_message( message=f"Could not load GeoNode style: {sld_load_error_msg}", @@ -449,10 +447,10 @@ def _show_message( ) -> None: utils.show_message(self.message_bar, message, level, add_loading_widget) - def _get_layer_properties_dialog(self): - # FIXME: This is a very hacky way to get the layer properties dialog - # but I've not been able to find a more elegant way to retrieve it yet - return self.parent().parent().parent().parent() + def _get_layer_properties_dialog(self, layer): + # We use the function syncToLayer of QgsMapLayerConfigWidget + # https://qgis.org/pyqgis/3.38/gui/QgsMapLayerConfigWidget.html + return self.syncToLayer(layer) def _toggle_link_controls(self, enabled: bool) -> None: self.links_gb.setEnabled(enabled) From c876e821e8c8d4a510f652f8caf5775ee174ab99 Mon Sep 17 00:00:00 2001 From: "G.Allegri" Date: Fri, 15 Nov 2024 16:00:42 +0100 Subject: [PATCH 02/15] implement support for vector properties help button --- src/qgis_geonode/conf.py | 10 +++++++++- .../gui/geonode_map_layer_config_widget.py | 1 + src/qgis_geonode/main.py | 12 ++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/qgis_geonode/conf.py b/src/qgis_geonode/conf.py index 366148c..f3d28e6 100644 --- a/src/qgis_geonode/conf.py +++ b/src/qgis_geonode/conf.py @@ -4,6 +4,7 @@ import json import typing import uuid +import urllib.parse from configparser import ConfigParser from pathlib import Path @@ -104,8 +105,15 @@ def prepare(self, plugin_dir): self.plugin_metadata = _plugin_metadata["general"] + homepage = urllib.parse.urlparse(self.plugin_metadata.get("homepage")) + self.homepage_root = f"{homepage.scheme}://{homepage.hostname}" + self.help_page = homepage.path.strip("/") + def get(self, attr): - return self.plugin_metadata.get(attr) + try: + return getattr(self, attr) + except ValueError: + return self.plugin_metadata.get(attr) class SettingsManager(QtCore.QObject): diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index 22d4abb..bef68e3 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -73,6 +73,7 @@ def connection_settings(self) -> typing.Optional[conf.ConnectionSettings]: def __init__(self, layer, canvas, parent): super().__init__(layer, canvas, parent) self.setupUi(self) + self.setProperty("helpPage", conf.plugin_metadata.get("help_page")) self.open_detail_url_pb.setIcon( QtGui.QIcon(":/plugins/qgis_geonode/mIconGeonode.svg") ) diff --git a/src/qgis_geonode/main.py b/src/qgis_geonode/main.py index 84994a5..957d167 100644 --- a/src/qgis_geonode/main.py +++ b/src/qgis_geonode/main.py @@ -11,6 +11,7 @@ import os.path +from qgis.core import QgsSettings from qgis.gui import QgsGui from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication from qgis.PyQt.QtGui import QIcon @@ -36,6 +37,17 @@ def __init__(self, iface): self.plugin_dir, "i18n", "QgisGeoNode_{}.qm".format(locale) ) + settings = QgsSettings() + help_paths = settings.value("help/helpSearchPath") + homepage_root = plugin_metadata.get("homepage_root") + + if isinstance(help_paths, str): + help_paths = [homepage_root, help_paths] + elif isinstance(help_paths, list): + help_paths = [homepage_root] + help_paths + + settings.setValue("help/helpSearchPath", help_paths) + if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) From 94bc430be9273c268ed8160ae20ac7f89d4bf2ee Mon Sep 17 00:00:00 2001 From: "G.Allegri" Date: Fri, 15 Nov 2024 16:09:15 +0100 Subject: [PATCH 03/15] do not keep adding help paths to settings! --- src/qgis_geonode/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qgis_geonode/main.py b/src/qgis_geonode/main.py index 957d167..90f08b1 100644 --- a/src/qgis_geonode/main.py +++ b/src/qgis_geonode/main.py @@ -43,7 +43,7 @@ def __init__(self, iface): if isinstance(help_paths, str): help_paths = [homepage_root, help_paths] - elif isinstance(help_paths, list): + elif isinstance(help_paths, list) and not homepage_root in help_paths: help_paths = [homepage_root] + help_paths settings.setValue("help/helpSearchPath", help_paths) From c1e834c2607806aafdb66871b37c1b67f52ddf31 Mon Sep 17 00:00:00 2001 From: "G.Allegri" Date: Fri, 15 Nov 2024 17:01:11 +0100 Subject: [PATCH 04/15] fix to home root --- src/qgis_geonode/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qgis_geonode/conf.py b/src/qgis_geonode/conf.py index f3d28e6..2cbc496 100644 --- a/src/qgis_geonode/conf.py +++ b/src/qgis_geonode/conf.py @@ -106,7 +106,7 @@ def prepare(self, plugin_dir): self.plugin_metadata = _plugin_metadata["general"] homepage = urllib.parse.urlparse(self.plugin_metadata.get("homepage")) - self.homepage_root = f"{homepage.scheme}://{homepage.hostname}" + self.homepage_root = f"{homepage.scheme}://{homepage.hostname}/" self.help_page = homepage.path.strip("/") def get(self, attr): From d8216e4c533d62df02652cfe1dfff78e19500829 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 11:16:28 +0200 Subject: [PATCH 05/15] fixing syncronization of the reloaded metadata and sld from GeoNode --- .../gui/geonode_map_layer_config_widget.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index bef68e3..d21e235 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -315,7 +315,8 @@ def _apply_metadata(self) -> None: dataset = self.get_dataset() updated_metadata = populate_metadata(self.layer.metadata(), dataset) self.layer.setMetadata(updated_metadata) - self._get_layer_properties_dialog(self.layer) + # sync layer properties with the reloaded SLD and/or Metadata from GeoNode + self.sync_layer_properties() # FIXME: rather use the api_client to perform the metadata upload def upload_metadata(self) -> None: @@ -433,7 +434,7 @@ def _apply_sld(self) -> None: dataset.default_style.sld, sld_load_error_msg ) if sld_load_result: - self._get_layer_properties_dialog(self.layer) + self.sync_layer_properties() else: self._show_message( message=f"Could not load GeoNode style: {sld_load_error_msg}", @@ -448,10 +449,13 @@ def _show_message( ) -> None: utils.show_message(self.message_bar, message, level, add_loading_widget) - def _get_layer_properties_dialog(self, layer): - # We use the function syncToLayer of QgsMapLayerConfigWidget - # https://qgis.org/pyqgis/3.38/gui/QgsMapLayerConfigWidget.html - return self.syncToLayer(layer) + def sync_layer_properties(self): + # get layer properties dialog + # TODO we have to find a more elegant way to retrieve the properties dialog + properties_dialog = self.parent().parent().parent().parent().parent().parent() + + # Sync GeoNode's SLD or / and metadata with the layer properties dialog + properties_dialog.syncToLayer() def _toggle_link_controls(self, enabled: bool) -> None: self.links_gb.setEnabled(enabled) From fa657a71cf670419884adc655c8928cdb07bde20 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 15:20:00 +0200 Subject: [PATCH 06/15] find the QDialog object through iteration by type --- .../gui/geonode_map_layer_config_widget.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index d21e235..e8a1512 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -449,10 +449,26 @@ def _show_message( ) -> None: utils.show_message(self.message_bar, message, level, add_loading_widget) + def find_parent_by_type(self, obj, target_type): + # Find the desired object by type + # from a structure: self.parent().parent()... + current_obj = obj + while current_obj is not None: + if isinstance(current_obj, target_type): + return current_obj + if hasattr(current_obj, "parent"): + current_obj = current_obj.parent() + else: + break + return None + def sync_layer_properties(self): # get layer properties dialog - # TODO we have to find a more elegant way to retrieve the properties dialog - properties_dialog = self.parent().parent().parent().parent().parent().parent() + # We need to find QDialog object from a structure like: + # self.parent().parent()... + target_type = QtWidgets.QDialog + obj = self + properties_dialog = self.find_parent_by_type(obj, target_type) # Sync GeoNode's SLD or / and metadata with the layer properties dialog properties_dialog.syncToLayer() From 1dc94abc291e55451aa0e0e3fe853c13d7cd0e5e Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 16:21:00 +0200 Subject: [PATCH 07/15] make the sync_layer_paroperties method more compact --- src/qgis_geonode/gui/geonode_map_layer_config_widget.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index e8a1512..f41beaf 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -466,9 +466,7 @@ def sync_layer_properties(self): # get layer properties dialog # We need to find QDialog object from a structure like: # self.parent().parent()... - target_type = QtWidgets.QDialog - obj = self - properties_dialog = self.find_parent_by_type(obj, target_type) + properties_dialog = self.find_parent_by_type(self, QtWidgets.QDialog) # Sync GeoNode's SLD or / and metadata with the layer properties dialog properties_dialog.syncToLayer() From 5721f8b9fd676b610787c938b56addf8be3a9279 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 16:32:53 +0200 Subject: [PATCH 08/15] improving the sync_layer_properties function --- src/qgis_geonode/gui/geonode_map_layer_config_widget.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index f41beaf..66a84f9 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -468,8 +468,13 @@ def sync_layer_properties(self): # self.parent().parent()... properties_dialog = self.find_parent_by_type(self, QtWidgets.QDialog) - # Sync GeoNode's SLD or / and metadata with the layer properties dialog - properties_dialog.syncToLayer() + if properties_dialog != None: + # Sync GeoNode's SLD or / and metadata with the layer properties dialog + properties_dialog.syncToLayer() + else: + self._show_message( + "The corresponding layer properties from GeoNode cannot be loaded correctly..." + ) def _toggle_link_controls(self, enabled: bool) -> None: self.links_gb.setEnabled(enabled) From 4c47bae0c36e08f7573d2c169b2868ff5b929046 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 16:42:06 +0200 Subject: [PATCH 09/15] update sync_layer_properties function --- src/qgis_geonode/gui/geonode_map_layer_config_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index 66a84f9..9d70e50 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -468,7 +468,7 @@ def sync_layer_properties(self): # self.parent().parent()... properties_dialog = self.find_parent_by_type(self, QtWidgets.QDialog) - if properties_dialog != None: + if properties_dialog is not None: # Sync GeoNode's SLD or / and metadata with the layer properties dialog properties_dialog.syncToLayer() else: From 37082a878776c35f436cde5ae85c0b3d045c2d27 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Mon, 18 Nov 2024 16:48:19 +0200 Subject: [PATCH 10/15] adding the CRITICAL level to the displayed message in case of a failure --- src/qgis_geonode/gui/geonode_map_layer_config_widget.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index 9d70e50..d9d0a4b 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -473,7 +473,8 @@ def sync_layer_properties(self): properties_dialog.syncToLayer() else: self._show_message( - "The corresponding layer properties from GeoNode cannot be loaded correctly..." + "The corresponding layer properties from GeoNode cannot be loaded correctly...", + level=qgis.core.Qgis.Critical, ) def _toggle_link_controls(self, enabled: bool) -> None: From f6ff5590fe5929a0610dd5df904be59083de3765 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Wed, 20 Nov 2024 17:38:30 +0200 Subject: [PATCH 11/15] adding the SLD request in a new task --- src/qgis_geonode/apiclient/base.py | 32 ++++++++++++-- src/qgis_geonode/apiclient/geonode_api_v2.py | 45 +++++++++++++------- src/qgis_geonode/gui/search_result_widget.py | 5 ++- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/qgis_geonode/apiclient/base.py b/src/qgis_geonode/apiclient/base.py index 229926b..a65d4d9 100644 --- a/src/qgis_geonode/apiclient/base.py +++ b/src/qgis_geonode/apiclient/base.py @@ -28,6 +28,7 @@ class BaseGeonodeClient(QtCore.QObject): dataset_list_received = QtCore.pyqtSignal(list, models.GeonodePaginationInfo) dataset_detail_received = QtCore.pyqtSignal(object) + dataset_sld_received = QtCore.pyqtSignal(QtXml.QDomElement) dataset_detail_error_received = QtCore.pyqtSignal([str], [str, int, str]) style_detail_received = QtCore.pyqtSignal(QtXml.QDomElement) style_detail_error_received = QtCore.pyqtSignal([str], [str, int, str]) @@ -122,11 +123,26 @@ def handle_dataset_style( def get_dataset_detail( self, dataset: typing.Union[models.BriefDataset, models.Dataset], - get_style_too: bool = False, ) -> None: requests_to_perform = [ network.RequestToPerform(url=self.get_dataset_detail_url(dataset.pk)) ] + + self.network_fetcher_task = network.NetworkRequestTask( + requests_to_perform, + self.network_requests_timeout, + self.auth_config, + description="Get dataset detail", + ) + self.network_fetcher_task.task_done.connect(self.handle_dataset_detail) + qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) + + def get_style_detail( + self, + dataset: typing.Union[models.BriefDataset, models.Dataset], + get_style_too: bool = True, + ) -> None: + if get_style_too: is_vector = ( dataset.dataset_sub_type == models.GeonodeResourceType.VECTOR_LAYER @@ -136,7 +152,7 @@ def get_dataset_detail( ) if is_vector and should_load_vector_style: sld_url = QtCore.QUrl(dataset.default_style.sld_url) - requests_to_perform.append(network.RequestToPerform(url=sld_url)) + requests_to_perform = [network.RequestToPerform(url=sld_url)] self.network_fetcher_task = network.NetworkRequestTask( requests_to_perform, @@ -144,7 +160,7 @@ def get_dataset_detail( self.auth_config, description="Get dataset detail", ) - self.network_fetcher_task.task_done.connect(self.handle_dataset_detail) + self.network_fetcher_task.task_done.connect(self.handle_sld_detail) qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) def handle_dataset_detail(self, result: bool): @@ -157,6 +173,16 @@ def handle_dataset_detail(self, result: bool): raise NotImplementedError + def handle_sld_detail(self, result, bool): + """Handle sld detail retrieval outcome. + + This method should emit either `dataset_sld_received` or + `dataset_sld_error_received`. + + """ + + raise NotImplementedError + def get_dataset_detail_from_id(self, dataset_id: int): self.network_fetcher_task = network.NetworkRequestTask( [network.RequestToPerform(url=self.get_dataset_detail_url(dataset_id))], diff --git a/src/qgis_geonode/apiclient/geonode_api_v2.py b/src/qgis_geonode/apiclient/geonode_api_v2.py index 33fc684..cff9499 100644 --- a/src/qgis_geonode/apiclient/geonode_api_v2.py +++ b/src/qgis_geonode/apiclient/geonode_api_v2.py @@ -266,22 +266,35 @@ def handle_dataset_detail(self, task_result: bool) -> None: f"Could not parse server response into a dataset: {str(exc)}", debug=False, ) - else: - try: - style_response_contents = ( - self.network_fetcher_task.response_contents[1] - ) - except IndexError: - pass - else: - ( - sld_named_layer, - error_message, - ) = geonode_styles.get_usable_sld(style_response_contents) - if sld_named_layer is None: - raise RuntimeError(error_message) - dataset.default_style.sld = sld_named_layer - self.dataset_detail_received.emit(dataset) + + self.dataset_detail_received.emit(dataset) + + def handle_sld_detail(self, task_result: bool) -> None: + response_contents = self._retrieve_response( + task_result, + 0, + self.style_detail_error_received + # deserialize_as_json=False + ) + # if response_contents is not None: + # style_response_contents = response_contents + # + # self.dataset_sld_received.emit(style_response_contents) + try: + style_response_contents = response_contents + + except IndexError: + pass + else: + ( + sld_named_layer, + error_message, + ) = geonode_styles.get_usable_sld(style_response_contents) + if sld_named_layer is None: + raise RuntimeError(error_message) + # dataset.default_style.sld = sld_named_layer + + self.dataset_sld_received.emit(sld_named_layer) def handle_dataset_style( self, diff --git a/src/qgis_geonode/gui/search_result_widget.py b/src/qgis_geonode/gui/search_result_widget.py index 7be16c6..5ab70a6 100644 --- a/src/qgis_geonode/gui/search_result_widget.py +++ b/src/qgis_geonode/gui/search_result_widget.py @@ -224,9 +224,12 @@ def prepare_loaded_layer(self): self.layer = self.dataset_loader_task.layer self.api_client.dataset_detail_received.connect(self.handle_layer_detail) self.api_client.dataset_detail_error_received.connect(self.handle_loading_error) + self.api_client.dataset_sld_received.connect(self.handle_layer_detail) self.api_client.get_dataset_detail( - self.brief_dataset, get_style_too=self.layer.dataProvider().name() != "wms" + self.brief_dataset, + # get_style_too=self.layer.dataProvider().name() != "wms" ) + self.api_client.get_style_detail(self.brief_dataset) def handle_layer_detail(self, dataset: typing.Optional[models.Dataset]): self.api_client.dataset_detail_received.disconnect(self.handle_layer_detail) From 967a8c07140baae043fcce624a76348a401cfa29 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Fri, 22 Nov 2024 12:00:41 +0200 Subject: [PATCH 12/15] removing duplicated code --- src/qgis_geonode/apiclient/base.py | 42 +------------------- src/qgis_geonode/apiclient/geonode_api_v2.py | 42 ++++++-------------- src/qgis_geonode/gui/search_result_widget.py | 2 - 3 files changed, 14 insertions(+), 72 deletions(-) diff --git a/src/qgis_geonode/apiclient/base.py b/src/qgis_geonode/apiclient/base.py index a65d4d9..e238118 100644 --- a/src/qgis_geonode/apiclient/base.py +++ b/src/qgis_geonode/apiclient/base.py @@ -28,7 +28,6 @@ class BaseGeonodeClient(QtCore.QObject): dataset_list_received = QtCore.pyqtSignal(list, models.GeonodePaginationInfo) dataset_detail_received = QtCore.pyqtSignal(object) - dataset_sld_received = QtCore.pyqtSignal(QtXml.QDomElement) dataset_detail_error_received = QtCore.pyqtSignal([str], [str, int, str]) style_detail_received = QtCore.pyqtSignal(QtXml.QDomElement) style_detail_error_received = QtCore.pyqtSignal([str], [str, int, str]) @@ -124,12 +123,9 @@ def get_dataset_detail( self, dataset: typing.Union[models.BriefDataset, models.Dataset], ) -> None: - requests_to_perform = [ - network.RequestToPerform(url=self.get_dataset_detail_url(dataset.pk)) - ] self.network_fetcher_task = network.NetworkRequestTask( - requests_to_perform, + [network.RequestToPerform(url=self.get_dataset_detail_url(dataset.pk))], self.network_requests_timeout, self.auth_config, description="Get dataset detail", @@ -137,32 +133,6 @@ def get_dataset_detail( self.network_fetcher_task.task_done.connect(self.handle_dataset_detail) qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) - def get_style_detail( - self, - dataset: typing.Union[models.BriefDataset, models.Dataset], - get_style_too: bool = True, - ) -> None: - - if get_style_too: - is_vector = ( - dataset.dataset_sub_type == models.GeonodeResourceType.VECTOR_LAYER - ) - should_load_vector_style = ( - models.ApiClientCapability.LOAD_VECTOR_LAYER_STYLE in self.capabilities - ) - if is_vector and should_load_vector_style: - sld_url = QtCore.QUrl(dataset.default_style.sld_url) - requests_to_perform = [network.RequestToPerform(url=sld_url)] - - self.network_fetcher_task = network.NetworkRequestTask( - requests_to_perform, - self.network_requests_timeout, - self.auth_config, - description="Get dataset detail", - ) - self.network_fetcher_task.task_done.connect(self.handle_sld_detail) - qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) - def handle_dataset_detail(self, result: bool): """Handle dataset detail retrieval outcome. @@ -173,16 +143,6 @@ def handle_dataset_detail(self, result: bool): raise NotImplementedError - def handle_sld_detail(self, result, bool): - """Handle sld detail retrieval outcome. - - This method should emit either `dataset_sld_received` or - `dataset_sld_error_received`. - - """ - - raise NotImplementedError - def get_dataset_detail_from_id(self, dataset_id: int): self.network_fetcher_task = network.NetworkRequestTask( [network.RequestToPerform(url=self.get_dataset_detail_url(dataset_id))], diff --git a/src/qgis_geonode/apiclient/geonode_api_v2.py b/src/qgis_geonode/apiclient/geonode_api_v2.py index cff9499..b25dc7a 100644 --- a/src/qgis_geonode/apiclient/geonode_api_v2.py +++ b/src/qgis_geonode/apiclient/geonode_api_v2.py @@ -266,35 +266,19 @@ def handle_dataset_detail(self, task_result: bool) -> None: f"Could not parse server response into a dataset: {str(exc)}", debug=False, ) - - self.dataset_detail_received.emit(dataset) - - def handle_sld_detail(self, task_result: bool) -> None: - response_contents = self._retrieve_response( - task_result, - 0, - self.style_detail_error_received - # deserialize_as_json=False - ) - # if response_contents is not None: - # style_response_contents = response_contents - # - # self.dataset_sld_received.emit(style_response_contents) - try: - style_response_contents = response_contents - - except IndexError: - pass - else: - ( - sld_named_layer, - error_message, - ) = geonode_styles.get_usable_sld(style_response_contents) - if sld_named_layer is None: - raise RuntimeError(error_message) - # dataset.default_style.sld = sld_named_layer - - self.dataset_sld_received.emit(sld_named_layer) + else: + is_vector = ( + dataset.dataset_sub_type == models.GeonodeResourceType.VECTOR_LAYER + ) + should_load_vector_style = ( + models.ApiClientCapability.LOAD_VECTOR_LAYER_STYLE + in self.capabilities + ) + # Check if the layer is vector and if it has the permissions to read the style + if is_vector and should_load_vector_style: + self.get_dataset_style(dataset, emit_dataset_detail_received=True) + else: + self.dataset_detail_received.emit(dataset) def handle_dataset_style( self, diff --git a/src/qgis_geonode/gui/search_result_widget.py b/src/qgis_geonode/gui/search_result_widget.py index 5ab70a6..a65c641 100644 --- a/src/qgis_geonode/gui/search_result_widget.py +++ b/src/qgis_geonode/gui/search_result_widget.py @@ -224,12 +224,10 @@ def prepare_loaded_layer(self): self.layer = self.dataset_loader_task.layer self.api_client.dataset_detail_received.connect(self.handle_layer_detail) self.api_client.dataset_detail_error_received.connect(self.handle_loading_error) - self.api_client.dataset_sld_received.connect(self.handle_layer_detail) self.api_client.get_dataset_detail( self.brief_dataset, # get_style_too=self.layer.dataProvider().name() != "wms" ) - self.api_client.get_style_detail(self.brief_dataset) def handle_layer_detail(self, dataset: typing.Optional[models.Dataset]): self.api_client.dataset_detail_received.disconnect(self.handle_layer_detail) From a36d94e988472410491450f1cf225f58b0fa9ac7 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Fri, 22 Nov 2024 16:16:04 +0200 Subject: [PATCH 13/15] check if it is a WFS or WMS request in handle_dataset_detail --- src/qgis_geonode/apiclient/base.py | 5 +++- src/qgis_geonode/apiclient/geonode_api_v2.py | 29 ++++++++++++-------- src/qgis_geonode/gui/search_result_widget.py | 3 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/qgis_geonode/apiclient/base.py b/src/qgis_geonode/apiclient/base.py index e238118..70a24a2 100644 --- a/src/qgis_geonode/apiclient/base.py +++ b/src/qgis_geonode/apiclient/base.py @@ -122,6 +122,7 @@ def handle_dataset_style( def get_dataset_detail( self, dataset: typing.Union[models.BriefDataset, models.Dataset], + get_style_too: bool = False, ) -> None: self.network_fetcher_task = network.NetworkRequestTask( @@ -130,7 +131,9 @@ def get_dataset_detail( self.auth_config, description="Get dataset detail", ) - self.network_fetcher_task.task_done.connect(self.handle_dataset_detail) + self.network_fetcher_task.task_done.connect( + partial(self.handle_dataset_detail, get_style_too=get_style_too) + ) qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) def handle_dataset_detail(self, result: bool): diff --git a/src/qgis_geonode/apiclient/geonode_api_v2.py b/src/qgis_geonode/apiclient/geonode_api_v2.py index b25dc7a..c573101 100644 --- a/src/qgis_geonode/apiclient/geonode_api_v2.py +++ b/src/qgis_geonode/apiclient/geonode_api_v2.py @@ -251,7 +251,9 @@ def handle_dataset_list(self, task_result: bool) -> None: ) self.dataset_list_received.emit(brief_datasets, pagination_info) - def handle_dataset_detail(self, task_result: bool) -> None: + def handle_dataset_detail( + self, task_result: bool, get_style_too: bool = False + ) -> None: log("inside the API client's handle_dataset_detail") deserialized_resource = self._retrieve_response( task_result, 0, self.dataset_detail_error_received @@ -267,16 +269,21 @@ def handle_dataset_detail(self, task_result: bool) -> None: debug=False, ) else: - is_vector = ( - dataset.dataset_sub_type == models.GeonodeResourceType.VECTOR_LAYER - ) - should_load_vector_style = ( - models.ApiClientCapability.LOAD_VECTOR_LAYER_STYLE - in self.capabilities - ) - # Check if the layer is vector and if it has the permissions to read the style - if is_vector and should_load_vector_style: - self.get_dataset_style(dataset, emit_dataset_detail_received=True) + # check if the request is from a WFS to see if it will retrieve the style + if get_style_too: + is_vector = ( + dataset.dataset_sub_type + == models.GeonodeResourceType.VECTOR_LAYER + ) + should_load_vector_style = ( + models.ApiClientCapability.LOAD_VECTOR_LAYER_STYLE + in self.capabilities + ) + # Check if the layer is vector and if it has the permissions to read the style + if is_vector and should_load_vector_style: + self.get_dataset_style( + dataset, emit_dataset_detail_received=True + ) else: self.dataset_detail_received.emit(dataset) diff --git a/src/qgis_geonode/gui/search_result_widget.py b/src/qgis_geonode/gui/search_result_widget.py index a65c641..7be16c6 100644 --- a/src/qgis_geonode/gui/search_result_widget.py +++ b/src/qgis_geonode/gui/search_result_widget.py @@ -225,8 +225,7 @@ def prepare_loaded_layer(self): self.api_client.dataset_detail_received.connect(self.handle_layer_detail) self.api_client.dataset_detail_error_received.connect(self.handle_loading_error) self.api_client.get_dataset_detail( - self.brief_dataset, - # get_style_too=self.layer.dataProvider().name() != "wms" + self.brief_dataset, get_style_too=self.layer.dataProvider().name() != "wms" ) def handle_layer_detail(self, dataset: typing.Optional[models.Dataset]): From 4d45f7be08d700d8754210c51c0cd1ecaf0fd2ec Mon Sep 17 00:00:00 2001 From: gpetrak Date: Tue, 26 Nov 2024 12:07:29 +0200 Subject: [PATCH 14/15] retrieve the WFS layer without a style for non-authenticated users --- src/qgis_geonode/apiclient/base.py | 13 ++++++++++++- src/qgis_geonode/apiclient/geonode_api_v2.py | 7 +++++-- .../gui/geonode_map_layer_config_widget.py | 11 ++++++++--- src/qgis_geonode/gui/search_result_widget.py | 10 ++++++++-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/qgis_geonode/apiclient/base.py b/src/qgis_geonode/apiclient/base.py index 70a24a2..5b5ce6b 100644 --- a/src/qgis_geonode/apiclient/base.py +++ b/src/qgis_geonode/apiclient/base.py @@ -123,8 +123,15 @@ def get_dataset_detail( self, dataset: typing.Union[models.BriefDataset, models.Dataset], get_style_too: bool = False, + authenticated: bool = False, ) -> None: + auth_manager = qgis.core.QgsApplication.authManager() + auth_provider_name = auth_manager.configAuthMethodKey(self.auth_config).lower() + + if auth_provider_name == "basic": + authenticated = True + self.network_fetcher_task = network.NetworkRequestTask( [network.RequestToPerform(url=self.get_dataset_detail_url(dataset.pk))], self.network_requests_timeout, @@ -132,7 +139,11 @@ def get_dataset_detail( description="Get dataset detail", ) self.network_fetcher_task.task_done.connect( - partial(self.handle_dataset_detail, get_style_too=get_style_too) + partial( + self.handle_dataset_detail, + get_style_too=get_style_too, + authenticated=authenticated, + ) ) qgis.core.QgsApplication.taskManager().addTask(self.network_fetcher_task) diff --git a/src/qgis_geonode/apiclient/geonode_api_v2.py b/src/qgis_geonode/apiclient/geonode_api_v2.py index c573101..d1cc8e6 100644 --- a/src/qgis_geonode/apiclient/geonode_api_v2.py +++ b/src/qgis_geonode/apiclient/geonode_api_v2.py @@ -252,7 +252,10 @@ def handle_dataset_list(self, task_result: bool) -> None: self.dataset_list_received.emit(brief_datasets, pagination_info) def handle_dataset_detail( - self, task_result: bool, get_style_too: bool = False + self, + task_result: bool, + get_style_too: bool = False, + authenticated: bool = False, ) -> None: log("inside the API client's handle_dataset_detail") deserialized_resource = self._retrieve_response( @@ -270,7 +273,7 @@ def handle_dataset_detail( ) else: # check if the request is from a WFS to see if it will retrieve the style - if get_style_too: + if get_style_too and authenticated: is_vector = ( dataset.dataset_sub_type == models.GeonodeResourceType.VECTOR_LAYER diff --git a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py index d6e9884..7a3c647 100644 --- a/src/qgis_geonode/gui/geonode_map_layer_config_widget.py +++ b/src/qgis_geonode/gui/geonode_map_layer_config_widget.py @@ -472,12 +472,17 @@ def _toggle_style_controls(self, enabled: bool) -> None: models.GeonodePermission.CHANGE_DATASET_STYLE in dataset.permissions ) is_service = self.layer.dataProvider().name().lower() in ("wfs", "wcs") - has_style_url = dataset.default_style.sld_url is not None - if can_load_style and has_style_url and is_service: + has_geonode_style = dataset.default_style.sld is not None + if can_load_style and has_geonode_style and is_service: widgets.append(self.download_style_pb) else: self.download_style_pb.setEnabled(False) - if allowed_to_modify and can_modify_style and has_style_url and is_service: + if ( + allowed_to_modify + and can_modify_style + and has_geonode_style + and is_service + ): widgets.append(self.upload_style_pb) else: self.upload_style_pb.setEnabled(False) diff --git a/src/qgis_geonode/gui/search_result_widget.py b/src/qgis_geonode/gui/search_result_widget.py index 7be16c6..a38bf24 100644 --- a/src/qgis_geonode/gui/search_result_widget.py +++ b/src/qgis_geonode/gui/search_result_widget.py @@ -228,7 +228,9 @@ def prepare_loaded_layer(self): self.brief_dataset, get_style_too=self.layer.dataProvider().name() != "wms" ) - def handle_layer_detail(self, dataset: typing.Optional[models.Dataset]): + def handle_layer_detail( + self, dataset: typing.Optional[models.Dataset], retrieved_style: bool = False + ): self.api_client.dataset_detail_received.disconnect(self.handle_layer_detail) self.layer.setCustomProperty( models.DATASET_CUSTOM_PROPERTY_KEY, @@ -245,7 +247,11 @@ def handle_layer_detail(self, dataset: typing.Optional[models.Dataset]): can_load_style = models.loading_style_supported( self.layer.type(), self.api_client.capabilities ) - if can_load_style and dataset.default_style: + + if dataset.default_style.sld is not None: + retrieved_style = True + + if can_load_style and retrieved_style: error_message = "" loaded_sld = self.layer.readSld(dataset.default_style.sld, error_message) if not loaded_sld: From 50c3d9c0c3056a374a5370ca672435d12bdcbe8a Mon Sep 17 00:00:00 2001 From: gpetrak Date: Wed, 27 Nov 2024 12:18:04 +0200 Subject: [PATCH 15/15] handling an SLD request error --- src/qgis_geonode/gui/search_result_widget.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qgis_geonode/gui/search_result_widget.py b/src/qgis_geonode/gui/search_result_widget.py index a38bf24..02eb17e 100644 --- a/src/qgis_geonode/gui/search_result_widget.py +++ b/src/qgis_geonode/gui/search_result_widget.py @@ -224,6 +224,7 @@ def prepare_loaded_layer(self): self.layer = self.dataset_loader_task.layer self.api_client.dataset_detail_received.connect(self.handle_layer_detail) self.api_client.dataset_detail_error_received.connect(self.handle_loading_error) + self.api_client.style_detail_error_received.connect(self.handle_style_error) self.api_client.get_dataset_detail( self.brief_dataset, get_style_too=self.layer.dataProvider().name() != "wms" ) @@ -263,10 +264,16 @@ def handle_loading_error(self): self.data_source_widget.show_message(message, level=qgis.core.Qgis.Critical) self.handle_layer_load_end(clear_message_bar=False) + def handle_style_error(self): + message = f"Unable to retrieve the style of {self.brief_dataset.title}" + self.data_source_widget.show_message(message, level=qgis.core.Qgis.Critical) + self.handle_layer_load_end(clear_message_bar=False) + def add_layer_to_project(self): self.api_client.dataset_detail_error_received.disconnect( self.handle_loading_error ) + self.api_client.style_detail_error_received.disconnect(self.handle_style_error) self.project.addMapLayer(self.layer) self.handle_layer_load_end()