Skip to content

Commit aacdc2e

Browse files
Akol125RobertNovac
authored andcommitted
parent 0719a0d
author Akol125 <[email protected]> 1741732167 +0000 committer Robert Novac <[email protected]> 1742314388 +0000 READ request- drop obfuscation for s-flag patient
1 parent 0719a0d commit aacdc2e

File tree

63 files changed

+6357
-267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+6357
-267
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ jobs:
88
if: github.ref == 'refs/heads/master'
99
steps:
1010
- name: Checkout
11-
uses: actions/checkout@v2
11+
uses: actions/checkout@v4
1212
with:
1313
fetch-depth: 0 # This causes all history to be fetched, which is required for calculate-version to function
1414

1515
- name: Install Python 3.9
16-
uses: actions/setup-python@v1
16+
uses: actions/setup-python@v5
1717
with:
1818
python-version: 3.9
1919

@@ -40,5 +40,4 @@ jobs:
4040
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4141
with:
4242
tag_name: ${{ env.SPEC_VERSION }}
43-
release_name: ${{ env.SPEC_VERSION }}
44-
43+
release_name: ${{ env.SPEC_VERSION }}

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ build-proxy:
3838
scripts/build_proxy.sh
3939

4040
#Files to loop over in release
41-
_dist_include="pytest.ini poetry.lock poetry.toml pyproject.toml Makefile build/. e2e specification sandbox terraform scripts backend delta_backend ack_backend filenameprocessor recordprocessor"
41+
_dist_include="pytest.ini poetry.lock poetry.toml pyproject.toml Makefile build/. e2e e2e_batch specification sandbox terraform scripts backend delta_backend ack_backend filenameprocessor recordprocessor"
4242

4343

4444
#Create /dist/ sub-directory and copy files into directory

azure/templates/post-deploy.yml

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ steps:
114114
displayName: Waiting for TF resources to be UP
115115
workingDirectory: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)"
116116
117+
- bash: |
118+
pyenv install -s 3.10.8
119+
pyenv global 3.10.8
120+
python --version
121+
displayName: Set Python 3.10
122+
117123
- bash: |
118124
set -e
119125
export RELEASE_RELEASEID=$(Build.BuildId)
@@ -166,13 +172,45 @@ steps:
166172
echo "running: $test_cmd -v -c"
167173
$test_cmd -v -c
168174
fi
169-
170175
workingDirectory: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/e2e"
171-
displayName: Run full test suite
176+
displayName: Run Full Test Suite
177+
178+
179+
180+
- bash: |
181+
set -e
182+
if ! [[ "$APIGEE_ENVIRONMENT" == "prod" || "$APIGEE_ENVIRONMENT" == "int" || "$APIGEE_ENVIRONMENT" == *"sandbox" ]]; then
183+
echo "Running E2E batch folder test cases"
184+
185+
export AWS_PROFILE="apim-dev"
186+
aws_account_no="$(aws sts get-caller-identity --query Account --output text)"
187+
echo "Using AWS Account: $aws_account_no"
188+
189+
service_name="${FULLY_QUALIFIED_SERVICE_NAME}"
190+
191+
pr_no=$(echo "$service_name" | { grep -oE '[0-9]+$' || true; })
192+
if [ -z "$pr_no" ]; then
193+
workspace="$APIGEE_ENVIRONMENT"
194+
else
195+
workspace="pr-$pr_no"
196+
fi
197+
198+
poetry install --no-root # Install dependencies defined in pyproject.toml
199+
200+
ENV="$workspace" poetry run python -m unittest -v -c
201+
202+
echo "E2E batch folder test cases executed successfully"
203+
else
204+
echo "Skipping E2E batch folder test cases as the environment is prod-int-sandbox"
205+
fi
206+
207+
displayName: Run full batch test suite
208+
workingDirectory: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/e2e_batch"
209+
172210

173211
- task: PublishTestResults@2
174212
displayName: 'Publish test results'
175213
condition: always()
176214
inputs:
177215
testResultsFiles: '$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/tests/test-report.xml'
178-
failTaskOnFailedTests: true
216+
failTaskOnFailedTests: true

backend/.envrc.default

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
layout pyenv 3.10.12
1+
layout pyenv 3.10.16
22

3-
dotenv
3+
dotenv

backend/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
build
22
.venv
3+
.direnv
4+
.env
5+
.envrc
6+
terraform.tfstate
7+
.python-version

