Skip to content

Commit 99dc94e

Browse files
committed
Refactor common reply handling
1 parent ccf6b43 commit 99dc94e

File tree

1 file changed

+57
-67
lines changed

1 file changed

+57
-67
lines changed
+57-67
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from __future__ import annotations
22

33
import json
4+
import re
5+
from http import HTTPStatus
6+
from typing import cast
47

58
from qgis.PyQt.QtCore import QByteArray, QObject, QUrl, pyqtSignal
69
from qgis.PyQt.QtNetwork import QNetworkAccessManager, QNetworkProxy, QNetworkReply, QNetworkRequest
@@ -12,7 +15,7 @@
1215
class LambdaService(QObject):
1316
jsons_received = pyqtSignal(dict, dict)
1417
validation_received = pyqtSignal(dict)
15-
ActionAttribute = QNetworkRequest.User + 1
18+
ActionAttribute = cast(QNetworkRequest.Attribute, QNetworkRequest.User + 1)
1619
ACTION_VALIDATE_PLANS = "validate_plans"
1720
ACTION_GET_PLANS = "get_plans"
1821

@@ -49,87 +52,74 @@ def _send_request(self, action: str, plan_id: str):
4952
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
5053
self.network_manager.post(request, payload_bytes)
5154

52-
def _handle_reply(self, reply: QNetworkReply):
53-
action = reply.request().attribute(LambdaService.ActionAttribute)
54-
if action == self.ACTION_GET_PLANS:
55-
self._process_json_reply(reply)
56-
elif action == self.ACTION_VALIDATE_PLANS:
57-
self._process_validation_reply(reply)
55+
def _is_api_gateway_request(self) -> bool:
56+
"""Determines if the lambda request is going through the API Gateway."""
57+
match = re.match(r"^https://.*execute-api.*amazonaws\.com.*$", self.lambda_url)
58+
return bool(match)
5859

59-
def _process_validation_reply(self, reply: QNetworkReply):
60-
"""Processes the validation reply from the lambda and emits a signal."""
60+
def _handle_reply(self, reply: QNetworkReply):
6161
if reply.error() != QNetworkReply.NoError:
62-
error_string = reply.errorString()
63-
QMessageBox.critical(None, "API Error", f"Lambda call failed: {error_string}")
62+
error = reply.errorString()
63+
QMessageBox.critical(None, "API Error", f"Lambda call failed: {error}")
6464
reply.deleteLater()
6565
return
6666

6767
try:
6868
response_data = reply.readAll().data().decode("utf-8")
6969
response_json = json.loads(response_data)
7070

71-
# Determine if the proxy is set up.
72-
if hasattr(self, "network_manager") and self.network_manager.proxy().type() == QNetworkProxy.Socks5Proxy:
73-
# If proxy has been set up, retrieve 'ryhti_responses' directly
74-
validation_errors = response_json.get("ryhti_responses", {})
71+
if not self._is_api_gateway_request():
72+
# If calling the lambda directly, the response includes status code and body
73+
if int(response_json.get("statusCode", 0)) != HTTPStatus.OK:
74+
error = response_json["body"] if "body" in response_json else response_json["errorMessage"]
75+
QMessageBox.critical(None, "API Error", f"Lambda call failed: {error}")
76+
reply.deleteLater()
77+
return
78+
body = response_json["body"]
7579
else:
76-
# If proxy has not been set up (using local docker lambda), the response includes 'body'.
77-
# In this case we need to retrieve 'ryhti_responses' from 'body' first.
78-
body = response_json.get("body", {})
79-
validation_errors = body.get("ryhti_responses", {})
80-
81-
self.validation_received.emit(validation_errors)
80+
body = response_json
8281

83-
except json.JSONDecodeError as e:
82+
except (json.JSONDecodeError, KeyError) as e:
8483
QMessageBox.critical(None, "JSON Error", f"Failed to parse response JSON: {e}")
84+
return
8585
finally:
8686
reply.deleteLater()
8787

88-
def _process_json_reply(self, reply: QNetworkReply):
89-
"""Processes the reply from the lambda and emits signal."""
90-
plan_id = get_active_plan_id()
88+
action = reply.request().attribute(LambdaService.ActionAttribute)
89+
if action == self.ACTION_GET_PLANS:
90+
self._process_json_reply(body)
91+
elif action == self.ACTION_VALIDATE_PLANS:
92+
self._process_validation_reply(body)
9193

92-
if reply.error() != QNetworkReply.NoError:
93-
error_string = reply.errorString()
94-
QMessageBox.critical(None, "API Virhe", f"Lambdan kutsu epäonnistui: {error_string}")
95-
reply.deleteLater()
96-
return
94+
def _process_validation_reply(self, response_json: dict):
95+
"""Processes the validation reply from the lambda and emits a signal."""
9796

98-
try:
99-
response_data = reply.readAll().data().decode("utf-8")
100-
response_json = json.loads(response_data)
97+
validation_errors = response_json.get("ryhti_responses")
10198

102-
# Determine if the proxy is set up.
103-
if hasattr(self, "network_manager") and self.network_manager.proxy().type() == QNetworkProxy.Socks5Proxy:
104-
# If proxy has been set up, retrieve 'details' directly
105-
details = response_json.get("details", {})
106-
else:
107-
# If proxy has not been set up (using local docker lambda), the response includes 'body'.
108-
# In this case we need to retrieve 'details' from 'body' first.
109-
body = response_json.get("body", {})
110-
details = body.get("details", {})
111-
112-
# Extract the plan JSON for the given plan_id
113-
plan_json = details.get(plan_id, {})
114-
if not isinstance(plan_json, dict):
115-
plan_json = {}
116-
117-
outline_json = {}
118-
if plan_json:
119-
geographical_area = plan_json.get("geographicalArea")
120-
if geographical_area:
121-
outline_name = get_plan_name(plan_id, language="fin")
122-
outline_json = {
123-
"type": "Feature",
124-
"properties": {"name": outline_name},
125-
"srid": geographical_area.get("srid"),
126-
"geometry": geographical_area.get("geometry"),
127-
}
128-
129-
# Emit the signal with the two JSONs
130-
self.jsons_received.emit(plan_json, outline_json)
131-
132-
except json.JSONDecodeError as e:
133-
QMessageBox.critical(None, "JSON Virhe", f"Failed to parse response JSON: {e}")
134-
finally:
135-
reply.deleteLater()
99+
self.validation_received.emit(validation_errors)
100+
101+
def _process_json_reply(self, response_json: dict):
102+
"""Processes the reply from the lambda and emits signal."""
103+
plan_id = get_active_plan_id()
104+
105+
details = response_json.get("details", {})
106+
107+
# Extract the plan JSON for the given plan_id
108+
plan_json = details.get(plan_id, {})
109+
if not isinstance(plan_json, dict):
110+
plan_json = {}
111+
112+
outline_json = {}
113+
if plan_json:
114+
geographical_area = plan_json.get("geographicalArea")
115+
if geographical_area:
116+
outline_name = get_plan_name(plan_id, language="fin")
117+
outline_json = {
118+
"type": "Feature",
119+
"properties": {"name": outline_name},
120+
"srid": geographical_area.get("srid"),
121+
"geometry": geographical_area.get("geometry"),
122+
}
123+
124+
# Emit the signal with the two JSONs
125+
self.jsons_received.emit(plan_json, outline_json)

0 commit comments

Comments
 (0)