From f6ff5590fe5929a0610dd5df904be59083de3765 Mon Sep 17 00:00:00 2001 From: gpetrak Date: Wed, 20 Nov 2024 17:38:30 +0200 Subject: [PATCH 1/5] 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 229926be..a65d4d95 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 33fc6848..cff94998 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 7be16c62..5ab70a65 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 2/5] 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 a65d4d95..e2381188 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 cff94998..b25dc7a9 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 5ab70a65..a65c6414 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 3/5] 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 e2381188..70a24a28 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 b25dc7a9..c573101f 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 a65c6414..7be16c62 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 4/5] 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 70a24a28..5b5ce6b2 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 c573101f..d1cc8e65 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 d6e98844..7a3c647b 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 7be16c62..a38bf24a 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 5/5] 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 a38bf24a..02eb17e2 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()