Skip to content

Commit f32b1e7

Browse files
authored
Merge pull request #696 from NHSDigital/feature/eema1-NRL-820-addNewPointerTypes
NRL-820 add new pointer types to constants
2 parents 6adbb5a + 81731ce commit f32b1e7

File tree

13 files changed

+207
-1
lines changed

13 files changed

+207
-1
lines changed

api/producer/createDocumentReference/create_document_reference.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from nrlf.core.constants import (
55
PERMISSION_AUDIT_DATES_FROM_PAYLOAD,
66
PERMISSION_SUPERSEDE_IGNORE_DELETE_FAIL,
7+
TYPE_CATEGORIES,
78
)
89
from nrlf.core.decorators import request_handler
910
from nrlf.core.dynamodb.repository import DocumentPointer, DocumentPointerRepository
@@ -90,6 +91,19 @@ def _check_permissions(
9091
expression="type.coding[0].code",
9192
)
9293

94+
type_category = TYPE_CATEGORIES.get(core_model.type)
95+
if type_category != core_model.category:
96+
logger.log(
97+
LogReference.PROCREATE005a,
98+
ods_code=metadata.ods_code,
99+
type=core_model.type,
100+
category=core_model.category,
101+
)
102+
return SpineErrorResponse.BAD_REQUEST(
103+
diagnostics=f"The Category code of the provided document '{core_model.category}' must match the allowed category for pointer type '{core_model.type}' with a category value of '{type_category}'",
104+
expression="category.coding[0].code",
105+
)
106+
93107

94108
def _get_document_ids_to_supersede(
95109
resource: DocumentReference,

api/producer/createDocumentReference/tests/test_create_document_reference.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,51 @@ def test_create_document_reference_invalid_pointer_type():
424424
}
425425

426426

