1
0
mirror of https://github.com/pcvolkmer/etl-processor.git synced 2025-04-19 17:26:51 +00:00

Do not append custom prefix to gPAS pseudonym

This commit is contained in:
Paul-Christian Volkmer 2023-08-09 12:26:57 +02:00
parent 47830ed9f7
commit 7f048e2483
5 changed files with 155 additions and 45 deletions

View File

@ -19,7 +19,6 @@
package dev.dnpm.etl.processor.pseudonym
import de.ukw.ccc.bwhc.dto.MtbFile
import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties
class PseudonymizeService(
@ -27,38 +26,11 @@ class PseudonymizeService(
private val configProperties: PseudonymizeConfigProperties
) {
fun pseudonymize(mtbFile: MtbFile): MtbFile {
val patientPseudonym = patientPseudonym(mtbFile.patient.id)
mtbFile.episode.patient = patientPseudonym
mtbFile.carePlans.forEach { it.patient = patientPseudonym }
mtbFile.patient.id = patientPseudonym
mtbFile.claims.forEach { it.patient = patientPseudonym }
mtbFile.consent.patient = patientPseudonym
mtbFile.claimResponses.forEach { it.patient = patientPseudonym }
mtbFile.diagnoses.forEach { it.patient = patientPseudonym }
mtbFile.ecogStatus.forEach { it.patient = patientPseudonym }
mtbFile.familyMemberDiagnoses.forEach { it.patient = patientPseudonym }
mtbFile.geneticCounsellingRequests.forEach { it.patient = patientPseudonym }
mtbFile.histologyReevaluationRequests.forEach { it.patient = patientPseudonym }
mtbFile.histologyReports.forEach { it.patient = patientPseudonym }
mtbFile.lastGuidelineTherapies.forEach { it.patient = patientPseudonym }
mtbFile.molecularPathologyFindings.forEach { it.patient = patientPseudonym }
mtbFile.molecularTherapies.forEach { it.history.forEach { it.patient = patientPseudonym } }
mtbFile.ngsReports.forEach { it.patient = patientPseudonym }
mtbFile.previousGuidelineTherapies.forEach { it.patient = patientPseudonym }
mtbFile.rebiopsyRequests.forEach { it.patient = patientPseudonym }
mtbFile.recommendations.forEach { it.patient = patientPseudonym }
mtbFile.recommendations.forEach { it.patient = patientPseudonym }
mtbFile.responses.forEach { it.patient = patientPseudonym }
mtbFile.specimens.forEach { it.patient = patientPseudonym }
mtbFile.specimens.forEach { it.patient = patientPseudonym }
return mtbFile
}
fun patientPseudonym(patientId: String): String {
return "${configProperties.prefix}_${generator.generate(patientId)}"
return when (generator) {
is GpasPseudonymGenerator -> generator.generate(patientId)
else -> "${configProperties.prefix}_${generator.generate(patientId)}"
}
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of ETL-Processor
*
* Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.dnpm.etl.processor.pseudonym
import de.ukw.ccc.bwhc.dto.MtbFile
infix fun MtbFile.pseudonymizeWith(pseudonymizeService: PseudonymizeService) {
val patientPseudonym = pseudonymizeService.patientPseudonym(this.patient.id)
this.episode.patient = patientPseudonym
this.carePlans.forEach { it.patient = patientPseudonym }
this.patient.id = patientPseudonym
this.claims.forEach { it.patient = patientPseudonym }
this.consent.patient = patientPseudonym
this.claimResponses.forEach { it.patient = patientPseudonym }
this.diagnoses.forEach { it.patient = patientPseudonym }
this.ecogStatus.forEach { it.patient = patientPseudonym }
this.familyMemberDiagnoses.forEach { it.patient = patientPseudonym }
this.geneticCounsellingRequests.forEach { it.patient = patientPseudonym }
this.histologyReevaluationRequests.forEach { it.patient = patientPseudonym }
this.histologyReports.forEach { it.patient = patientPseudonym }
this.lastGuidelineTherapies.forEach { it.patient = patientPseudonym }
this.molecularPathologyFindings.forEach { it.patient = patientPseudonym }
this.molecularTherapies.forEach { it.history.forEach { it.patient = patientPseudonym } }
this.ngsReports.forEach { it.patient = patientPseudonym }
this.previousGuidelineTherapies.forEach { it.patient = patientPseudonym }
this.rebiopsyRequests.forEach { it.patient = patientPseudonym }
this.recommendations.forEach { it.patient = patientPseudonym }
this.recommendations.forEach { it.patient = patientPseudonym }
this.responses.forEach { it.patient = patientPseudonym }
this.specimens.forEach { it.patient = patientPseudonym }
this.specimens.forEach { it.patient = patientPseudonym }
}

View File

@ -27,6 +27,7 @@ import dev.dnpm.etl.processor.monitoring.RequestStatus
import dev.dnpm.etl.processor.monitoring.RequestType
import dev.dnpm.etl.processor.output.MtbFileSender
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
import dev.dnpm.etl.processor.pseudonym.pseudonymizeWith
import org.apache.commons.codec.binary.Base32
import org.apache.commons.codec.digest.DigestUtils
import org.slf4j.LoggerFactory
@ -47,12 +48,13 @@ class RequestProcessor(
fun processMtbFile(mtbFile: MtbFile) {
val pid = mtbFile.patient.id
val pseudonymized = pseudonymizeService.pseudonymize(mtbFile)
if (isDuplication(pseudonymized)) {
mtbFile pseudonymizeWith pseudonymizeService
if (isDuplication(mtbFile)) {
requestService.save(
Request(
patientId = pseudonymized.patient.id,
patientId = mtbFile.patient.id,
pid = pid,
fingerprint = fingerprint(mtbFile),
status = RequestStatus.DUPLICATION,
@ -64,19 +66,19 @@ class RequestProcessor(
return
}
val request = MtbFileSender.MtbFileRequest(UUID.randomUUID().toString(), pseudonymized)
val request = MtbFileSender.MtbFileRequest(UUID.randomUUID().toString(), mtbFile)
val responseStatus = sender.send(request)
if (responseStatus.status == MtbFileSender.ResponseStatus.SUCCESS || responseStatus.status == MtbFileSender.ResponseStatus.WARNING) {
logger.info(
"Sent file for Patient '{}' using '{}'",
pseudonymized.patient.id,
mtbFile.patient.id,
sender.javaClass.simpleName
)
} else {
logger.error(
"Error sending file for Patient '{}' using '{}'",
pseudonymized.patient.id,
mtbFile.patient.id,
sender.javaClass.simpleName
)
}

View File

@ -0,0 +1,86 @@
/*
* This file is part of ETL-Processor
*
* Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.dnpm.etl.processor.pseudonym
import de.ukw.ccc.bwhc.dto.*
import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.whenever
@ExtendWith(MockitoExtension::class)
class PseudonymizeServiceTest {
private val mtbFile = MtbFile.builder()
.withPatient(
Patient.builder()
.withId("123")
.withBirthDate("2000-08-08")
.withGender(Patient.Gender.MALE)
.build()
)
.withConsent(
Consent.builder()
.withId("1")
.withStatus(Consent.Status.ACTIVE)
.withPatient("123")
.build()
)
.withEpisode(
Episode.builder()
.withId("1")
.withPatient("123")
.withPeriod(PeriodStart("2023-08-08"))
.build()
)
.build()
@Test
fun shouldNotUsePseudonymPrefixForGpas(@Mock generator: GpasPseudonymGenerator) {
doAnswer {
it.arguments[0]
}.whenever(generator).generate(anyString())
val pseudonymizeService = PseudonymizeService(generator, PseudonymizeConfigProperties())
mtbFile.pseudonymizeWith(pseudonymizeService)
assertThat(mtbFile.patient.id).isEqualTo("123")
}
@Test
fun shouldUsePseudonymPrefixForBuiltin(@Mock generator: AnonymizingGenerator) {
doAnswer {
it.arguments[0]
}.whenever(generator).generate(anyString())
val pseudonymizeService = PseudonymizeService(generator, PseudonymizeConfigProperties())
mtbFile.pseudonymizeWith(pseudonymizeService)
assertThat(mtbFile.patient.id).isEqualTo("UNKNOWN_123")
}
}

View File

@ -82,7 +82,7 @@ class RequestProcessorTest {
uuid = UUID.randomUUID().toString(),
patientId = "TEST_12345678901",
pid = "P1",
fingerprint = "cwaxsvectyfj4qcw4hiwzx5fwwo7lekyagpzd2ayuf36jlvi6msa",
fingerprint = "xrysxpozhbs2lnrjgf3yq4fzj33kxr7xr5c2cbuskmelfdmckl3a",
type = RequestType.MTB_FILE,
status = RequestStatus.SUCCESS,
processedAt = Instant.parse("2023-08-08T02:00:00Z")
@ -94,8 +94,8 @@ class RequestProcessorTest {
}.`when`(requestService).isLastRequestDeletion(anyString())
doAnswer {
it.arguments[0] as MtbFile
}.`when`(pseudonymizeService).pseudonymize(any())
it.arguments[0] as String
}.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(
@ -153,8 +153,8 @@ class RequestProcessorTest {
}.`when`(sender).send(any<MtbFileSender.MtbFileRequest>())
doAnswer {
it.arguments[0] as MtbFile
}.`when`(pseudonymizeService).pseudonymize(any())
it.arguments[0] as String
}.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(
@ -212,8 +212,8 @@ class RequestProcessorTest {
}.`when`(sender).send(any<MtbFileSender.MtbFileRequest>())
doAnswer {
it.arguments[0] as MtbFile
}.`when`(pseudonymizeService).pseudonymize(any())
it.arguments[0] as String
}.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(