Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions layer/nrlf/core/tests/test_sample_pointers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os

import pytest

from nrlf.consumer.fhir.r4.model import DocumentReference as ConsumerDocumentReference
from nrlf.core.validators import DocumentReferenceValidator
from nrlf.producer.fhir.r4.model import DocumentReference as ProducerDocumentReference


def sample_pointer_files() -> list[str]:
return [f for f in os.listdir("./tests/data/samples") if f.endswith(".json")]


def load_sample_pointer_data(pointer_file: str) -> str:
with open(f"./tests/data/samples/{pointer_file}", "r") as f:
return f.read()


@pytest.mark.parametrize("sample_pointer_file", sample_pointer_files())
def test_sample_pointer_as_consumer(sample_pointer_file: str):
sample_pointer_data = load_sample_pointer_data(sample_pointer_file)

docref = ConsumerDocumentReference.model_validate_json(sample_pointer_data)
result = DocumentReferenceValidator().validate(data=docref)

assert result.is_valid


@pytest.mark.parametrize("sample_pointer_file", sample_pointer_files())
def test_sample_pointer_as_producer(sample_pointer_file: str):
sample_pointer_data = load_sample_pointer_data(sample_pointer_file)

docref = ProducerDocumentReference.model_validate_json(sample_pointer_data)
result = DocumentReferenceValidator().validate(data=docref)

assert result.is_valid
99 changes: 99 additions & 0 deletions scripts/redact_live_pointers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import json
import os
from datetime import datetime, timedelta, timezone
from typing import Any

import boto3
import fire

from nrlf.consumer.fhir.r4.model import DocumentReference
from nrlf.core.constants import PointerTypes
from nrlf.core.logger import logger
from nrlf.core.utils import create_fhir_instant
from nrlf.core.validators import DocumentReferenceValidator

dynamodb = boto3.client("dynamodb")
paginator = dynamodb.get_paginator("scan")

logger.setLevel("ERROR")

type_to_name = {pointer_type.value: pointer_type.name for pointer_type in PointerTypes}


def _redact_timestamps(docref: DocumentReference) -> None:
mock_timestamp = create_fhir_instant()
docref.meta.lastUpdated = mock_timestamp
docref.date = mock_timestamp


def _redact_ids(docref: DocumentReference) -> None:
ods_code = docref.custodian.identifier.value

mock_id = "c2a99222-eb50-4451-ad6e-1e951627800e"
docref.subject.identifier.value = "9999999999"
docref.id = f"{ods_code}-{mock_id}"
if docref.masterIdentifier:
docref.masterIdentifier.value = f"mid_{mock_id}"
if docref.relatesTo:
for relates_to in docref.relatesTo:
relates_to.target.identifier.value = f"rel_{mock_id}"


def _redact_content(docref: DocumentReference) -> None:
mock_timestamp = create_fhir_instant()
for content in docref.content:
if content.attachment.url.startswith("ssp://"):
content.attachment.url = "ssp://content.test.local/content"
else:
content.attachment.url = "https://content.test.local/content"
content.attachment.creation = mock_timestamp


def _redact_context(docref: DocumentReference) -> None:
if docref.context.related:
for related in docref.context.related:
related.identifier.value = "012345678910"

mock_timestamp = create_fhir_instant()
if docref.context.period:
if docref.context.period.start:
docref.context.period.start = mock_timestamp
if docref.context.period.end:
docref.context.period.end = mock_timestamp


def _redact_pointers(src_path: str, dest_path: str) -> None:
"""
Redact pointers in .json files in from the source path and write the redacted pointer to the destination path.
Parameters:
- src_path: The path to the source directory containing the pointers.
- dest_path: The path to the destination directory to write the redacted pointers.
"""
src_pointer_files = [f for f in os.listdir(src_path) if f.endswith(".json")]

for src_pointer_file in src_pointer_files:
print("Reading", src_pointer_file)
with open(f"{src_path}/{src_pointer_file}", "r") as f:
pointer_data = f.read()

docref = DocumentReference.model_validate_json(pointer_data)

ods_code = docref.custodian.identifier.value
type_coding = docref.type.coding[0]
pointer_type = type_to_name[f"{type_coding.system}|{type_coding.code}"]

