Skip to content

Commit 80fd185

Browse files
authored
Merge pull request #371 from NHSDigital/VED-73-recover-my-changes
recover reverted changes
2 parents 939b42a + af47e45 commit 80fd185

13 files changed

+82
-91
lines changed

backend/src/fhir_service.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,27 +79,18 @@ def get_immunization_by_identifier(
7979

8080
def get_immunization_by_id(self, imms_id: str, imms_vax_type_perms: str) -> Optional[dict]:
8181
"""
82-
Get an Immunization by its ID. Return None if not found. If the patient doesn't have an NHS number,
82+
Get an Immunization by its ID. Return None if it is not found. If the patient doesn't have an NHS number,
8383
return the Immunization without calling PDS or checking S flag.
8484
"""
8585
if not (imms_resp := self.immunization_repo.get_immunization_by_id(imms_id, imms_vax_type_perms)):
8686
return None
8787

88-
# Remove fields rom the imms resource which are not to be returned for read
89-
imms_filtered_for_read = Filter.read(imms_resp.get("Resource", {}))
90-
91-
# Handle s-flag filtering, where applicable
92-
if not (nhs_number := obtain_field_value(imms_filtered_for_read, FieldNames.patient_identifier_value)):
93-
imms_filtered_for_read_and_s_flag = imms_filtered_for_read
94-
else:
95-
if patient := self.pds_service.get_patient_details(nhs_number):
96-
imms_filtered_for_read_and_s_flag = handle_s_flag(imms_filtered_for_read, patient)
97-
else:
98-
raise UnhandledResponseError("unable to validate NHS number with downstream service")
88+
# Returns the Immunisation full resource with no obfuscation
89+
resource = imms_resp.get("Resource", {})
9990

10091
return {
10192
"Version": imms_resp.get("Version", ""),
102-
"Resource": Immunization.parse_obj(imms_filtered_for_read_and_s_flag),
93+
"Resource": Immunization.parse_obj(resource),
10394
}
10495

10596
def get_immunization_by_id_all(self, imms_id: str, imms: dict) -> Optional[dict]:

backend/src/filter.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,6 @@ def add_use_to_identifier(imms: dict) -> dict:
9494

9595
class Filter:
9696
"""Functions for filtering a FHIR Immunization Resource"""
97-
98-
@staticmethod
99-
def read(imms: dict) -> dict:
100-
"""Apply filtering for READ request"""
101-
imms.pop("identifier")
102-
return imms
103-
10497
@staticmethod
10598
def search(imms: dict, patient_full_url: str, bundle_patient: dict = None) -> dict:
10699
"""Apply filtering for an individual FHIR Immunization Resource as part of SEARCH request"""

backend/tests/sample_data/completed_covid19_immunization_event_filtered_for_read.json renamed to backend/tests/sample_data/completed_covid19_immunization_event_for_read.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
]
4949
}
5050
}
51+
],"identifier": [
52+
{
53+
"system": "https://supplierABC/identifiers/vacc",
54+
"value": "ACME-vacc123456"
55+
}
5156
],
5257
"status": "completed",
5358
"vaccineCode": {

backend/tests/test_fhir_service.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -187,40 +187,24 @@ def test_immunization_not_found(self):
187187

188188
def test_get_immunization_by_id_patient_not_restricted(self):
189189
"""
190-
Test that get_immunization_by_id returns a FHIR Immunization Resource which has been filtered for read,
191-
but not for s-flag, when patient is not restricted
190+
Test that get_immunization_by_id returns a FHIR Immunization Resource which has not been filtered for read,
191+
but also dropped for s-flag, when patient is not restricted
192192
"""
193193
imms_id = "non_restricted_id"
194194

195195
immunization_data = load_json_data("completed_covid19_immunization_event.json")
196196
self.imms_repo.get_immunization_by_id.return_value = {"Resource": immunization_data}
197197
self.fhir_service.pds_service.get_patient_details.return_value = {"meta": {"security": [{"code": "U"}]}}
198198

199-
expected_imms = load_json_data("completed_covid19_immunization_event_filtered_for_read.json")
199+
expected_imms = load_json_data("completed_covid19_immunization_event_for_read.json")
200200
expected_output = Immunization.parse_obj(expected_imms)
201201

202202
# When
203203
actual_output = self.fhir_service.get_immunization_by_id(imms_id, "COVID19:read")
204204

205205
# Then
206206
self.assertEqual(actual_output["Resource"], expected_output)
207-
208-
def test_get_immunization_by_id_patient_restricted(self):
209-
"""it should return a filtered Immunization when patient is restricted"""
210-
imms_id = "restricted_id"
211-
immunization_data = load_json_data("completed_covid19_immunization_event.json")
212-
filtered_immunization = load_json_data("completed_covid19_immunization_event_filtered_for_s_flag_and_read.json")
213-
self.imms_repo.get_immunization_by_id.return_value = {"Resource": immunization_data}
214-
patient_data = {"meta": {"security": [{"code": "R"}]}}
215-
self.fhir_service.pds_service.get_patient_details.return_value = patient_data
216-
217-
# When
218-
resp_imms = self.fhir_service.get_immunization_by_id(imms_id, "COVID19:read")
219-
act_res = resp_imms["Resource"]
220-
filtered_immunization_res = Immunization.parse_obj(filtered_immunization)
221-
# Then
222-
self.assertEqual(act_res, filtered_immunization_res)
223-
207+
224208
def test_pre_validation_failed(self):
225209
"""it should throw exception if Immunization is not valid"""
226210
imms_id = "an-id"

backend/tests/test_filter.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ def test_replace_address_postal_codes(self):
9494
input_imms = load_json_data("completed_covid19_immunization_event.json")
9595
expected_output = deepcopy(input_imms)
9696
expected_output["contained"][1]["address"][0]["postalCode"] = "ZZ99 3CZ"
97-
9897
self.assertEqual(replace_address_postal_codes(input_imms), expected_output)
9998

10099
def test_replace_organization_values(self):
@@ -145,12 +144,6 @@ def test_replace_organization_values(self):
145144
del expected_output_data["performer"][1]["actor"]["identifier"]
146145
self.assertEqual(replace_organization_values(input_imms_data), expected_output_data)
147146

148-
def test_filter_read(self):
149-
"""Tests to ensure Filter.read appropriately filters a FHIR Immunization Resource"""
150-
unfiltered_imms = deepcopy(self.covid_19_immunization_event)
151-
expected_output = load_json_data("completed_covid19_immunization_event_filtered_for_read.json")
152-
self.assertEqual(Filter.read(unfiltered_imms), expected_output)
153-
154147
def test_filter_search(self):
155148
"""Tests to ensure Filter.search appropriately filters a FHIR Immunization Resource"""
156149
bundle_patient = deepcopy(self.bundle_patient_resource)

e2e/test_get_immunization.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from decimal import Decimal
2+
import uuid
23

34
from utils.base_test import ImmunizationBaseTest
45
from utils.immunisation_api import parse_location
@@ -12,18 +13,26 @@ def test_get_imms(self):
1213
"""it should get a FHIR Immunization resource"""
1314
for imms_api in self.imms_apis:
1415
with self.subTest(imms_api):
16+
# Create one shared UUID per immunization (covid & rsv)
17+
covid_uuid = str(uuid.uuid4())
18+
rsv_uuid = str(uuid.uuid4())
1519
# Given
1620
immunizations = [
1721
{
18-
"data": generate_imms_resource(),
22+
"data": generate_imms_resource(imms_identifier_value=covid_uuid),
1923
"expected": generate_filtered_imms_resource(
20-
crud_operation_to_filter_for=EndpointOperationNames.READ)
24+
crud_operation_to_filter_for=EndpointOperationNames.READ,
25+
imms_identifier_value=covid_uuid)
2126
},
2227
{
23-
"data": generate_imms_resource(sample_data_file_name="completed_rsv_immunization_event"),
28+
"data": generate_imms_resource(
29+
sample_data_file_name="completed_rsv_immunization_event",
30+
vaccine_type=VaccineTypes.rsv,
31+
imms_identifier_value=rsv_uuid),
2432
"expected": generate_filtered_imms_resource(
2533
crud_operation_to_filter_for=EndpointOperationNames.READ,
26-
vaccine_type=VaccineTypes.rsv
34+
vaccine_type=VaccineTypes.rsv,
35+
imms_identifier_value=rsv_uuid
2736
)
2837
}
2938
]
@@ -40,7 +49,6 @@ def test_get_imms(self):
4049
# When - Retrieve and validate each immunization by ID
4150
for immunization in immunizations:
4251
response = imms_api.get_immunization_by_id(immunization["id"])
43-
4452
# Then
4553
self.assertEqual(response.status_code, 200)
4654
self.assertEqual(response.json()["id"], immunization["id"])