backend/src/fhir_service.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def get_immunization_by_identifier(
7676
base_url = f"{get_service_url()}/Immunization"
7777
response = form_json(imms_resp, element, identifier, base_url)
7878
return response
79-
79+
8080
def get_immunization_by_id(self, imms_id: str, imms_vax_type_perms: str) -> Optional[dict]:
8181
"""
8282
Get an Immunization by its ID. Return None if not found. If the patient doesn't have an NHS number,
@@ -85,26 +85,19 @@ def get_immunization_by_id(self, imms_id: str, imms_vax_type_perms: str) -> Opti
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", {}))
88+
# Returns the Immunisation full resource with no obfuscation
89+
resource = imms_resp.get("Resource", {})
90+
imms_filtered_for_read = Filter.read(resource) if resource else {}
9091

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")
9992

10093
return {
10194
"Version": imms_resp.get("Version", ""),
102-
"Resource": Immunization.parse_obj(imms_filtered_for_read_and_s_flag),
95+
"Resource": Immunization.parse_obj(imms_filtered_for_read),
10396
}
10497

10598
def get_immunization_by_id_all(self, imms_id: str, imms: dict) -> Optional[dict]:
10699
"""
107-
Get an Immunization by its ID. Return None if not found. If the patient doesn't have an NHS number,
100+
Get an Immunization by its ID. Return None if it is not found. If the patient doesn't have an NHS number,
108101
return the Immunization without calling PDS or checking S flag.
109102
"""
110103
imms["id"] = imms_id

backend/src/filter.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def replace_address_postal_codes(imms: dict) -> dict:
4747
# Remove all other keys in the address dictionary
4848
keys_to_remove = [key for key in address.keys() if key != "postalCode"]
4949
for key in keys_to_remove:
50-
del address[key]
50+
del address[key]
5151

5252
return imms
5353

@@ -59,23 +59,23 @@ def replace_organization_values(imms: dict) -> dict:
5959
"""
6060
for performer in imms.get("performer", [{}]):
6161
if performer.get("actor", {}).get("type") == "Organization":
62-
62+
6363
# Obfuscate or set the identifier value and system.
6464
identifier = performer["actor"].get("identifier", {})
6565
if identifier.get("value") is not None:
6666
identifier["value"] = "N2N9I"
6767
identifier["system"] = Urls.ods_organization_code
6868
if identifier.get("system") is not None:
6969
identifier["system"] = Urls.ods_organization_code
70-
70+
7171
# Ensure only 'system' and 'value' remain in identifier
7272
keys = {"system", "value"}
7373
keys_to_remove = [key for key in identifier.keys() if key not in keys]
7474
for key in keys_to_remove:
7575
del identifier[key]
76-
76+
7777
# Remove all other fields except 'identifier' in actor
78-
keys_to_remove = [key for key in performer["actor"].keys() if key not in ("identifier","type")]
78+
keys_to_remove = [key for key in performer["actor"].keys() if key not in ("identifier", "type")]
7979
for key in keys_to_remove:
8080
del performer["actor"][key]
8181

@@ -94,7 +94,6 @@ def add_use_to_identifier(imms: dict) -> dict:
9494

9595
class Filter:
9696
"""Functions for filtering a FHIR Immunization Resource"""
97-
9897
@staticmethod
9998
def read(imms: dict) -> dict:
10099
"""Apply filtering for READ request"""
@@ -108,9 +107,6 @@ def search(imms: dict, patient_full_url: str, bundle_patient: dict = None) -> di
108107
imms.pop("contained")
109108
imms["patient"] = create_reference_to_patient_resource(patient_full_url, bundle_patient)
110109
imms = add_use_to_identifier(imms)
111-
# Location identifier system and value are to be overwritten
112-
# (for backwards compatibility with Immunisation History API, as agreed with VDS team)
113-
imms["location"] = {"identifier": {"system": "urn:iso:std:iso:3166", "value": "GB"}}
114110
return imms
115111

116112
@staticmethod

backend/src/get_imms_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_imms_handler(event, context):
1616

1717
def get_immunization_by_id(event, controller: FhirController):
1818
try:
19-
return controller.get_immunization_by_id(event)
19+
return controller.get_immunization_by_id(event)
2020
except Exception: # pylint: disable = broad-exception-caught
2121
exp_error = create_operation_outcome(
2222
resource_id=str(uuid.uuid4()),

backend/tests/sample_data/completed_covid19_immunization_event_filtered_for_search_using_bundle_patient_resource.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@
4646
"display": "AstraZeneca Ltd"
4747
},
4848
"location": {
49+
"type": "Location",
4950
"identifier": {
50-
"value": "GB",
51-
"system": "urn:iso:std:iso:3166"
51+
"value": "X99999",
52+
"system": "https://fhir.nhs.uk/Id/ods-organization-code"
5253
}
5354
},
5455
"lotNumber": "4120Z001",

backend/tests/test_fhir_service.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def setUp(self):
157157
self.pds_service = create_autospec(PdsService)
158158
self.validator = create_autospec(ImmunizationValidator)
159159
self.fhir_service = FhirService(self.imms_repo, self.pds_service, self.validator)
160-
160+
161161
def test_get_immunization_by_id(self):
162162
"""it should find an Immunization by id"""
163163
imms_id = "an-id"
@@ -204,23 +204,7 @@ def test_get_immunization_by_id_patient_not_restricted(self):
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"

0 commit comments

Comments
 (0)