summaryrefslogtreecommitdiff
path: root/src/main/kotlin/dev/dnpm/etl
diff options
context:
space:
mode:
authorPaul-Christian Volkmer2024-07-15 10:27:51 +0200
committerPaul-Christian Volkmer2024-07-15 10:31:52 +0200
commitc8f6e6efc812cc12d17c2af1cc24a9318180a8fe (patch)
treec4a39f322e708648c2e731d6954d8fc600b12db9 /src/main/kotlin/dev/dnpm/etl
parentc949ec07e50f86cb98b7ac5dd9e529022cb6cd0b (diff)
refactor: add types for patient id and pseudonym
Diffstat (limited to 'src/main/kotlin/dev/dnpm/etl')
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt6
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt6
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt20
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt4
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt3
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt8
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt3
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt24
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt9
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/types.kt10
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt3
11 files changed, 57 insertions, 39 deletions
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt b/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt
index b72b1fd..2aff8cb 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt
@@ -22,6 +22,7 @@ package dev.dnpm.etl.processor.input
import com.fasterxml.jackson.databind.ObjectMapper
import de.ukw.ccc.bwhc.dto.Consent
import de.ukw.ccc.bwhc.dto.MtbFile
+import dev.dnpm.etl.processor.PatientId
import dev.dnpm.etl.processor.RequestId
import dev.dnpm.etl.processor.services.RequestProcessor
import org.apache.kafka.clients.consumer.ConsumerRecord
@@ -36,6 +37,7 @@ class KafkaInputListener(
override fun onMessage(data: ConsumerRecord<String, String>) {
val mtbFile = objectMapper.readValue(data.value(), MtbFile::class.java)
+ val patientId = PatientId(mtbFile.patient.id)
val firstRequestIdHeader = data.headers().headers("requestId")?.firstOrNull()
val requestId = if (null != firstRequestIdHeader) {
RequestId(String(firstRequestIdHeader.value()))
@@ -53,9 +55,9 @@ class KafkaInputListener(
} else {
logger.debug("Accepted MTB File and process deletion")
if (requestId.isBlank()) {
- requestProcessor.processDeletion(mtbFile.patient.id)
+ requestProcessor.processDeletion(patientId)
} else {
- requestProcessor.processDeletion(mtbFile.patient.id, requestId)
+ requestProcessor.processDeletion(patientId, requestId)
}
}
}
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
index 8259288..9e282c2 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
@@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.input
import de.ukw.ccc.bwhc.dto.Consent
import de.ukw.ccc.bwhc.dto.MtbFile
+import dev.dnpm.etl.processor.PatientId
import dev.dnpm.etl.processor.services.RequestProcessor
import org.slf4j.LoggerFactory
import org.springframework.http.ResponseEntity
@@ -46,7 +47,8 @@ class MtbFileRestController(
requestProcessor.processMtbFile(mtbFile)
} else {
logger.debug("Accepted MTB File and process deletion")
- requestProcessor.processDeletion(mtbFile.patient.id)
+ val patientId = PatientId(mtbFile.patient.id)
+ requestProcessor.processDeletion(patientId)
}
return ResponseEntity.accepted().build()
}
@@ -54,7 +56,7 @@ class MtbFileRestController(
@DeleteMapping(path = ["{patientId}"])
fun deleteData(@PathVariable patientId: String): ResponseEntity<Void> {
logger.debug("Accepted patient ID to process deletion")
- requestProcessor.processDeletion(patientId)
+ requestProcessor.processDeletion(PatientId(patientId))
return ResponseEntity.accepted().build()
}
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt
index 9efae4c..d26d222 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt
@@ -19,9 +19,7 @@
package dev.dnpm.etl.processor.monitoring
-import dev.dnpm.etl.processor.Fingerprint
-import dev.dnpm.etl.processor.randomRequestId
-import dev.dnpm.etl.processor.RequestId
+import dev.dnpm.etl.processor.*
import org.springframework.data.annotation.Id
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
@@ -38,8 +36,8 @@ import java.util.*
data class Request(
@Id val id: Long? = null,
val uuid: RequestId = randomRequestId(),
- val patientId: String,
- val pid: String,
+ val patientId: PatientPseudonym,
+ val pid: PatientId,
@Column("fingerprint")
val fingerprint: Fingerprint,
val type: RequestType,
@@ -49,8 +47,8 @@ data class Request(
) {
constructor(
uuid: RequestId,
- patientId: String,
- pid: String,
+ patientId: PatientPseudonym,
+ pid: PatientId,
fingerprint: Fingerprint,
type: RequestType,
status: RequestStatus
@@ -59,8 +57,8 @@ data class Request(
constructor(
uuid: RequestId,
- patientId: String,
- pid: String,
+ patientId: PatientPseudonym,
+ pid: PatientId,
fingerprint: Fingerprint,
type: RequestType,
status: RequestStatus,
@@ -83,11 +81,11 @@ data class CountedState(
interface RequestRepository : CrudRepository<Request, Long>, PagingAndSortingRepository<Request, Long> {
- fun findAllByPatientIdOrderByProcessedAtDesc(patientId: String): List<Request>
+ fun findAllByPatientIdOrderByProcessedAtDesc(patientId: PatientPseudonym): List<Request>
fun findByUuidEquals(uuid: RequestId): Optional<Request>
- fun findRequestByPatientId(patientId: String, pageable: Pageable): Page<Request>
+ fun findRequestByPatientId(patientId: PatientPseudonym, pageable: Pageable): Page<Request>
@Query("SELECT count(*) AS count, status FROM request WHERE type = 'MTB_FILE' GROUP BY status ORDER BY status, count DESC;")
fun countStates(): List<CountedState>
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt
index 7b777e8..4838689 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt
@@ -63,7 +63,7 @@ class KafkaMtbFileSender(
val dummyMtbFile = MtbFile.builder()
.withConsent(
Consent.builder()
- .withPatient(request.patientId)
+ .withPatient(request.patientId.value)
.withStatus(Consent.Status.REJECTED)
.build()
)
@@ -99,7 +99,7 @@ class KafkaMtbFileSender(
}
private fun key(request: MtbFileSender.DeleteRequest): String {
- return "{\"pid\": \"${request.patientId}\"}"
+ return "{\"pid\": \"${request.patientId.value}\"}"
}
data class Data(val requestId: RequestId, val content: MtbFile)
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt
index 2670f2e..8d994c5 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt
@@ -20,6 +20,7 @@
package dev.dnpm.etl.processor.output
import de.ukw.ccc.bwhc.dto.MtbFile
+import dev.dnpm.etl.processor.PatientPseudonym
import dev.dnpm.etl.processor.RequestId
import dev.dnpm.etl.processor.monitoring.RequestStatus
import org.springframework.http.HttpStatusCode
@@ -35,7 +36,7 @@ interface MtbFileSender {
data class MtbFileRequest(val requestId: RequestId, val mtbFile: MtbFile)
- data class DeleteRequest(val requestId: RequestId, val patientId: String)
+ data class DeleteRequest(val requestId: RequestId, val patientId: PatientPseudonym)
}
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
index d18cd2c..e80f6ec 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
@@ -19,6 +19,8 @@
package dev.dnpm.etl.processor.pseudonym
+import dev.dnpm.etl.processor.PatientId
+import dev.dnpm.etl.processor.PatientPseudonym
import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties
class PseudonymizeService(
@@ -26,10 +28,10 @@ class PseudonymizeService(
private val configProperties: PseudonymizeConfigProperties
) {
- fun patientPseudonym(patientId: String): String {
+ fun patientPseudonym(patientId: PatientId): PatientPseudonym {
return when (generator) {
- is GpasPseudonymGenerator -> generator.generate(patientId)
- else -> "${configProperties.prefix}_${generator.generate(patientId)}"
+ is GpasPseudonymGenerator -> PatientPseudonym(generator.generate(patientId.value))
+ else -> PatientPseudonym("${configProperties.prefix}_${generator.generate(patientId.value)}")
}
}
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt
index ef25787..bf645f6 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt
@@ -20,6 +20,7 @@
package dev.dnpm.etl.processor.pseudonym
import de.ukw.ccc.bwhc.dto.MtbFile
+import dev.dnpm.etl.processor.PatientId
import org.apache.commons.codec.digest.DigestUtils
/** Replaces patient ID with generated patient pseudonym
@@ -29,7 +30,7 @@ import org.apache.commons.codec.digest.DigestUtils
* @return The MTB file containing patient pseudonymes
*/
infix fun MtbFile.pseudonymizeWith(pseudonymizeService: PseudonymizeService) {
- val patientPseudonym = pseudonymizeService.patientPseudonym(this.patient.id)
+ val patientPseudonym = pseudonymizeService.patientPseudonym(PatientId(this.patient.id)).value
this.episode?.patient = patientPseudonym
this.carePlans?.forEach { it.patient = patientPseudonym }
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt
index 94598ae..2cbfd2f 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt
@@ -21,9 +21,7 @@ package dev.dnpm.etl.processor.services
import com.fasterxml.jackson.databind.ObjectMapper
import de.ukw.ccc.bwhc.dto.MtbFile
-import dev.dnpm.etl.processor.Fingerprint
-import dev.dnpm.etl.processor.randomRequestId
-import dev.dnpm.etl.processor.RequestId
+import dev.dnpm.etl.processor.*
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.monitoring.Report
import dev.dnpm.etl.processor.monitoring.Request
@@ -56,17 +54,19 @@ class RequestProcessor(
}
fun processMtbFile(mtbFile: MtbFile, requestId: RequestId) {
- val pid = mtbFile.patient.id
+ val pid = PatientId(mtbFile.patient.id)
mtbFile pseudonymizeWith pseudonymizeService
mtbFile anonymizeContentWith pseudonymizeService
val request = MtbFileSender.MtbFileRequest(requestId, transformationService.transform(mtbFile))
+ val patientPseudonym = PatientPseudonym(request.mtbFile.patient.id)
+
requestService.save(
Request(
requestId,
- request.mtbFile.patient.id,
+ patientPseudonym,
pid,
fingerprint(request.mtbFile),
RequestType.MTB_FILE,
@@ -101,20 +101,22 @@ class RequestProcessor(
}
private fun isDuplication(pseudonymizedMtbFile: MtbFile): Boolean {
+ val patientPseudonym = PatientPseudonym(pseudonymizedMtbFile.patient.id)
+
val lastMtbFileRequestForPatient =
- requestService.lastMtbFileRequestForPatientPseudonym(pseudonymizedMtbFile.patient.id)
- val isLastRequestDeletion = requestService.isLastRequestWithKnownStatusDeletion(pseudonymizedMtbFile.patient.id)
+ requestService.lastMtbFileRequestForPatientPseudonym(patientPseudonym)
+ val isLastRequestDeletion = requestService.isLastRequestWithKnownStatusDeletion(patientPseudonym)
return null != lastMtbFileRequestForPatient
&& !isLastRequestDeletion
&& lastMtbFileRequestForPatient.fingerprint == fingerprint(pseudonymizedMtbFile)
}
- fun processDeletion(patientId: String) {
+ fun processDeletion(patientId: PatientId) {
processDeletion(patientId, randomRequestId())
}
- fun processDeletion(patientId: String, requestId: RequestId) {
+ fun processDeletion(patientId: PatientId, requestId: RequestId) {
try {
val patientPseudonym = pseudonymizeService.patientPseudonym(patientId)
@@ -123,7 +125,7 @@ class RequestProcessor(
requestId,
patientPseudonym,
patientId,
- fingerprint(patientPseudonym),
+ fingerprint(patientPseudonym.value),
RequestType.DELETE,
RequestStatus.UNKNOWN
)
@@ -147,7 +149,7 @@ class RequestProcessor(
requestService.save(
Request(
uuid = requestId,
- patientId = "???",
+ patientId = emptyPatientPseudonym(),
pid = patientId,
fingerprint = Fingerprint.empty(),
status = RequestStatus.ERROR,
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt
index a2e8de3..826b060 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt
@@ -19,6 +19,7 @@
package dev.dnpm.etl.processor.services
+import dev.dnpm.etl.processor.PatientPseudonym
import dev.dnpm.etl.processor.RequestId
import dev.dnpm.etl.processor.monitoring.*
import org.springframework.data.domain.Page
@@ -40,15 +41,15 @@ class RequestService(
fun findByUuid(uuid: RequestId): Optional<Request> =
requestRepository.findByUuidEquals(uuid)
- fun findRequestByPatientId(patientId: String, pageable: Pageable): Page<Request> = requestRepository.findRequestByPatientId(patientId, pageable)
+ fun findRequestByPatientId(patientId: PatientPseudonym, pageable: Pageable): Page<Request> = requestRepository.findRequestByPatientId(patientId, pageable)
- fun allRequestsByPatientPseudonym(patientPseudonym: String) = requestRepository
+ fun allRequestsByPatientPseudonym(patientPseudonym: PatientPseudonym) = requestRepository
.findAllByPatientIdOrderByProcessedAtDesc(patientPseudonym)
- fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: String) =
+ fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: PatientPseudonym) =
Companion.lastMtbFileRequestForPatientPseudonym(allRequestsByPatientPseudonym(patientPseudonym))
- fun isLastRequestWithKnownStatusDeletion(patientPseudonym: String) =
+ fun isLastRequestWithKnownStatusDeletion(patientPseudonym: PatientPseudonym) =
Companion.isLastRequestWithKnownStatusDeletion(allRequestsByPatientPseudonym(patientPseudonym))
fun countStates(): Iterable<CountedState> = requestRepository.countStates()
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/types.kt b/src/main/kotlin/dev/dnpm/etl/processor/types.kt
index b41a550..b2f13ef 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/types.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/types.kt
@@ -38,4 +38,12 @@ value class RequestId(val value: String) {
}
-fun randomRequestId() = RequestId(UUID.randomUUID().toString()) \ No newline at end of file
+fun randomRequestId() = RequestId(UUID.randomUUID().toString())
+
+@JvmInline
+value class PatientId(val value: String)
+
+@JvmInline
+value class PatientPseudonym(val value: String)
+
+fun emptyPatientPseudonym() = PatientPseudonym("") \ No newline at end of file
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt b/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt
index ac003d3..43f2f1d 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt
@@ -20,6 +20,7 @@
package dev.dnpm.etl.processor.web
import dev.dnpm.etl.processor.NotFoundException
+import dev.dnpm.etl.processor.PatientPseudonym
import dev.dnpm.etl.processor.RequestId
import dev.dnpm.etl.processor.monitoring.ReportService
import dev.dnpm.etl.processor.services.RequestService
@@ -56,7 +57,7 @@ class HomeController(
@PageableDefault(page = 0, size = 20, sort = ["processedAt"], direction = Sort.Direction.DESC) pageable: Pageable,
model: Model
): String {
- val requests = requestService.findRequestByPatientId(patientId, pageable)
+ val requests = requestService.findRequestByPatientId(PatientPseudonym(patientId), pageable)
model.addAttribute("patientId", patientId)
model.addAttribute("requests", requests)