Skip to content

Commit 36942c8

Browse files
[PRMP-1082] move validation into model
1 parent 4aff1fd commit 36942c8

File tree

5 files changed

+35
-66
lines changed

5 files changed

+35
-66
lines changed

lambdas/handlers/post_document_review_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from utils.decorators.ensure_env_var import ensure_environment_variables
1111
from utils.decorators.handle_lambda_exceptions import handle_lambda_exceptions
1212
from utils.decorators.set_audit_arg import set_request_context_for_logging
13-
from utils.exceptions import InvalidNhsNumberException
13+
from utils.exceptions import InvalidNhsNumberException, DocumentReviewException
1414
from utils.lambda_exceptions import DocumentReviewLambdaException
1515
from utils.lambda_response import ApiGatewayResponse
1616

@@ -55,7 +55,7 @@ def validate_event_body(body):
5555
event_body = DocumentReviewUploadEvent.model_validate_json(body)
5656

5757
return event_body
58-
except (ValidationError, InvalidNhsNumberException) as e:
58+
except (ValidationError, InvalidNhsNumberException, DocumentReviewException) as e:
5959
logger.error(e)
6060
raise DocumentReviewLambdaException(
6161
400, LambdaError.DocumentReviewUploadInvalidRequest

lambdas/models/document_review.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import uuid
22
from datetime import datetime, timezone
3+
from typing import Self
34

45
from enums.document_review_status import DocumentReviewStatus
56
from enums.metadata_field_names import DocumentReferenceMetadataFields
7+
from enums.upload_forbidden_file_extensions import is_file_type_allowed
68
from enums.snomed_codes import SnomedCodes
7-
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
9+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator, ValidationError
810
from pydantic.alias_generators import to_camel, to_pascal
9-
from utils.exceptions import InvalidNhsNumberException
11+
from utils.exceptions import InvalidNhsNumberException, ConfigNotFoundException, DocumentReviewException
12+
from utils import upload_file_configs
1013
from utils.utilities import validate_nhs_number
1114

1215

@@ -155,3 +158,16 @@ def check_snomed_code(cls, value) -> SnomedCodes | None:
155158
def verify_nhs_number(cls, value) -> str | None:
156159
if validate_nhs_number(value):
157160
return value
161+
162+
@model_validator(mode="after")
163+
def validate_file_extension(self) -> Self:
164+
try:
165+
accepted_file_types = upload_file_configs.get_config_by_snomed_code(self.snomed_code.code).accepted_file_types
166+
167+
for file in self.documents:
168+
if not is_file_type_allowed(file, accepted_file_types):
169+
raise DocumentReviewException("Invalid file extension.")
170+
return self
171+
except ConfigNotFoundException:
172+
raise DocumentReviewException("Unable to find file configuration.")
173+

lambdas/services/post_document_review_service.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from enums.document_review_status import DocumentReviewReason, DocumentReviewStatus
77
from enums.lambda_error import LambdaError
88
from enums.patient_ods_inactive_status import PatientOdsInactiveStatus
9-
from enums.upload_forbidden_file_extensions import is_file_type_allowed
109
from models.document_review import (
1110
DocumentReviewFileDetails,
1211
DocumentReviewUploadEvent,
@@ -15,10 +14,8 @@
1514
from pydantic import ValidationError
1615
from services.base.s3_service import S3Service
1716
from services.document_upload_review_service import DocumentUploadReviewService
18-
from utils import upload_file_configs
1917
from utils.audit_logging_setup import LoggingService
2018
from utils.exceptions import (
21-
ConfigNotFoundException,
2219
DocumentReviewException,
2320
OdsErrorException,
2421
PatientNotFoundException,
@@ -54,8 +51,6 @@ def process_event(self, event: DocumentReviewUploadEvent) -> dict:
5451
403, LambdaError.DocumentReviewUploadForbidden
5552
)
5653

57-
self.validate_document_file_type(event)
58-
5954
document_review_reference = self.create_review_reference_from_event(
6055
event=event, author=author, patient_details=patient_details
6156
)
@@ -89,26 +84,6 @@ def process_event(self, event: DocumentReviewUploadEvent) -> dict:
8984
except ClientError:
9085
raise DocumentReviewLambdaException(500, LambdaError.DocumentReviewDB)
9186

92-
def validate_document_file_type(self, event: DocumentReviewUploadEvent) -> None:
93-
snomed_code = event.snomed_code.code
94-
accepted_file_types = self.get_accepted_file_types(
95-
snomed_code, upload_file_configs
96-
)
97-
98-
if not is_file_type_allowed(event.documents[0], accepted_file_types):
99-
logger.info("File type is not supported.")
100-
raise DocumentReviewLambdaException(
101-
400, LambdaError.DocumentReviewUnsupportedFileType
102-
)
103-
104-
def get_accepted_file_types(self, snomed_code, upload_file_configs):
105-
try:
106-
return upload_file_configs.get_config_by_snomed_code(
107-
snomed_code
108-
).accepted_file_types
109-
except ConfigNotFoundException:
110-
logger.error(f"Unable to find config for snomed code: {snomed_code}")
111-
raise DocumentReviewLambdaException(400, LambdaError.DocRefInvalidType)
11287

11388
def create_response(
11489
self, document_review_reference: DocumentUploadReviewReference

lambdas/tests/unit/handlers/test_post_document_review_handler.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
"documents": [],
3939
}
4040

41+
INVALID_EVENT_INVALID_FILE_EXTENSION = {
42+
"nhsNumber": TEST_NHS_NUMBER,
43+
"snomedCode": SnomedCodes.LLOYD_GEORGE.value.code,
44+
"documents": ["testFile.job"],
45+
}
46+
4147
TEST_PRESIGNED_URL_1 = "https://s3.amazonaws.com/presigned1?signature=abc123"
4248

4349

@@ -222,6 +228,14 @@ def test_validate_event_body_throws_error_unsupported_snomed_code(invalid_event)
222228
assert e.value.err_code == "UDR_4003"
223229

224230

231+
def test_validate_event_body_throws_error_unsupported_file_type(invalid_event):
232+
invalid_event["body"] = INVALID_EVENT_UNSUPPORTED_SNOMED_CODE
233+
with pytest.raises(DocumentReviewLambdaException) as e:
234+
validate_event_body(invalid_event["body"])
235+
assert e.value.status_code == 400
236+
assert e.value.err_code == "UDR_4003"
237+
238+
225239
def test_lambda_handler_calls_service_with_validated_event(
226240
mock_service, context, mock_upload_document_iteration_3_enabled, valid_event
227241
):

lambdas/tests/unit/services/test_post_document_review_service.py

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -293,40 +293,4 @@ def test_create_response(mock_service):
293293
nhs_number=TEST_NHS_NUMBER,
294294
)
295295
)
296-
assert actual == expected
297-
298-
299-
@freeze_time("2024-01-01 12:00:00")
300-
def test_validate_file_type_with_invalid_file_type(mock_extract_ods, mock_service):
301-
mock_extract_ods.return_value = TEST_CURRENT_GP_ODS
302-
mock_service.pds_service.fetch_patient_details.return_value = (
303-
EXPECTED_PARSED_PATIENT_BASE_CASE
304-
)
305-
invalid_event = deepcopy(VALID_EVENT)
306-
invalid_event.documents = ["testFile.exe"]
307-
308-
with pytest.raises(DocumentReviewLambdaException) as e:
309-
mock_service.process_event(invalid_event)
310-
311-
assert e.value.status_code == 400
312-
assert e.value.err_code == "DRV_4006"
313-
314-
mock_service.review_document_service.create_dynamo_entry.assert_not_called()
315-
316-
317-
@freeze_time("2024-01-01 12:00:00")
318-
def test_validate_file_type_with_invalid_snomed_code(mock_extract_ods, mock_service):
319-
mock_extract_ods.return_value = TEST_CURRENT_GP_ODS
320-
mock_service.pds_service.fetch_patient_details.return_value = (
321-
EXPECTED_PARSED_PATIENT_BASE_CASE
322-
)
323-
invalid_event = deepcopy(VALID_EVENT)
324-
invalid_event.snomed_code.code = "INVALID_SNOMED_CODE"
325-
326-
with pytest.raises(DocumentReviewLambdaException) as e:
327-
mock_service.process_event(invalid_event)
328-
329-
assert e.value.status_code == 400
330-
assert e.value.err_code == "DR_4007"
331-
332-
mock_service.review_document_service.create_dynamo_entry.assert_not_called()
296+
assert actual == expected

0 commit comments

Comments
 (0)