e2e/test_s_flag_immunization.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List
22
from decimal import Decimal
3+
import uuid
34

45
from utils.base_test import ImmunizationBaseTest
56
from utils.constants import valid_nhs_number1, valid_nhs_number_with_s_flag
@@ -11,43 +12,37 @@
1112
class SFlagBaseTest(ImmunizationBaseTest):
1213
"""Parent class with helper for storing immunisation events in the IEDS"""
1314

14-
def store_imms(self, imms_api: ImmunisationApi, patient_is_restricted: bool) -> dict:
15+
def store_imms(self, imms_api: ImmunisationApi, patient_is_restricted: bool, imms_identifier_value=None) -> dict:
1516
"""
1617
Store an immunisation event in the IEDS using valid_nhs_number_with_s_flag if patient is restricted, or
1718
valid_nhs_number_1 otherwise
1819
"""
1920
nhs_number = valid_nhs_number_with_s_flag if patient_is_restricted else valid_nhs_number1
20-
imms = generate_imms_resource(nhs_number=nhs_number, vaccine_type=VaccineTypes.covid_19)
21+
imms = generate_imms_resource(
22+
nhs_number=nhs_number, vaccine_type=VaccineTypes.covid_19,
23+
imms_identifier_value=imms_identifier_value)
2124
return self.create_immunization_resource(imms_api, imms)
2225

