Skip to content

Commit e18e4f0

Browse files
authored
Merge pull request #90 from digital-land/1798-jsonpath-bug-sentry-logging-error-detail
1798 jsonpath bug sentry logging error detail
2 parents 0fe990e + 6742499 commit e18e4f0

File tree

4 files changed

+44
-30
lines changed

4 files changed

+44
-30
lines changed

request-api/src/crud.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import logging
12
from sqlalchemy import func
23
from sqlalchemy.orm import Session
4+
from sqlalchemy.exc import ProgrammingError, DataError
35

46
from pagination_model import PaginatedResult, PaginationParams
57
from request_model import models
68
from request_model import schemas
79

10+
logger = logging.getLogger(__name__)
11+
812

913
def get_request(db: Session, request_id: int):
1014
return db.query(models.Request).filter(models.Request.id == request_id).first()
@@ -26,12 +30,22 @@ def get_response_details(
2630
func.jsonb_path_match(models.ResponseDetails.detail, jsonpath)
2731
)
2832

29-
response_details = (
30-
base_query.offset(pagination_params.offset).limit(pagination_params.limit).all()
31-
)
33+
try:
34+
response_details = (
35+
base_query.offset(pagination_params.offset)
36+
.limit(pagination_params.limit)
37+
.all()
38+
)
39+
total_results = base_query.count()
40+
except (ProgrammingError, DataError) as e:
41+
# jsonb_path_math can raise errors if the jsonpath is invalid
42+
logger.warning("Invalid JSONPath expression '%s': %s", jsonpath, str(e))
43+
response_details = []
44+
total_results = 0
45+
3246
return PaginatedResult(
3347
params=pagination_params,
34-
total_results_available=base_query.count(),
48+
total_results_available=total_results,
3549
data=response_details,
3650
)
3751

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from unittest.mock import MagicMock
2+
3+
from sqlalchemy.exc import ProgrammingError
4+
5+
import crud
6+
7+
8+
def test_get_response_details_invalid_jsonpath_returns_empty(monkeypatch):
9+
base_query = MagicMock()
10+
base_query.join.return_value = base_query
11+
base_query.filter.return_value = base_query
12+
base_query.offset.return_value = base_query
13+
base_query.limit.return_value = base_query
14+
base_query.all.side_effect = ProgrammingError("bad jsonpath", None, None)
15+
base_query.count = MagicMock()
16+
17+
db = MagicMock()
18+
db.query.return_value = base_query
19+
20+
result = crud.get_response_details(db, request_id=1, jsonpath=";")
21+
22+
assert result.data == []
23+
assert result.total_results_available == 0
24+
base_query.count.assert_not_called()

request-processor/src/application/core/utils.py

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -240,51 +240,28 @@ def append_source(
240240

241241
def create_user_friendly_error_log(exception_detail):
242242
"""
243-
Creates a user-friendly error log from CustomException detail, as the message will be displayed to end users.
243+
Creates a user-friendly error message from CustomException detail, as the message may be displayed to end users.
244244
Keeps all info from exception_detail and adds user-friendly message.
245245
"""
246246
status_code = exception_detail.get("errCode")
247247
exception_type = exception_detail.get("exceptionType")
248248
content_type = exception_detail.get("contentType")
249249

250250
user_message = "An error occurred, please try again later."
251-
user_message_detail = None
252251

253252
if exception_type in ["SSLError", "SSLCertVerificationError"]:
254253
user_message = "SSL certificate verification failed"
255-
user_message_detail = [
256-
(
257-
"We couldn't verify the SSL certificate for that link. "
258-
"While it may open in some browsers, our security checks "
259-
"require a complete certificate chain."
260-
),
261-
(
262-
"Please make sure the site is served over HTTPS and its "
263-
"SSL certificate is correctly installed."
264-
),
265-
]
266254
elif content_type and "text/html" in content_type:
267255
user_message = (
268256
"The selected file must be a CSV, GeoJSON, GML or GeoPackage file"
269257
)
270-
user_message_detail = (
271-
"The URL returned a webpage (HTML) instead of a data file. "
272-
"Please provide a direct link to the data file "
273-
"(for example: .csv, .geojson, .gml or .gpkg)."
274-
)
275258
elif status_code == "403":
276259
user_message = "The URL must be accessible"
277-
user_message_detail = [
278-
"You must host the URL on a server which does not block access due to set permissions.",
279-
"Contact your IT team for support if you need it, referencing a 'HTTP status code 403' error.",
280-
]
281260
elif status_code == "404":
282261
user_message = "The URL does not exist. Check the URL you've entered is correct (HTTP 404 error)"
283262

284263
result = dict(exception_detail)
285264
result["message"] = user_message
286-
if user_message_detail is not None:
287-
result["user_message_detail"] = user_message_detail
288265

289266
return result
290267

request-processor/src/tasks.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def check_dataurl(request: Dict, directories=None):
173173
logger.info(f"Fetched resource: file_name={file_name}")
174174

175175
except CustomException as e:
176-
logger.error(f"URL FETCH Error during _fetch_resource: {e}")
177176
# Track in Sentry for monitoring (not as error)
178177
_capture_sentry_event(
179178
e.detail,
@@ -227,7 +226,7 @@ def check_dataurl(request: Dict, directories=None):
227226
)
228227
save_response_to_db(request_schema.id, error_log)
229228
else:
230-
logger.error("File could not be fetched from collector")
229+
logger.info("File could not be fetched from collector")
231230
error_log = create_generic_error_log(
232231
url=request_data.url,
233232
exception="UnknownCollectionError",

0 commit comments

Comments
 (0)