From e03a9efe6d841d348bf822035b700ee026b3bf78 Mon Sep 17 00:00:00 2001 From: Miikka Kallio Date: Thu, 21 Nov 2024 17:55:41 +0200 Subject: [PATCH 1/3] Save plan and plan outline as JSON. - Added UI for selecting path for saving JSONs - Added get_plan_json that calls lambda with the active_plan_id. The JSONs are extracted from the response and saved at user defined location. - Changed default lambda port. Refactor get_plan_json. Changed lambda call to use QNetworkRequest and created the required QNetworkProxy. Changed settings to store Proxy host and port. Added lambda url to settings. Cleanup --- arho_feature_template/core/plan_manager.py | 112 ++++++++++++++++++- arho_feature_template/gui/plugin_settings.py | 15 ++- arho_feature_template/gui/plugin_settings.ui | 14 ++- arho_feature_template/gui/serialize_plan.py | 50 +++++++++ arho_feature_template/gui/serialize_plan.ui | 89 +++++++++++++++ arho_feature_template/plugin.py | 13 +++ arho_feature_template/utils/misc_utils.py | 11 +- 7 files changed, 289 insertions(+), 15 deletions(-) create mode 100644 arho_feature_template/gui/serialize_plan.py create mode 100644 arho_feature_template/gui/serialize_plan.ui diff --git a/arho_feature_template/core/plan_manager.py b/arho_feature_template/core/plan_manager.py index 232ac70..c3d3544 100644 --- a/arho_feature_template/core/plan_manager.py +++ b/arho_feature_template/core/plan_manager.py @@ -1,16 +1,40 @@ +import json + from qgis.core import QgsExpressionContextUtils, QgsProject, QgsVectorLayer +from qgis.PyQt.QtCore import QByteArray, QUrl +from qgis.PyQt.QtNetwork import QNetworkAccessManager, QNetworkProxy, QNetworkReply, QNetworkRequest from qgis.PyQt.QtWidgets import QDialog, QMessageBox from qgis.utils import iface from arho_feature_template.core.update_plan import LandUsePlan, update_selected_plan from arho_feature_template.gui.load_plan_dialog import LoadPlanDialog +from arho_feature_template.gui.serialize_plan import SerializePlan from arho_feature_template.utils.db_utils import get_existing_database_connection_names -from arho_feature_template.utils.misc_utils import get_layer_by_name, handle_unsaved_changes +from arho_feature_template.utils.misc_utils import get_active_plan_id, get_settings, handle_unsaved_changes class PlanManager: def __init__(self): - self.kaava_layer = get_layer_by_name("Kaava") + # Init network manager + self.network_manager = QNetworkAccessManager() + proxy_host, proxy_port, self.lambda_url = get_settings() + + # SOCKS5 Proxy + proxy = QNetworkProxy() + proxy.setType(QNetworkProxy.Socks5Proxy) + proxy.setHostName(proxy_host) + proxy.setPort(int(proxy_port)) + self.network_manager.setProxy(proxy) + + self.kaava_layer = self.get_layer_by_name("Kaava") + + def get_layer_by_name(self, layer_name): + """Retrieve a layer by name from the project.""" + layers = QgsProject.instance().mapLayersByName(layer_name) + if layers: + return layers[0] + iface.messageBar().pushMessage("Error", f"Layer '{layer_name}' not found", level=3) + return None def add_new_plan(self): """Initiate the process to add a new plan to the Kaava layer.""" @@ -98,3 +122,87 @@ def commit_all_editable_layers(self): for layer in QgsProject.instance().mapLayers().values(): if isinstance(layer, QgsVectorLayer) and layer.isEditable(): layer.commitChanges() + + def get_plan_json(self): + """Serializes plan and plan outline to JSON""" + dialog = SerializePlan() + if dialog.exec_() == QDialog.Accepted: + json_plan_path = dialog.plan_path_edit.text() + json_plan_outline_path = dialog.plan_outline_path_edit.text() + + plan_id = get_active_plan_id() + + if not plan_id: + QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa. Luo tai avaa kaava.") + return + + payload = {"action": "get_plans", "plan_uuid": plan_id} + payload_bytes = QByteArray(json.dumps(payload).encode("utf-8")) + + request = QNetworkRequest(QUrl(self.lambda_url)) + request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") + + reply = self.network_manager.post(request, payload_bytes) + + # Connect the finished signal to a lambda to pass extra arguments + reply.finished.connect(lambda: self._handle_response(reply, json_plan_path, json_plan_outline_path)) + + def _handle_response(self, reply: QNetworkReply, json_plan_path: str, json_plan_outline_path: str): + """Handle the API response and process the plan and outline data.""" + if reply.error() != QNetworkReply.NoError: + error_string = reply.errorString() + QMessageBox.critical(None, "Virhe API kutsussa", f"Virhe: {error_string}") + return + + try: + response_data = reply.readAll().data().decode("utf-8") + response_json = json.loads(response_data) + + details = response_json.get("details") + if not details: + QMessageBox.warning(None, "Varoitus", "Vastauksesta puuttuu 'details' kenttä.") + return + + # Extract plan and write it to file + plan_id = get_active_plan_id() + if not plan_id: + QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa.") + return + + plan_json = details.get(plan_id) + if not plan_json: + QMessageBox.warning(None, "Varoitus", f"Aktiiviselle kaavalle (id: {plan_id}) ei löydy tietoja.") + return + + with open(json_plan_path, "w", encoding="utf-8") as full_file: + json.dump(plan_json, full_file, ensure_ascii=False, indent=2) + + # Process the geographicalArea for the outline + geographical_area = plan_json.get("geographicalArea") + if geographical_area: + try: + # Build the structured outline JSON and write to file + outline_json = { + "type": "Feature", + "properties": {"name": "Example Polygon"}, + "srid": geographical_area.get("srid"), + "geometry": geographical_area.get("geometry"), + } + + with open(json_plan_outline_path, "w", encoding="utf-8") as outline_file: + json.dump(outline_json, outline_file, ensure_ascii=False, indent=2) + + QMessageBox.information(None, "Success", "Kaava ja sen ulkorja tallennettu onnistuneesti.") + except KeyError as e: + QMessageBox.critical( + None, + "Virhe", + f"'geographicalArea' ei sisällä vaadittuja tietoja: {e}", + ) + else: + QMessageBox.warning(None, "Varoitus", "Kenttä 'geographicalArea' puuttuu kaavan tiedoista.") + except json.JSONDecodeError as e: + QMessageBox.critical(None, "Virhe", f"Vastaus JSON:in purkaminen epäonnistui: {e}") + + # Clean up the reply + reply.deleteLater() diff --git a/arho_feature_template/gui/plugin_settings.py b/arho_feature_template/gui/plugin_settings.py index 1bc1061..77fa6a7 100644 --- a/arho_feature_template/gui/plugin_settings.py +++ b/arho_feature_template/gui/plugin_settings.py @@ -22,16 +22,19 @@ def load_settings(self): """Load settings from QSettings with default values.""" settings = QSettings("ArhoFeatureTemplate") - lambda_host = settings.value("lambda_host", "localhost") - lambda_port = settings.value("lambda_port", "5435") + proxy_host = settings.value("proxy_host", "localhost") + proxy_port = settings.value("proxy_port", "5443") + lambda_url = settings.value("lambda_url", "https://t5w26iqnsf.execute-api.eu-central-1.amazonaws.com/v0/ryhti") - self.hostInput.setText(lambda_host) - self.portInput.setText(lambda_port) + self.hostInput.setText(proxy_host) + self.portInput.setText(proxy_port) + self.lambdaInput.setText(lambda_url) def save_settings(self): """Save settings to QSettings.""" settings = QSettings("ArhoFeatureTemplate") - settings.setValue("lambda_host", self.hostInput.text()) - settings.setValue("lambda_port", self.portInput.text()) + settings.setValue("proxy_host", self.hostInput.text()) + settings.setValue("proxy_port", self.portInput.text()) + settings.setValue("lambda_url", self.lambdaInput.text()) self.accept() diff --git a/arho_feature_template/gui/plugin_settings.ui b/arho_feature_template/gui/plugin_settings.ui index f438cd5..12dc285 100644 --- a/arho_feature_template/gui/plugin_settings.ui +++ b/arho_feature_template/gui/plugin_settings.ui @@ -17,7 +17,7 @@ - Lambdan isäntä: + Proxy isäntä: @@ -27,13 +27,23 @@ - Lambdan portti: + Proxy portti: + + + + Lambdan osoite: + + + + + + diff --git a/arho_feature_template/gui/serialize_plan.py b/arho_feature_template/gui/serialize_plan.py new file mode 100644 index 0000000..10a4464 --- /dev/null +++ b/arho_feature_template/gui/serialize_plan.py @@ -0,0 +1,50 @@ +from importlib import resources + +from qgis.PyQt import uic +from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QFileDialog, QLineEdit, QPushButton + +ui_path = resources.files(__package__) / "serialize_plan.ui" +FormClass, _ = uic.loadUiType(ui_path) + + +class SerializePlan(QDialog, FormClass): # type: ignore + def __init__(self): + super().__init__() + self.setupUi(self) + + self.plan_outline_path_edit = self.findChild(QLineEdit, "plan_outline_path_edit") + self.plan_path_edit = self.findChild(QLineEdit, "plan_path_edit") + self.plan_outline_select_button = self.findChild(QPushButton, "plan_outline_select_button") + self.plan_select_button = self.findChild(QPushButton, "plan_select_button") + + self.plan_outline_select_button.clicked.connect(self.select_plan_outline_file) + self.plan_select_button.clicked.connect(self.select_plan_file) + + # Disable Save button initially + self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False) + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.reject) + + def select_plan_outline_file(self): + file_path, _ = QFileDialog.getSaveFileName( + self, "Valitse kaavan ulkorajan tallennuspolku", "", "JSON Files (*.json)" + ) + if file_path: + self.plan_outline_path_edit.setText(file_path) + self.check_inputs() + + def select_plan_file(self): + file_path, _ = QFileDialog.getSaveFileName(self, "Valitse kaavan tallennuspolku", "", "JSON Files (*.json)") + if file_path: + self.plan_path_edit.setText(file_path) + self.check_inputs() + + def check_inputs(self): + # Enable Save button if both text fields have paths + if self.plan_outline_path_edit.text() and self.plan_path_edit.text(): + self.buttonBox.button(QDialogButtonBox.Save).setEnabled(True) + else: + self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False) + + def get_paths(self): + return self.plan_outline_path_edit.text(), self.plan_path_edit.text() diff --git a/arho_feature_template/gui/serialize_plan.ui b/arho_feature_template/gui/serialize_plan.ui new file mode 100644 index 0000000..1f2cdba --- /dev/null +++ b/arho_feature_template/gui/serialize_plan.ui @@ -0,0 +1,89 @@ + + + Dialog + + + + 0 + 0 + 558 + 193 + + + + Tallenna kaava JSON + + + + + 20 + 150 + 521 + 32 + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + true + + + + + + 20 + 20 + 521 + 120 + + + + + + + Kaavan ulkorajan tallennuspolku: + + + + + + + true + + + + + + + Valitse... + + + + + + + Kaavan tallennuspolku: + + + + + + + true + + + + + + + Valitse... + + + + + + + + + diff --git a/arho_feature_template/plugin.py b/arho_feature_template/plugin.py index eb85359..5b8dc8c 100644 --- a/arho_feature_template/plugin.py +++ b/arho_feature_template/plugin.py @@ -172,6 +172,15 @@ def initGui(self) -> None: # noqa N802 add_to_toolbar=True, ) + self.serialize_plan_action = self.add_action( + "", + text="Tallenna kaava JSON", + triggered_callback=self.serialize_plan, + add_to_menu=True, + add_to_toolbar=True, + status_tip="Tallenna aktiivinen kaava JSON muodossa", + ) + self.plugin_settings_action = self.add_action( "", text="Asetukset", @@ -191,6 +200,10 @@ def add_new_plan(self): def load_existing_land_use_plan(self): self.plan_manager.load_land_use_plan() + def serialize_plan(self): + """Serializes currently active plan.""" + self.plan_manager.get_plan_json() + def open_settings(self): """Open the plugin settings dialog.""" settings = PluginSettings() diff --git a/arho_feature_template/utils/misc_utils.py b/arho_feature_template/utils/misc_utils.py index 708ea3d..712afe6 100644 --- a/arho_feature_template/utils/misc_utils.py +++ b/arho_feature_template/utils/misc_utils.py @@ -106,9 +106,10 @@ def get_active_plan_id(): return QgsExpressionContextUtils.projectScope(QgsProject.instance()).variable("active_plan_id") -def get_lambda_settings(): - """Retrieve Lambda settings, using defaults if not set.""" +def get_settings(): + """Retrieve stored settings, using defaults if not set.""" settings = QSettings("ArhoFeatureTemplate") - lambda_host = settings.value("lambda_host", "localhost") - lambda_port = settings.value("lambda_port", "8083") - return lambda_host, lambda_port + proxy_host = settings.value("proxy_host", "localhost") + proxy_port = settings.value("proxy_port", "5443") + lambda_url = settings.value("lambda_url", "https://t5w26iqnsf.execute-api.eu-central-1.amazonaws.com/v0/ryhti") + return proxy_host, proxy_port, lambda_url From 63a3b36267840ca323885f2751572b0f764b274d Mon Sep 17 00:00:00 2001 From: Miikka Kallio Date: Thu, 28 Nov 2024 16:09:59 +0200 Subject: [PATCH 2/3] Moved lambda request and response handling to their own module. - Moved lambda request and response handling to their own module. - Added capability to use local docker lambdas. - Added utility to get plan name with plan_id from "Kaava" layer. Update lambda_service.py --- arho_feature_template/core/lambda_service.py | 95 +++++++++++++++ arho_feature_template/core/plan_manager.py | 118 +++++-------------- arho_feature_template/gui/serialize_plan.py | 10 +- arho_feature_template/utils/misc_utils.py | 14 ++- 4 files changed, 140 insertions(+), 97 deletions(-) create mode 100644 arho_feature_template/core/lambda_service.py diff --git a/arho_feature_template/core/lambda_service.py b/arho_feature_template/core/lambda_service.py new file mode 100644 index 0000000..2a71f0f --- /dev/null +++ b/arho_feature_template/core/lambda_service.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +import json + +from qgis.PyQt.QtCore import QByteArray, QObject, QUrl, pyqtSignal +from qgis.PyQt.QtNetwork import QNetworkAccessManager, QNetworkProxy, QNetworkReply, QNetworkRequest +from qgis.PyQt.QtWidgets import QMessageBox + +from arho_feature_template.utils.misc_utils import get_active_plan_id, get_plan_name, get_settings + + +class LambdaService(QObject): + jsons_received = pyqtSignal(dict, dict) + + def __init__(self): + super().__init__() # Ensure QObject initialization + # Init network manager + self.network_manager = QNetworkAccessManager() + + # Get settings + proxy_host, proxy_port, self.lambda_url = get_settings() + + if proxy_host and proxy_port: + # Set up SOCKS5 Proxy if values are provided + proxy = QNetworkProxy() + proxy.setType(QNetworkProxy.Socks5Proxy) + proxy.setHostName(proxy_host) + proxy.setPort(int(proxy_port)) + self.network_manager.setProxy(proxy) + + def send_request(self, action: str, plan_id: str): + """Sends a request to the lambda function.""" + payload = {"action": action, "plan_uuid": plan_id} + payload_bytes = QByteArray(json.dumps(payload).encode("utf-8")) + + request = QNetworkRequest(QUrl(self.lambda_url)) + request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") + + reply = self.network_manager.post(request, payload_bytes) + + # Connect reply signal to handle the response + reply.finished.connect(lambda: self._process_reply(reply)) + + def _process_reply(self, reply: QNetworkReply): + """Processes the reply from the lambda and emits signal.""" + plan_id = get_active_plan_id() + + if reply.error() != QNetworkReply.NoError: + error_string = reply.errorString() + QMessageBox.critical(None, "API Virhe", f"Lambdan kutsu epäonnistui: {error_string}") + reply.deleteLater() + return + + try: + response_data = reply.readAll().data().decode("utf-8") + + response_json = json.loads(response_data) + + # Determine if the proxy is set up. + if hasattr(self, "network_manager") and self.network_manager.proxy().type() == QNetworkProxy.Socks5Proxy: + # If proxy has been set up, retrieve 'details' directly + details = response_json.get("details", {}) + else: + # If proxy has not been set up (using local docker lambda), the response includes 'body'. + # In this case we need to retrieve 'details' from 'body' first. + body = response_json.get("body", {}) + details = body.get("details", {}) + + # Extract the plan JSON for the given plan_id + plan_json = details.get(plan_id, {}) + if not isinstance(plan_json, dict): + plan_json = {} + + outline_json = None + if plan_json: + geographical_area = plan_json.get("geographicalArea") + if geographical_area: + outline_name = get_plan_name(plan_id, language="fin") + outline_json = { + "type": "Feature", + "properties": {"name": outline_name}, + "srid": geographical_area.get("srid"), + "geometry": geographical_area.get("geometry"), + } + + if outline_json is None: + outline_json = {} # Fallback to empty dictionary if no outline JSON is created + + # Emit the signal with the two JSONs + self.jsons_received.emit(plan_json, outline_json) + + except json.JSONDecodeError as e: + QMessageBox.critical(None, "JSON Virhe", f"Failed to parse response JSON: {e}") + finally: + reply.deleteLater() diff --git a/arho_feature_template/core/plan_manager.py b/arho_feature_template/core/plan_manager.py index c3d3544..f990088 100644 --- a/arho_feature_template/core/plan_manager.py +++ b/arho_feature_template/core/plan_manager.py @@ -1,40 +1,26 @@ +from __future__ import annotations + import json from qgis.core import QgsExpressionContextUtils, QgsProject, QgsVectorLayer -from qgis.PyQt.QtCore import QByteArray, QUrl -from qgis.PyQt.QtNetwork import QNetworkAccessManager, QNetworkProxy, QNetworkReply, QNetworkRequest from qgis.PyQt.QtWidgets import QDialog, QMessageBox from qgis.utils import iface +from arho_feature_template.core.lambda_service import LambdaService from arho_feature_template.core.update_plan import LandUsePlan, update_selected_plan from arho_feature_template.gui.load_plan_dialog import LoadPlanDialog from arho_feature_template.gui.serialize_plan import SerializePlan from arho_feature_template.utils.db_utils import get_existing_database_connection_names -from arho_feature_template.utils.misc_utils import get_active_plan_id, get_settings, handle_unsaved_changes +from arho_feature_template.utils.misc_utils import get_active_plan_id, get_layer_by_name, handle_unsaved_changes class PlanManager: def __init__(self): - # Init network manager - self.network_manager = QNetworkAccessManager() - proxy_host, proxy_port, self.lambda_url = get_settings() - - # SOCKS5 Proxy - proxy = QNetworkProxy() - proxy.setType(QNetworkProxy.Socks5Proxy) - proxy.setHostName(proxy_host) - proxy.setPort(int(proxy_port)) - self.network_manager.setProxy(proxy) - - self.kaava_layer = self.get_layer_by_name("Kaava") - - def get_layer_by_name(self, layer_name): - """Retrieve a layer by name from the project.""" - layers = QgsProject.instance().mapLayersByName(layer_name) - if layers: - return layers[0] - iface.messageBar().pushMessage("Error", f"Layer '{layer_name}' not found", level=3) - return None + self.lambda_service = LambdaService() + self.lambda_service.jsons_received.connect(self.save_plan_jsons) + self.json_plan_path = None + self.json_plan_outline_path = None + self.kaava_layer = get_layer_by_name("Kaava") def add_new_plan(self): """Initiate the process to add a new plan to the Kaava layer.""" @@ -127,82 +113,32 @@ def get_plan_json(self): """Serializes plan and plan outline to JSON""" dialog = SerializePlan() if dialog.exec_() == QDialog.Accepted: - json_plan_path = dialog.plan_path_edit.text() - json_plan_outline_path = dialog.plan_outline_path_edit.text() + self.json_plan_path = dialog.plan_path_edit.text() + self.json_plan_outline_path = dialog.plan_outline_path_edit.text() plan_id = get_active_plan_id() - if not plan_id: - QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa. Luo tai avaa kaava.") + QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa.") return - payload = {"action": "get_plans", "plan_uuid": plan_id} - payload_bytes = QByteArray(json.dumps(payload).encode("utf-8")) - - request = QNetworkRequest(QUrl(self.lambda_url)) - request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") + self.lambda_service.send_request("get_plans", plan_id) - reply = self.network_manager.post(request, payload_bytes) - - # Connect the finished signal to a lambda to pass extra arguments - reply.finished.connect(lambda: self._handle_response(reply, json_plan_path, json_plan_outline_path)) - - def _handle_response(self, reply: QNetworkReply, json_plan_path: str, json_plan_outline_path: str): - """Handle the API response and process the plan and outline data.""" - if reply.error() != QNetworkReply.NoError: - error_string = reply.errorString() - QMessageBox.critical(None, "Virhe API kutsussa", f"Virhe: {error_string}") + def save_plan_jsons(self, plan_json, outline_json): + """This slot saves the plan and outline JSONs to files.""" + if plan_json is None or outline_json is None: + QMessageBox.critical(None, "Virhe", "Kaava tai sen ulkoraja ei löytynyt.") return - try: - response_data = reply.readAll().data().decode("utf-8") - response_json = json.loads(response_data) - - details = response_json.get("details") - if not details: - QMessageBox.warning(None, "Varoitus", "Vastauksesta puuttuu 'details' kenttä.") - return - - # Extract plan and write it to file - plan_id = get_active_plan_id() - if not plan_id: - QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa.") - return + # Retrieve paths + if self.json_plan_path is None or self.json_plan_outline_path is None: + QMessageBox.critical(None, "Virhe", "Tiedostopolut eivät ole saatavilla.") + return - plan_json = details.get(plan_id) - if not plan_json: - QMessageBox.warning(None, "Varoitus", f"Aktiiviselle kaavalle (id: {plan_id}) ei löydy tietoja.") - return + # Save the JSONs + with open(self.json_plan_path, "w", encoding="utf-8") as full_file: + json.dump(plan_json, full_file, ensure_ascii=False, indent=2) - with open(json_plan_path, "w", encoding="utf-8") as full_file: - json.dump(plan_json, full_file, ensure_ascii=False, indent=2) - - # Process the geographicalArea for the outline - geographical_area = plan_json.get("geographicalArea") - if geographical_area: - try: - # Build the structured outline JSON and write to file - outline_json = { - "type": "Feature", - "properties": {"name": "Example Polygon"}, - "srid": geographical_area.get("srid"), - "geometry": geographical_area.get("geometry"), - } - - with open(json_plan_outline_path, "w", encoding="utf-8") as outline_file: - json.dump(outline_json, outline_file, ensure_ascii=False, indent=2) - - QMessageBox.information(None, "Success", "Kaava ja sen ulkorja tallennettu onnistuneesti.") - except KeyError as e: - QMessageBox.critical( - None, - "Virhe", - f"'geographicalArea' ei sisällä vaadittuja tietoja: {e}", - ) - else: - QMessageBox.warning(None, "Varoitus", "Kenttä 'geographicalArea' puuttuu kaavan tiedoista.") - except json.JSONDecodeError as e: - QMessageBox.critical(None, "Virhe", f"Vastaus JSON:in purkaminen epäonnistui: {e}") + with open(self.json_plan_outline_path, "w", encoding="utf-8") as outline_file: + json.dump(outline_json, outline_file, ensure_ascii=False, indent=2) - # Clean up the reply - reply.deleteLater() + QMessageBox.information(None, "Tallennus onnistui", "Kaava ja sen ulkoraja tallennettu onnistuneesti.") diff --git a/arho_feature_template/gui/serialize_plan.py b/arho_feature_template/gui/serialize_plan.py index 10a4464..dc8163d 100644 --- a/arho_feature_template/gui/serialize_plan.py +++ b/arho_feature_template/gui/serialize_plan.py @@ -8,15 +8,15 @@ class SerializePlan(QDialog, FormClass): # type: ignore + plan_outline_path_edit: QLineEdit + plan_path_edit: QLineEdit + plan_outline_select_button: QPushButton + plan_select_button: QPushButton + def __init__(self): super().__init__() self.setupUi(self) - self.plan_outline_path_edit = self.findChild(QLineEdit, "plan_outline_path_edit") - self.plan_path_edit = self.findChild(QLineEdit, "plan_path_edit") - self.plan_outline_select_button = self.findChild(QPushButton, "plan_outline_select_button") - self.plan_select_button = self.findChild(QPushButton, "plan_select_button") - self.plan_outline_select_button.clicked.connect(self.select_plan_outline_file) self.plan_select_button.clicked.connect(self.select_plan_file) diff --git a/arho_feature_template/utils/misc_utils.py b/arho_feature_template/utils/misc_utils.py index 712afe6..7810968 100644 --- a/arho_feature_template/utils/misc_utils.py +++ b/arho_feature_template/utils/misc_utils.py @@ -102,7 +102,6 @@ def handle_unsaved_changes() -> bool: def get_active_plan_id(): """Retrieve the active plan ID stored as a project variable.""" - # return QgsExpressionContextUtils.projectScope(QgsProject.instance(), "active_plan_id") return QgsExpressionContextUtils.projectScope(QgsProject.instance()).variable("active_plan_id") @@ -113,3 +112,16 @@ def get_settings(): proxy_port = settings.value("proxy_port", "5443") lambda_url = settings.value("lambda_url", "https://t5w26iqnsf.execute-api.eu-central-1.amazonaws.com/v0/ryhti") return proxy_host, proxy_port, lambda_url + + +def get_plan_name(plan_id: str, language: Literal["fin", "eng", "swe"] = "fin") -> str: + """Retrieve the name of a plan from the 'Kaava' layer based on its ID.""" + layer = get_layer_by_name("Kaava") + if layer: + for feature in layer.getFeatures(): + if feature["id"] == plan_id: + name_field = feature["name"] + name = name_field.get(language, "") + # Return "Nimetön" if the name is an empty string + return name if name.strip() else "Nimetön" + return "Nimetön" From 4d8202d57b14a59478f37d6ac76daa7d4011fe7e Mon Sep 17 00:00:00 2001 From: Miikka Kallio Date: Tue, 3 Dec 2024 10:53:21 +0200 Subject: [PATCH 3/3] Initialize or reset proxy each time before request is sent. Initialize or reset proxy each time before request is sent. Create LambdaService object when button is pressed. Removed redundant code. --- arho_feature_template/core/lambda_service.py | 15 +++++++-------- arho_feature_template/core/plan_manager.py | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arho_feature_template/core/lambda_service.py b/arho_feature_template/core/lambda_service.py index 2a71f0f..fbc5a69 100644 --- a/arho_feature_template/core/lambda_service.py +++ b/arho_feature_template/core/lambda_service.py @@ -17,9 +17,12 @@ def __init__(self): # Init network manager self.network_manager = QNetworkAccessManager() - # Get settings + def send_request(self, action: str, plan_id: str): + """Sends a request to the lambda function.""" + proxy_host, proxy_port, self.lambda_url = get_settings() + # Initialize or reset proxy each time a request is sent. Incase settings have changed. if proxy_host and proxy_port: # Set up SOCKS5 Proxy if values are provided proxy = QNetworkProxy() @@ -27,9 +30,9 @@ def __init__(self): proxy.setHostName(proxy_host) proxy.setPort(int(proxy_port)) self.network_manager.setProxy(proxy) + else: + self.network_manager.setProxy(QNetworkProxy()) - def send_request(self, action: str, plan_id: str): - """Sends a request to the lambda function.""" payload = {"action": action, "plan_uuid": plan_id} payload_bytes = QByteArray(json.dumps(payload).encode("utf-8")) @@ -53,7 +56,6 @@ def _process_reply(self, reply: QNetworkReply): try: response_data = reply.readAll().data().decode("utf-8") - response_json = json.loads(response_data) # Determine if the proxy is set up. @@ -71,7 +73,7 @@ def _process_reply(self, reply: QNetworkReply): if not isinstance(plan_json, dict): plan_json = {} - outline_json = None + outline_json = {} if plan_json: geographical_area = plan_json.get("geographicalArea") if geographical_area: @@ -83,9 +85,6 @@ def _process_reply(self, reply: QNetworkReply): "geometry": geographical_area.get("geometry"), } - if outline_json is None: - outline_json = {} # Fallback to empty dictionary if no outline JSON is created - # Emit the signal with the two JSONs self.jsons_received.emit(plan_json, outline_json) diff --git a/arho_feature_template/core/plan_manager.py b/arho_feature_template/core/plan_manager.py index f990088..83e0510 100644 --- a/arho_feature_template/core/plan_manager.py +++ b/arho_feature_template/core/plan_manager.py @@ -16,8 +16,6 @@ class PlanManager: def __init__(self): - self.lambda_service = LambdaService() - self.lambda_service.jsons_received.connect(self.save_plan_jsons) self.json_plan_path = None self.json_plan_outline_path = None self.kaava_layer = get_layer_by_name("Kaava") @@ -121,6 +119,8 @@ def get_plan_json(self): QMessageBox.critical(None, "Virhe", "Ei aktiivista kaavaa.") return + self.lambda_service = LambdaService() + self.lambda_service.jsons_received.connect(self.save_plan_jsons) self.lambda_service.send_request("get_plans", plan_id) def save_plan_jsons(self, plan_json, outline_json):