2326

2427
class TestGetSFlagImmunization(SFlagBaseTest):
25-
"""Test that sensitive data is filtered out for a READ if and only if the patient is s-flagged"""
26-
27-
def test_get_s_flagged_imms(self):
28-
"""Test that sensitive data is filtered out for a READ when the patient is s-flagged"""
29-
for imms_api in self.imms_apis:
30-
with self.subTest(imms_api):
31-
imms_id = self.store_imms(imms_api, patient_is_restricted=True)
32-
read_imms = imms_api.get_immunization_by_id(imms_id).json(parse_float=Decimal)
33-
expected_response = generate_filtered_imms_resource(
34-
crud_operation_to_filter_for="READ",
35-
filter_for_s_flag=True,
36-
nhs_number=valid_nhs_number_with_s_flag,
37-
)
38-
expected_response["id"] = read_imms["id"]
39-
self.assertEqual(read_imms, expected_response)
40-
4128
def test_get_not_s_flagged_imms(self):
4229
"""Test that sensitive data is not filtered out for a READ when the patient is not s-flagged"""
4330
for imms_api in self.imms_apis:
4431
with self.subTest(imms_api):
45-
imms = self.store_imms(imms_api, patient_is_restricted=False)
32+
33+
shared_uuid = str(uuid.uuid4())
34+
35+
imms = self.store_imms(
36+
imms_api,
37+
patient_is_restricted=False,
38+
imms_identifier_value=shared_uuid)
39+
4640
read_imms = imms_api.get_immunization_by_id(imms).json(parse_float=Decimal)
4741
expected_response = generate_filtered_imms_resource(
4842
crud_operation_to_filter_for="READ",
4943
filter_for_s_flag=False,
5044
nhs_number=valid_nhs_number1,
45+
imms_identifier_value=shared_uuid
5146
)
5247
expected_response["id"] = read_imms["id"]
5348
self.assertEqual(read_imms, expected_response)

e2e/test_search_immunization.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,17 @@ def test_search_immunization_parameter_smoke_tests(self):
162162
time_1 = "2024-01-30T13:28:17.271+00:00"
163163
time_2 = "2024-02-01T13:28:17.271+00:00"
164164
stored_records = [
165-
generate_imms_resource(valid_nhs_number1, VaccineTypes.mmr),
166-
generate_imms_resource(valid_nhs_number1, VaccineTypes.flu),
167-
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19),
168-
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19, time_1),
169-
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19, time_2),
170-
generate_imms_resource(valid_nhs_number2, VaccineTypes.flu),
171-
generate_imms_resource(valid_nhs_number2, VaccineTypes.covid_19),
165+
generate_imms_resource(valid_nhs_number1, VaccineTypes.mmr, imms_identifier_value=str(uuid.uuid4())),
166+
generate_imms_resource(valid_nhs_number1, VaccineTypes.flu, imms_identifier_value=str(uuid.uuid4())),
167+
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19, imms_identifier_value=str(uuid.uuid4())),
168+
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19,
169+
occurrence_date_time=time_1,
170+
imms_identifier_value=str(uuid.uuid4())),
171+
generate_imms_resource(valid_nhs_number1, VaccineTypes.covid_19,
172+
occurrence_date_time=time_2,
173+
imms_identifier_value=str(uuid.uuid4())),
174+
generate_imms_resource(valid_nhs_number2, VaccineTypes.flu, imms_identifier_value=str(uuid.uuid4())),
175+
generate_imms_resource(valid_nhs_number2, VaccineTypes.covid_19, imms_identifier_value=str(uuid.uuid4())),
172176
]
173177

