Skip to content

Commit fc0e4d3

Browse files
committed
VED-457: Refactor backend to include e-tag Header
1 parent 2f648bb commit fc0e4d3

File tree

7 files changed

+30
-26
lines changed

7 files changed

+30
-26
lines changed

backend/src/fhir_controller.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ def create_immunization(self, aws_event):
197197
return self.create_response(400, json.dumps(exp_error))
198198
else:
199199
location = f"{get_service_url()}/Immunization/{resource.id}"
200-
return self.create_response(201, None, {"Location": location})
200+
version = "1"
201+
return self.create_response(201, None, {"Location": location, "E-Tag": version})
201202
except ValidationError as error:
202203
return self.create_response(400, error.to_operation_outcome())
203204
except IdentifierDuplicationError as duplicate:
@@ -276,11 +277,12 @@ def update_immunization(self, aws_event):
276277
# Check vaccine type permissions on the existing record - end
277278

278279
existing_resource_version = int(existing_record["Version"])
280+
279281
try:
280282
# Validate if the imms resource to be updated is a logically deleted resource - start
281283
if existing_record["DeletedAt"] == True:
282284

283-
outcome, resource = self.fhir_service.reinstate_immunization(
285+
outcome, resource, updated_version = self.fhir_service.reinstate_immunization(
284286
imms_id, imms, existing_resource_version, imms_vax_type_perms, supplier_system)
285287
# Validate if the imms resource to be updated is a logically deleted resource-end
286288
else:
@@ -338,7 +340,7 @@ def update_immunization(self, aws_event):
338340
supplier_system
339341
)
340342
else:
341-
outcome, resource = self.fhir_service.update_immunization(
343+
outcome, resource, updated_version = self.fhir_service.update_immunization(
342344
imms_id,
343345
imms,
344346
existing_resource_version,
@@ -358,7 +360,7 @@ def update_immunization(self, aws_event):
358360
)
359361
return self.create_response(400, json.dumps(exp_error))
360362
if outcome == UpdateOutcome.UPDATE:
361-
return self.create_response(200)
363+
return self.create_response(200, {"E-Tag": updated_version}) #include e-tag here, is it not included in the response resource
362364
except ValidationError as error:
363365
return self.create_response(400, error.to_operation_outcome())
364366
except IdentifierDuplicationError as duplicate:
@@ -667,5 +669,5 @@ def create_response(status_code, body=None, headers=None):
667669
def _identify_supplier_system(aws_event):
668670
supplier_system = aws_event["headers"]["SupplierSystem"]
669671
if not supplier_system:
670-
return self.create_response(403, unauthorized.to_operation_outcome())
672+
raise UnauthorizedError("SupplierSystem header is missing")
671673
return supplier_system

backend/src/fhir_repository.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ def _perform_dynamo_update(
301301
update_reinstated: bool,
302302
) -> dict:
303303
try:
304+
updated_version = existing_resource_version + 1
304305
condition_expression = Attr("PK").eq(attr.pk) & (
305306
Attr("DeletedAt").exists()
306307
if deleted_at_required
@@ -313,7 +314,7 @@ def _perform_dynamo_update(
313314
":patient_sk": attr.patient_sk,
314315
":imms_resource_val": json.dumps(attr.resource, use_decimal=True),
315316
":operation": "UPDATE",
316-
":version": existing_resource_version + 1,
317+
":version": updated_version,
317318
":supplier_system": supplier_system,
318319
":respawn": "reinstated",
319320
}
@@ -324,7 +325,7 @@ def _perform_dynamo_update(
324325
":patient_sk": attr.patient_sk,
325326
":imms_resource_val": json.dumps(attr.resource, use_decimal=True),
326327
":operation": "UPDATE",
327-
":version": existing_resource_version + 1,
328+
":version": updated_version,
328329
":supplier_system": supplier_system,
329330
}
330331

@@ -338,7 +339,7 @@ def _perform_dynamo_update(
338339
ReturnValues="ALL_NEW",
339340
ConditionExpression=condition_expression,
340341
)
341-
return self._handle_dynamo_response(response)
342+
return self._handle_dynamo_response(response), updated_version
342343
except botocore.exceptions.ClientError as error:
343344
# Either resource didn't exist or it has already been deleted. See ConditionExpression in the request
344345
if error.response["Error"]["Code"] == "ConditionalCheckFailedException":

backend/src/fhir_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def update_immunization(
142142
patient = self._validate_patient(immunization)
143143
if "diagnostics" in patient:
144144
return (None, patient)
145-
imms = self.immunization_repo.update_immunization(
145+
imms, updated_version = self.immunization_repo.update_immunization(
146146
imms_id,
147147
immunization,
148148
patient,
@@ -151,7 +151,7 @@ def update_immunization(
151151
supplier_system
152152
)
153153

154-
return UpdateOutcome.UPDATE, Immunization.parse_obj(imms)
154+
return UpdateOutcome.UPDATE, Immunization.parse_obj(imms), updated_version
155155

156156
def reinstate_immunization(
157157
self,

backend/tests/test_fhir_controller.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ def test_update_immunization(self,mock_get_permissions):
10511051
"body": imms,
10521052
"pathParameters": {"id": imms_id},
10531053
}
1054-
self.service.update_immunization.return_value = UpdateOutcome.UPDATE, "value doesn't matter"
1054+
self.service.update_immunization.return_value = UpdateOutcome.UPDATE, "value doesn't matter", 2
10551055
self.service.get_immunization_by_id_all.return_value = {
10561056
"resource": "new_value",
10571057
"Version": 1,
@@ -1066,7 +1066,7 @@ def test_update_immunization(self,mock_get_permissions):
10661066
)
10671067
mock_get_permissions.assert_called_once_with("Test")
10681068
self.assertEqual(response["statusCode"], 200)
1069-
self.assertTrue("body" not in response)
1069+
self.assertEqual(json.loads(response["body"]), {"E-Tag": 2})
10701070

10711071
@patch("fhir_controller.get_supplier_permissions")
10721072
def test_update_immunization_etag_missing(self, mock_get_supplier_permissions):
@@ -1247,7 +1247,7 @@ def test_update_deletedat_immunization_with_version(self, mock_get_supplier_perm
12471247
"body": imms,
12481248
"pathParameters": {"id": imms_id},
12491249
}
1250-
self.service.reinstate_immunization.return_value = UpdateOutcome.UPDATE, "value doesn't matter"
1250+
self.service.reinstate_immunization.return_value = UpdateOutcome.UPDATE, {}, 2
12511251
self.service.get_immunization_by_id_all.return_value = {
12521252
"resource": "new_value",
12531253
"Version": 1,
@@ -1261,7 +1261,7 @@ def test_update_deletedat_immunization_with_version(self, mock_get_supplier_perm
12611261
imms_id, json.loads(imms), 1, ["COVID19.CRUDS"], "Test"
12621262
)
12631263
self.assertEqual(response["statusCode"], 200)
1264-
self.assertTrue("body" not in response)
1264+
self.assertEqual(json.loads(response["body"]), {"E-Tag": 2})
12651265

12661266
@patch("fhir_controller.get_supplier_permissions")
12671267
def test_update_deletedat_immunization_without_version(self, mock_get_supplier_permissions):
@@ -1271,11 +1271,11 @@ def test_update_deletedat_immunization_without_version(self, mock_get_supplier_p
12711271
imms = '{"id": "valid-id"}'
12721272
imms_id = "valid-id"
12731273
aws_event = {
1274-
"headers": {"SupplierSystem": "Test"},
1274+
"headers": {"SupplierSystem": "Test", "E-tag":1},
12751275
"body": imms,
12761276
"pathParameters": {"id": imms_id},
12771277
}
1278-
self.service.reinstate_immunization.return_value = UpdateOutcome.UPDATE, "value doesn't matter"
1278+
self.service.reinstate_immunization.return_value = UpdateOutcome.UPDATE, {}, 2
12791279
self.service.get_immunization_by_id_all.return_value = {
12801280
"resource": "new_value",
12811281
"Version": 1,
@@ -1290,7 +1290,7 @@ def test_update_deletedat_immunization_without_version(self, mock_get_supplier_p
12901290
)
12911291
mock_get_supplier_permissions.assert_called_once_with("Test")
12921292
self.assertEqual(response["statusCode"], 200)
1293-
self.assertTrue("body" not in response)
1293+
self.assertEqual(json.loads(response["body"]), {"E-Tag": 2})
12941294

12951295
@patch("fhir_controller.get_supplier_permissions")
12961296
def test_update_record_exists(self, mock_get_supplier_permissions):
@@ -1376,7 +1376,7 @@ def test_validation_superseded_number_to_give_bad_request_for_update_immunizatio
13761376
update_result = {
13771377
"diagnostics": "Validation errors: contained[?(@.resourceType=='Patient')].identifier[0].value does not exists"
13781378
}
1379-
self.service.update_immunization.return_value = None, update_result
1379+
self.service.update_immunization.return_value = None, update_result, 2
13801380
req_imms = '{"id": "valid-id"}'
13811381
path_id = "valid-id"
13821382
aws_event = {
@@ -1396,7 +1396,7 @@ def test_validation_superseded_number_to_give_bad_request_for_update_immunizatio
13961396

13971397
self.assertEqual(response["statusCode"], 400)
13981398
body = json.loads(response["body"])
1399-
self.assertEqual(body["resourceType"], "OperationOutcome")
1399+
self.assertEqual(body["resourceType"], "OperationOutcome", 2)
14001400

14011401
@patch("fhir_controller.get_supplier_permissions")
14021402
def test_validation_identifier_to_give_bad_request_for_update_immunization(self, mock_get_supplier_permissions):

backend/tests/test_fhir_repository.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ def test_update1(self):
405405
mock_time.return_value = now_epoch
406406
# When
407407

408-
act_resource = self.repository.update_immunization(
408+
act_resource, updated_version = self.repository.update_immunization(
409409
imms_id, imms, self.patient, 1, ["COVID19.CRUD"], "Test"
410410
)
411411

@@ -773,10 +773,11 @@ def run_update_immunization_test(self, imms_id, imms, resource, updated_dose_qua
773773
now_epoch = 123456
774774
with patch("time.time") as mock_time:
775775
mock_time.return_value = now_epoch
776-
act_resource = self.repository.update_immunization(
776+
act_resource, act_version = self.repository.update_immunization(
777777
imms_id, imms, self.patient, 1, ["COVID19.CRUD"], "Test"
778778
)
779779
self.assertDictEqual(act_resource, resource)
780+
self.assertEqual(act_version, 2)
780781

781782
update_exp = (
782783
"SET UpdatedAt = :timestamp, PatientPK = :patient_pk, "

backend/tests/test_fhir_service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ def test_update_immunization(self):
492492
"""it should update Immunization and validate NHS number"""
493493
imms_id = "an-id"
494494
self.imms_repo.update_immunization.return_value = (
495-
create_covid_19_immunization_dict(imms_id)
495+
create_covid_19_immunization_dict(imms_id), 2
496496
)
497497
pds_patient = {"identifier": [{"system": "https://fhir.nhs.uk/Id/nhs-number", "value": "9990548609"}]}
498498
self.fhir_service.pds_service.get_patient_details.return_value = pds_patient
@@ -501,7 +501,7 @@ def test_update_immunization(self):
501501
req_imms = create_covid_19_immunization_dict(imms_id, nhs_number)
502502

503503
# When
504-
outcome, _ = self.fhir_service.update_immunization(imms_id, req_imms, 1, ["COVID19.CRUD"], "Test")
504+
outcome, _, _ = self.fhir_service.update_immunization(imms_id, req_imms, 1, ["COVID19.CRUD"], "Test")
505505

506506
# Then
507507
self.assertEqual(outcome, UpdateOutcome.UPDATE)
@@ -511,7 +511,7 @@ def test_update_immunization(self):
511511
def test_id_not_present(self):
512512
"""it should populate id in the message if it is not present"""
513513
req_imms_id = "an-id"
514-
self.imms_repo.update_immunization.return_value = create_covid_19_immunization_dict(req_imms_id)
514+
self.imms_repo.update_immunization.return_value = create_covid_19_immunization_dict(req_imms_id), 2
515515
self.fhir_service.pds_service.get_patient_details.return_value = {"identifier": [{"system": "https://fhir.nhs.uk/Id/nhs-number", "value": "9990548609"}]}
516516

517517
req_imms = create_covid_19_immunization_dict("we-will-remove-this-id")

backend/tests/utils/test_utils_for_batch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ class MockFhirImmsResources:
148148
"coding": [
149149
{
150150
"system": "http://snomed.info/sct",
151-
"code": "55735004",
152-
"display": "Respiratory syncytial virus infection (disorder)",
151+
"code": "398102009",
152+
"display": "Acute poliomyelitis",
153153
}
154154
]
155155
}

0 commit comments

Comments
 (0)