Skip to content

Commit c4addd2

Browse files
authored
Merge pull request #146 from NHSDigital/dev/NPA-4474_Update_GET_Consent_Responses
NPA-4474 Add new GET /Consent status codes
2 parents 7c8ec64 + adf605d commit c4addd2

File tree

15 files changed

+246
-139
lines changed

15 files changed

+246
-139
lines changed

poetry.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pytest-nhsd-apim = "^3.3.2"
2525
flake8 = "^3.7.9"
2626
black = "^24.3.0"
2727
pip-licenses = "^4.4.0"
28-
jinja2 = "^3.1.3"
28+
jinja2 = "^3.1.6"
2929
PyYAML = "^6.0.1"
3030
docopt = "^0.6.2"
3131
jsonpath-rw = "^1.4.0"

sandbox/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ SHELL := /bin/bash
22
dirname := $(notdir $(patsubst %/,%,$(CURDIR)))
33

44
install: # Installs dependencies using poetry.
5-
poetry install --no-root
5+
poetry install
66

77
list: # List of make targets
88
@grep '^[^#[:space:]].*:' Makefile

sandbox/api/app.py

Lines changed: 5 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,28 @@
44

55
from .constants import (
66
INTERNAL_SERVER_ERROR_EXAMPLE,
7+
QUESTIONNAIRE_RESPONSE__SUCCESS,
78
RELATED__LIST_RELATIONSHIP,
89
RELATED__LIST_RELATIONSHIP_WITH_INCLUDE,
9-
INVALIDATED_RESOURCE,
10-
QUESTIONNAIRE_RESPONSE__SUCCESS,
1110
RELATED__VERIFY_RELATIONSHIP_09,
12-
RELATED__VERIFY_RELATIONSHIP_25,
1311
RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE,
12+
RELATED__VERIFY_RELATIONSHIP_25,
1413
RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE,
15-
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP,
16-
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH,
17-
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP,
18-
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH,
19-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH,
20-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PERFORMER,
21-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PATIENT,
22-
GET_CONSENT__MULTIPLE_RELATIONSHIPS,
23-
GET_CONSENT__NO_RELATIONSHIPS,
24-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_ACTIVE,
25-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_INACTIVE,
26-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE,
2714
POST_CONSENT__SUCCESS,
2815
POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR,
2916
POST_CONSENT__INVALID_ACCESS_LEVEL_ERROR,
3017
POST_CONSENT__INVALID_EVIDENCE_ERROR,
3118
POST_CONSENT__INVALID_PATIENT_AGE_ERROR,
3219
POST_CONSENT__PERFORMER_IDENTIFIER_ERROR,
3320
)
21+
from .get_consent import get_consent_response
3422
from .utils import (
3523
check_for_empty,
36-
check_for_consent_errors,
37-
check_for_related_person_errors,
3824
check_for_list,
25+
check_for_related_person_errors,
3926
check_for_validate,
4027
generate_response_from_example,
4128
remove_system,
42-
check_for_consent_include_params,
43-
check_for_consent_filtering,
4429
)
4530