427+
def test_create_document_reference_invalid_category_type():
428+
doc_ref = load_document_reference("Y05868-736253002-Valid")
429+
430+
assert doc_ref.category and doc_ref.category[0].coding
431+
doc_ref.category[0].coding[0].code = "1102421000000108"
432+
doc_ref.category[0].coding[0].display = "Observations"
433+
434+
event = create_test_api_gateway_event(
435+
headers=create_headers(),
436+
body=doc_ref.json(exclude_none=True),
437+
)
438+
439+
result = handler(event, create_mock_context())
440+
body = result.pop("body")
441+
442+
assert result == {
443+
"statusCode": "400",
444+
"headers": {},
445+
"isBase64Encoded": False,
446+
}
447+
448+
parsed_body = json.loads(body)
449+
450+
assert parsed_body == {
451+
"resourceType": "OperationOutcome",
452+
"issue": [
453+
{
454+
"severity": "error",
455+
"code": "invalid",
456+
"details": {
457+
"coding": [
458+
{
459+
"code": "BAD_REQUEST",
460+
"display": "Bad request",
461+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
462+
}
463+
]
464+
},
465+
"diagnostics": "The Category code of the provided document 'http://snomed.info/sct|1102421000000108' must match the allowed category for pointer type 'http://snomed.info/sct|736253002' with a category value of 'http://snomed.info/sct|734163000'",
466+
"expression": ["category.coding[0].code"],
467+
}
468+
],
469+
}
470+
471+
427472
def test_create_document_reference_no_relatesto_target():
428473
doc_ref = load_document_reference("Y05868-736253002-Valid")
429474
doc_ref.relatesTo = [

api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,51 @@ def test_create_document_reference_happy_path_with_ssp(
142142
}
143143

144144

145+
def test_create_document_reference_invalid_category_type():
146+
doc_ref = load_document_reference("Y05868-736253002-Valid")
147+
148+
assert doc_ref.category and doc_ref.category[0].coding
149+
doc_ref.category[0].coding[0].code = "1102421000000108"
150+
doc_ref.category[0].coding[0].display = "Observations"
151+
152+
event = create_test_api_gateway_event(
153+
headers=create_headers(),
154+
body=doc_ref.json(exclude_none=True),
155+
)
156+
157+
result = handler(event, create_mock_context())
158+
body = result.pop("body")
159+
160+
assert result == {
161+
"statusCode": "400",
162+
"headers": {},
163+
"isBase64Encoded": False,
164+
}
165+
166+
parsed_body = json.loads(body)
167+
168+
assert parsed_body == {
169+
"resourceType": "OperationOutcome",
170+
"issue": [
171+
{
172+
"severity": "error",
173+
"code": "invalid",
174+
"details": {
175+
"coding": [
176+
{
177+
"code": "BAD_REQUEST",
178+
"display": "Bad request",
179+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
180+
}
181+
]
182+
},
183+
"diagnostics": "The Category code of the provided document 'http://snomed.info/sct|1102421000000108' must match the allowed category for pointer type 'http://snomed.info/sct|736253002' with a category value of 'http://snomed.info/sct|734163000'",
184+
"expression": ["category.coding[0].code"],
185+
}
186+
],
187+
}
188+
189+
145190
def test_create_document_reference_no_body():
146191
event = create_test_api_gateway_event(
147192
headers=create_headers(),

api/producer/upsertDocumentReference/upsert_document_reference.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from nrlf.core.constants import (
33
PERMISSION_AUDIT_DATES_FROM_PAYLOAD,
44
PERMISSION_SUPERSEDE_IGNORE_DELETE_FAIL,
5+
TYPE_CATEGORIES,
56
)
67
from nrlf.core.decorators import request_handler
78
from nrlf.core.dynamodb.repository import DocumentPointer, DocumentPointerRepository
@@ -88,6 +89,19 @@ def _check_permissions(
8889
expression="type.coding[0].code",
8990
)
9091

92+
type_category = TYPE_CATEGORIES.get(core_model.type)
93+
if type_category != core_model.category:
94+
logger.log(
95+
LogReference.PROUPSERT005a,
96+
ods_code=metadata.ods_code,
97+
type=core_model.type,
98+
category=core_model.category,
99+
)
100+
return SpineErrorResponse.BAD_REQUEST(
101+
diagnostics=f"The Category code of the provided document '{core_model.category}' must match the allowed category for pointer type '{core_model.type}' with a category value of '{type_category}'",
102+
expression="category.coding[0].code",
103+
)
104+
91105

92106
def _get_document_ids_to_supersede(
93107
resource: DocumentReference,

layer/nrlf/core/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class PointerTypes(Enum):
4646
CONTINGENCY_PLAN = "http://snomed.info/sct|325691000000100"
4747
EOL_CARE_PLAN = "http://snomed.info/sct|736373009"
4848
LLOYD_GEORGE_FOLDER = "http://snomed.info/sct|16521000000101"
49+
ADVANCED_CARE_PLAN = "http://snomed.info/sct|736366004"
50+
TREATMENT_ESCALATION_PLAN = "http://snomed.info/sct|735324008"
4951

5052
@staticmethod
5153
def list():
@@ -66,6 +68,8 @@ class Categories(Enum):
6668
PointerTypes.EOL_CARE_PLAN.value: Categories.CARE_PLAN.value,
6769
PointerTypes.LLOYD_GEORGE_FOLDER.value: Categories.CARE_PLAN.value,
6870
PointerTypes.NEWS2_CHART.value: Categories.OBSERVATIONS.value,
71+
PointerTypes.ADVANCED_CARE_PLAN.value: Categories.CARE_PLAN.value,
72+
PointerTypes.TREATMENT_ESCALATION_PLAN.value: Categories.CARE_PLAN.value,
6973
}
7074

7175

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import pytest
2+
3+
from nrlf.core.constants import PointerTypes
4+
from nrlf.core.dynamodb.repository import _get_sk_ids_for_type
5+
6+
7+
def test_get_sk_ids_for_type_exception_thrown_for_invalid_type():
8+
with pytest.raises(ValueError) as error:
9+
_get_sk_ids_for_type("invalid_type")
10+
11+
assert str(error.value) == "Cannot find category for pointer type: invalid_type"
12+
13+
14+
def test_get_sk_ids_for_type_returns_type_and_category_for_every_type():
15+
for each in PointerTypes.list():
16+
category, pointer_type = _get_sk_ids_for_type(each)
17+
assert category and pointer_type
18+
19+
20+
def test_get_sk_ids_for_type_exception_thrown_if_new_type_has_no_category():
21+
pointer_types = PointerTypes.list()
22+
pointer_types.append("some_pointer_type")
23+
with pytest.raises(ValueError) as error:
24+
for each in pointer_types:
25+
category, pointer_type = _get_sk_ids_for_type(each)
26+
assert category and pointer_type
27+
28+
assert (
29+
str(error.value) == "Cannot find category for pointer type: some_pointer_type"
30+
)
31+
32+
33+
# TODO: Add unit tests for Repository Class

layer/nrlf/core/log_references.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ class LogReference(Enum):
210210
PROCREATE005 = _Reference(
211211
"WARN", "Organisation is not allowed to create pointer type"
212212
) #
213+
PROCREATE005a = _Reference(
214+
"WARN",
215+
"Organisation is not allowed to create pointer type with incorrect category",
216+
) #
213217
PROCREATE006 = _Reference("DEBUG", "Performing relatesTo validation on resource")
214218
PROCREATE007a = _Reference(
215219
"WARN", "RelatesTo validation failed - no target identifier value"
@@ -256,6 +260,10 @@ class LogReference(Enum):
256260
PROUPSERT005 = _Reference(
257261
"WARN", "Organisation is not allowed to upsert pointer type for upsert"
258262
) #
263+
PROUPSERT005a = _Reference(
264+
"WARN",
265+
"Organisation is not allowed to upsert pointer type with incorrect category code",
266+
) #
259267
PROUPSERT006 = _Reference(
260268
"DEBUG", "Performing relatesTo validation on resource for upsert"
261269
)

scripts/get_s3_permissions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
"http://snomed.info/sct|736373009",
1515
"http://snomed.info/sct|861421000000109",
1616
"http://snomed.info/sct|887701000000100",
17+
"http://snomed.info/sct|736366004",
18+
"http://snomed.info/sct|735324008",
1719
]
1820

1921

terraform/account-wide-infrastructure/modules/lambda-errors-metric-alarm/iam.tf

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,43 @@ resource "aws_iam_policy" "lambda-errors-topic-kms-read-write" {
1313
]
1414
Effect = "Allow"
1515
Resource = [
16-
aws_kms_key.lambda-errors-topic-key.arn
16+
aws_kms_key.lambda-errors-topic-key.arn,
17+
aws_cloudwatch_metric_alarm.metric_alarm.arn
1718
]
1819
}
1920
]
2021
})
2122
}
23+
24+
data "aws_caller_identity" "current" {}
25+
26+
data "aws_iam_policy_document" "sns_kms_key_policy" {
27+
policy_id = "CloudWatchEncryptUsingKey"
28+
29+
statement {
30+
effect = "Allow"
31+
actions = [
32+
"kms:*"
33+
]
34+
resources = ["*"]
35+
36+
principals {
37+
type = "AWS"
38+
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
39+
}
40+
}
41+
42+
statement {
43+
effect = "Allow"
44+
actions = [
45+
"kms:Decrypt",
46+
"kms:GenerateDataKey"
47+
]
48+
resources = ["*"]
49+
50+
principals {
51+
type = "Service"
52+
identifiers = ["cloudwatch.amazonaws.com"]
53+
}
54+
}
55+
}

terraform/account-wide-infrastructure/modules/lambda-errors-metric-alarm/kms.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
resource "aws_kms_key" "lambda-errors-topic-key" {
22
description = "Lambda errors SNS topic table KMS key"
33
deletion_window_in_days = var.kms_deletion_window_in_days
4+
policy = data.aws_iam_policy_document.sns_kms_key_policy.json
45

56
}
67

0 commit comments

Comments
 (0)