_redact_ids(docref)
_redact_timestamps(docref)
_redact_content(docref)
_redact_context(docref)

month_year = datetime.now().strftime("%b%y")
filename = f"{dest_path}/{ods_code}_{pointer_type}_{month_year}.json"

print("Writing", filename)
with open(filename, "w") as f:
f.write(docref.model_dump_json(indent=2, exclude_unset=True))


if __name__ == "__main__":
fire.Fire(_redact_pointers)
103 changes: 103 additions & 0 deletions tests/data/samples/11X_ADVANCE_CARE_PLAN_Feb25.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"resourceType": "DocumentReference",
"id": "11X-c2a99222-eb50-4451-ad6e-1e951627800e",
"meta": {
"lastUpdated": "2025-02-10T16:48:27.326Z"
},
"masterIdentifier": {
"system": "urn:ietf:rfc:3986",
"value": "mid_c2a99222-eb50-4451-ad6e-1e951627800e"
},
"status": "current",
"type": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "736366004",
"display": "Advance care plan"
}
]
},
"category": [
{
"coding": [
{
"system": "http://snomed.info/sct",
"code": "734163000",
"display": "Care plan"
}
]
}
],
"subject": {
"identifier": {
"system": "https://fhir.nhs.uk/Id/nhs-number",
"value": "9999999999"
}
},
"date": "2025-02-10T16:48:27.326Z",
"author": [
{
"identifier": {
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "L85012"
}
}
],
"custodian": {
"identifier": {
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "11X"
}
},
"content": [
{
"attachment": {
"contentType": "application/pdf",
"url": "ssp://content.test.local/content",
"creation": "2025-02-10T16:48:27.326Z"
},
"format": {
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode",
"code": "urn:nhs-ic:unstructured",
"display": "Unstructured Document"
},
"extension": [
{
"valueCodeableConcept": {
"coding": [
{
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
"code": "static",
"display": "Static"
}
]
},
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability"
}
]
}
],
"context": {
"period": {
"start": "2025-02-10T16:48:27.326Z"
},
"practiceSetting": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1060971000000108",
"display": "General practice service"
}
]
},
"related": [
{
"identifier": {
"system": "https://fhir.nhs.uk/Id/nhsSpineASID",
"value": "012345678910"
}
}
]
}
}
103 changes: 103 additions & 0 deletions tests/data/samples/11X_PERSONALISED_CARE_AND_SUPPORT_PLAN_Feb25.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"resourceType": "DocumentReference",
"id": "11X-c2a99222-eb50-4451-ad6e-1e951627800e",
"meta": {
"lastUpdated": "2025-02-10T16:48:27.327Z"
},
"masterIdentifier": {
"system": "urn:ietf:rfc:3986",
"value": "mid_c2a99222-eb50-4451-ad6e-1e951627800e"
},
"status": "current",
"type": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "2181441000000107",
"display": "Personalised Care and Support Plan"
}
]
},
"category": [
{
"coding": [
{
"system": "http://snomed.info/sct",
"code": "734163000",
"display": "Care plan"
}
]
}
],
"subject": {
"identifier": {
"system": "https://fhir.nhs.uk/Id/nhs-number",
"value": "9999999999"
}
},
"date": "2025-02-10T16:48:27.327Z",
"author": [
{
"identifier": {
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "L85609"
}
}
],
"custodian": {
"identifier": {
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "11X"
}
},
"content": [
{
"attachment": {
"contentType": "application/pdf",
"url": "ssp://content.test.local/content",
"creation": "2025-02-10T16:48:27.327Z"
},
"format": {
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode",
"code": "urn:nhs-ic:unstructured",
"display": "Unstructured Document"
},
"extension": [
{
"valueCodeableConcept": {
"coding": [
{
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
"code": "static",
"display": "Static"
}
]
},
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability"
}
]
}
],
"context": {
"period": {
"start": "2025-02-10T16:48:27.327Z"
},
"practiceSetting": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1060971000000108",
"display": "General practice service"
}
]
},
"related": [
{
"identifier": {
"system": "https://fhir.nhs.uk/Id/nhsSpineASID",
"value": "012345678910"
}
}
]
}
}
Loading
Loading