4631
app = Flask(__name__)
@@ -140,56 +125,7 @@ def get_consent() -> Union[dict, tuple]:
140125
Returns:
141126
Union[dict, tuple]: Response for GET /Consent
142127
"""
143-
try:
144-
# Check Headers
145-
if errors := check_for_consent_errors(request):
146-
return errors
147-
148-
performer_identifier = remove_system(request.args.get("performer:identifier"))
149-
status = request.args.getlist("status")
150-
_include = request.args.getlist("_include")
151-
152-
# Single consenting adult relationship
153-
if performer_identifier == "9000000010":
154-
return check_for_consent_include_params(
155-
_include,
156-
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP,
157-
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH,
158-
)
159-
# Single mother child relationship
160-
elif performer_identifier == "9000000019":
161-
return check_for_consent_include_params(
162-
_include,
163-
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP,
164-
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH,
165-
)
166-
# Filtering
167-
elif performer_identifier == "9000000017":
168-
return check_for_consent_filtering(
169-
status,
170-
_include,
171-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_ACTIVE,
172-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_INACTIVE,
173-
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE,
174-
)
175-
elif performer_identifier == "9000000022":
176-
return check_for_consent_include_params(
177-
_include,
178-
GET_CONSENT__MULTIPLE_RELATIONSHIPS,
179-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH,
180-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PATIENT,
181-
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PERFORMER,
182-
)
183-
# No relationships
184-
elif performer_identifier == "9000000025":
185-
return generate_response_from_example(GET_CONSENT__NO_RELATIONSHIPS, 200)
186-
else:
187-
logger.error("Performer identifier does not match examples")
188-
return generate_response_from_example(INVALIDATED_RESOURCE, 404)
189-
190-
except Exception:
191-
logger.exception("GET Consent failed")
192-
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
128+
return get_consent_response()
193129

194130

195131
@app.route(f"/{COMMON_PATH}/Consent", methods=["POST"])

sandbox/api/get_consent.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from logging import INFO, basicConfig, getLogger
2+
from typing import Union
3+
4+
from flask import request
5+
6+
from .constants import (
7+
INTERNAL_SERVER_ERROR_EXAMPLE,
8+
INVALIDATED_RESOURCE,
9+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_ACTIVE,
10+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_INACTIVE,
11+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE,
12+
GET_CONSENT__MULTIPLE_RELATIONSHIPS,
13+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH,
14+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PATIENT,
15+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PERFORMER,
16+
GET_CONSENT__NO_RELATIONSHIPS,
17+
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP,
18+
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH,
19+
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP,
20+
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH,
21+
)
22+
from .utils import (
23+
check_for_consent_errors,
24+
check_for_consent_filtering,
25+
check_for_consent_include_params,
26+
generate_response_from_example,
27+
remove_system,
28+
)
29+
30+
basicConfig(level=INFO, format="%(asctime)s - %(message)s")
31+
logger = getLogger(__name__)
32+
33+
34+
def get_consent_response() -> Union[dict, tuple]:
35+
"""Sandbox API for GET /Consent
36+
37+
Returns:
38+
Union[dict, tuple]: Response for GET /Consent
39+
"""
40+
try:
41+
# Check Headers
42+
if errors := check_for_consent_errors(request):
43+
return errors
44+
45+
performer_identifier = remove_system(request.args.get("performer:identifier"))
46+
status = request.args.getlist("status")
47+
_include = request.args.getlist("_include")
48+
49+
# Single consenting adult relationship
50+
if performer_identifier == "9000000010":
51+
return check_for_consent_include_params(
52+
_include,
53+
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP,
54+
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH,
55+
)
56+
# Single mother child relationship
57+
elif performer_identifier == "9000000019":
58+
return check_for_consent_include_params(
59+
_include,
60+
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP,
61+
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH,
62+
)
63+
# Filtering
64+
elif performer_identifier == "9000000017":
65+
return check_for_consent_filtering(
66+
status,
67+
_include,
68+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_ACTIVE,
69+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_INACTIVE,
70+
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE,
71+
)
72+
elif performer_identifier == "9000000022":
73+
return check_for_consent_include_params(
74+
_include,
75+
GET_CONSENT__MULTIPLE_RELATIONSHIPS,
76+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH,
77+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PATIENT,
78+
GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_PERFORMER,
79+
)
80+
# No relationships
81+
elif performer_identifier == "9000000025":
82+
return generate_response_from_example(GET_CONSENT__NO_RELATIONSHIPS, 200)
83+
else:
84+
logger.error("Performer identifier does not match examples")
85+
return generate_response_from_example(INVALIDATED_RESOURCE, 404)
86+
87+
except Exception:
88+
logger.exception("An error occurred while processing the request")
89+
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)

sandbox/api/tests/test_app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
UTILS_FILE_PATH = "sandbox.api.utils"
2323
APP_FILE_PATH = "sandbox.api.app"
24+
GET_CONSENT_FILE_PATH = "sandbox.api.get_consent"
2425

2526

2627
@pytest.mark.parametrize("endpoint", ["/_status", "/_ping", "/health"])
@@ -163,7 +164,7 @@ def test_questionnaire_response(
163164
),
164165
],
165166
)
166-
@patch(f"{APP_FILE_PATH}.generate_response_from_example")
167+
@patch(f"{GET_CONSENT_FILE_PATH}.generate_response_from_example")
167168
def test_get_consent(
168169
mock_generate_response_from_example: MagicMock,
169170
request_args: str,
@@ -241,8 +242,8 @@ def test_post_consent_when_valid_returns_success(
241242
assert response.json == loads(mocked_response.get_data(as_text=True))
242243

243244

244-
@patch(f"{APP_FILE_PATH}.remove_system")
245-
@patch(f"{APP_FILE_PATH}.generate_response_from_example")
245+
@patch(f"{GET_CONSENT_FILE_PATH}.remove_system")
246+
@patch(f"{GET_CONSENT_FILE_PATH}.generate_response_from_example")
246247
def test_consent__500_internal_server_error(
247248
mock_generate_response_from_example: MagicMock,
248249
mock_remove_system: MagicMock,

sandbox/api/tests/test_utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from flask import Response
66

77
from ..utils import load_json_file
8-
from .conftest import RELATED_PERSON_API_ENDPOINT, CONSENT_API_ENDPOINT
8+
from .conftest import CONSENT_API_ENDPOINT, RELATED_PERSON_API_ENDPOINT
99

1010
FILE_PATH = "sandbox.api.utils"
1111

@@ -114,12 +114,12 @@ def test_related_person__not_found(
114114
(
115115
"performer:identifier=9000000017&status=test", # Invalid status parameter error
116116
"./api/examples/GET_Consent/errors/invalid-status-parameter.yaml",
117-
400,
117+
422,
118118
),
119119
(
120120
"performer:identifier=9000000019&_include=test", # Invalid include parameter error
121121
"./api/examples/errors/invalid-include-parameter.yaml",
122-
400,
122+
422,
123123
),
124124
],
125125
)
@@ -205,7 +205,7 @@ def test_check_for_related_person_errors(
205205
(
206206
"performer:identifier=90000009990", # Invalid performer identifier
207207
"./api/examples/GET_Consent/errors/invalid-identifier.yaml",
208-
400,
208+
422,
209209
),
210210
(
211211
"", # missing performer identifier
@@ -215,7 +215,7 @@ def test_check_for_related_person_errors(
215215
(
216216
"performer:identifier=https://fhir.nhs.uk/Id/nhs-number|A730675929", # identifier system invalid
217217
"./api/examples/GET_Consent/errors/invalid-identifier-system.yaml",
218-
400,
218+
422,
219219
),
220220
],
221221
)

0 commit comments

Comments
 (0)