174178
created_resource_ids = list(self.store_records(*stored_records))
@@ -308,6 +312,13 @@ class SearchTestParams(NamedTuple):
308312

309313
result_ids = [result["resource"]["id"] for result in results["entry"]]
310314
created_and_returned_ids = list(set(result_ids) & set(created_resource_ids))
315+
print("\n Search Test Debug Info:")
316+
print("Search method:", search.method)
317+
print("Search query string:", search.query_string)
318+
print("Expected indexes:", search.expected_indexes)
319+
print("Expected IDs:", [created_resource_ids[i] for i in search.expected_indexes])
320+
print("Actual returned IDs:", result_ids)
321+
print("Matched IDs:", created_and_returned_ids)
311322
assert len(created_and_returned_ids) == len(search.expected_indexes)
312323
for expected_index in search.expected_indexes:
313324
assert created_resource_ids[expected_index] in result_ids

e2e/utils/resource.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@ def load_example(path: str) -> dict:
2222
def generate_imms_resource(
2323
nhs_number=valid_nhs_number1,
2424
vaccine_type=VaccineTypes.covid_19,
25+
imms_identifier_value: str = None,
2526
occurrence_date_time: str = None,
2627
sample_data_file_name: str = "completed_[vaccine_type]_immunization_event",
2728
) -> dict:
2829
"""
2930
Creates a FHIR Immunization Resource dictionary, which includes an id, using the sample data for the given
3031
vaccine type as a base, and updates the id, nhs_number and occurrence_date_time as required.
31-
The unique_identifier is also updated to ensure uniqueness.
32+
The unique_identifier is also updated to ensure uniqueness...
3233
"""
3334
# Load the data
3435
sample_data_file_name = sample_data_file_name.replace("[vaccine_type]", vaccine_type.lower())
3536
imms = deepcopy(load_example(f"Immunization/{sample_data_file_name}.json"))
3637

37-
# Amend data fields as appropriate
38-
imms["identifier"][0]["value"] = str(uuid.uuid4())
38+
# Apply identifier directly
39+
imms["identifier"][0]["value"] = imms_identifier_value or str(uuid.uuid4())
3940

4041
if nhs_number is not None:
4142
imms["contained"][1]["identifier"][0]["value"] = nhs_number
@@ -49,8 +50,8 @@ def generate_imms_resource(
4950
def generate_filtered_imms_resource(
5051
crud_operation_to_filter_for: Literal["READ", "SEARCH", ""] = "",
5152
filter_for_s_flag: bool = False,
52-
imms_identifier_value: str = None,
5353
nhs_number=valid_nhs_number1,
54+
imms_identifier_value: str = None,
5455
vaccine_type=VaccineTypes.covid_19,
5556
occurrence_date_time: str = None,
5657
) -> dict:
@@ -72,10 +73,8 @@ def generate_filtered_imms_resource(
7273
+ f"_filtered_for_{crud_operation_to_filter_for.lower()}{s_flag_string}"
7374
)
7475
imms = deepcopy(load_example(f"{file_name}.json"))
75-
76-
# Amend values as required
77-
if imms_identifier_value:
78-
imms["identifier"][0]["value"] = imms_identifier_value
76+
# Apply identifier directly
77+
imms["identifier"][0]["value"] = imms_identifier_value or str(uuid.uuid4())
7978

8079
# Note that NHS number is found in a different place on a search return
8180
if crud_operation_to_filter_for == "SEARCH":

specification/components/examples/Immunization/completed_covid19_immunization_event.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"identifier": [
5353
{
5454
"system": "https://supplierABC/identifiers/vacc",
55-
"value": "ACME-vacc123456"
55+
"value": "ACME-vacc123456789"
5656
}
5757
],
5858
"status": "completed",
@@ -149,4 +149,4 @@
149149
"doseNumberPositiveInt": 1
150150
}
151151
]
152-
}
152+
}

0 commit comments

Comments
 (0)