mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-01 14:12:55 +00:00
feat: Broad Consent and GenomDE Consent can be embedded into mtb file
This commit is contained in:
@ -214,13 +214,11 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Bundle getBroadConsent(String personIdentifierValue, Date requestDate) {
|
public Bundle getBroadConsent(String personIdentifierValue, Date requestDate) {
|
||||||
String consentDomainName = gIcsConfigProperties.getBroadConsentDomainName();
|
|
||||||
return currentConsentForPersonAndTemplate(personIdentifierValue, ConsentDomain.BroadConsent,
|
return currentConsentForPersonAndTemplate(personIdentifierValue, ConsentDomain.BroadConsent,
|
||||||
requestDate);
|
requestDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bundle getGnomDeConsent(String personIdentifierValue, Date requestDate) {
|
public Bundle getGenomDeConsent(String personIdentifierValue, Date requestDate) {
|
||||||
|
|
||||||
return currentConsentForPersonAndTemplate(personIdentifierValue,
|
return currentConsentForPersonAndTemplate(personIdentifierValue,
|
||||||
ConsentDomain.Modelvorhaben64e, requestDate);
|
ConsentDomain.Modelvorhaben64e, requestDate);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|||||||
import de.ukw.ccc.bwhc.dto.MtbFile
|
import de.ukw.ccc.bwhc.dto.MtbFile
|
||||||
import dev.dnpm.etl.processor.*
|
import dev.dnpm.etl.processor.*
|
||||||
import dev.dnpm.etl.processor.config.AppConfigProperties
|
import dev.dnpm.etl.processor.config.AppConfigProperties
|
||||||
|
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||||
import dev.dnpm.etl.processor.monitoring.Report
|
import dev.dnpm.etl.processor.monitoring.Report
|
||||||
import dev.dnpm.etl.processor.monitoring.Request
|
import dev.dnpm.etl.processor.monitoring.Request
|
||||||
@ -32,9 +33,17 @@ import dev.dnpm.etl.processor.output.*
|
|||||||
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
|
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
|
||||||
import dev.dnpm.etl.processor.pseudonym.anonymizeContentWith
|
import dev.dnpm.etl.processor.pseudonym.anonymizeContentWith
|
||||||
import dev.dnpm.etl.processor.pseudonym.pseudonymizeWith
|
import dev.dnpm.etl.processor.pseudonym.pseudonymizeWith
|
||||||
|
import dev.pcvolkmer.mv64e.mtb.ConsentProvision
|
||||||
|
import dev.pcvolkmer.mv64e.mtb.ModelProjectConsent
|
||||||
|
import dev.pcvolkmer.mv64e.mtb.ModelProjectConsentPurpose
|
||||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||||
|
import dev.pcvolkmer.mv64e.mtb.MvhMetadata
|
||||||
|
import dev.pcvolkmer.mv64e.mtb.Provision
|
||||||
import org.apache.commons.codec.binary.Base32
|
import org.apache.commons.codec.binary.Base32
|
||||||
import org.apache.commons.codec.digest.DigestUtils
|
import org.apache.commons.codec.digest.DigestUtils
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource
|
||||||
|
import org.hl7.fhir.r4.model.Bundle
|
||||||
|
import org.hl7.fhir.r4.model.Consent
|
||||||
import org.springframework.context.ApplicationEventPublisher
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -48,7 +57,8 @@ class RequestProcessor(
|
|||||||
private val requestService: RequestService,
|
private val requestService: RequestService,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val applicationEventPublisher: ApplicationEventPublisher,
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
private val appConfigProperties: AppConfigProperties
|
private val appConfigProperties: AppConfigProperties,
|
||||||
|
private val gicsConsentService: GicsConsentService?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun processMtbFile(mtbFile: MtbFile) {
|
fun processMtbFile(mtbFile: MtbFile) {
|
||||||
@ -69,12 +79,84 @@ class RequestProcessor(
|
|||||||
|
|
||||||
fun processMtbFile(mtbFile: Mtb, requestId: RequestId) {
|
fun processMtbFile(mtbFile: Mtb, requestId: RequestId) {
|
||||||
val pid = PatientId(mtbFile.patient.id)
|
val pid = PatientId(mtbFile.patient.id)
|
||||||
|
|
||||||
|
addConsentToMtb(mtbFile)
|
||||||
mtbFile pseudonymizeWith pseudonymizeService
|
mtbFile pseudonymizeWith pseudonymizeService
|
||||||
mtbFile anonymizeContentWith pseudonymizeService
|
mtbFile anonymizeContentWith pseudonymizeService
|
||||||
val request = DnpmV2MtbFileRequest(requestId, transformationService.transform(mtbFile))
|
val request = DnpmV2MtbFileRequest(requestId, transformationService.transform(mtbFile))
|
||||||
saveAndSend(request, pid)
|
saveAndSend(request, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addConsentToMtb(mtbFile: Mtb) {
|
||||||
|
if (gicsConsentService == null) return
|
||||||
|
// init metadata if necessary
|
||||||
|
if (mtbFile.metadata == null) {
|
||||||
|
val mvhMetadata = MvhMetadata.builder().build();
|
||||||
|
mtbFile.metadata = mvhMetadata
|
||||||
|
if (mtbFile.metadata.researchConsents == null) {
|
||||||
|
mtbFile.metadata.researchConsents = mutableListOf()
|
||||||
|
}
|
||||||
|
if (mtbFile.metadata.modelProjectConsent == null) {
|
||||||
|
mtbFile.metadata.modelProjectConsent = ModelProjectConsent()
|
||||||
|
mtbFile.metadata.modelProjectConsent.provisions = mutableListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixme Date should be extracted from mtbFile
|
||||||
|
val consentGnomeDe =
|
||||||
|
gicsConsentService.getGenomDeConsent(mtbFile.patient.id, Date.from(Instant.now()))
|
||||||
|
addGenomeDbProvisions(mtbFile, consentGnomeDe)
|
||||||
|
|
||||||
|
// fixme Date should be extracted from mtbFile
|
||||||
|
val broadConsent =
|
||||||
|
gicsConsentService.getBroadConsent(mtbFile.patient.id, Date.from(Instant.now()))
|
||||||
|
embedBroadConsentResources(mtbFile, broadConsent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun embedBroadConsentResources(
|
||||||
|
mtbFile: Mtb,
|
||||||
|
broadConsent: Bundle
|
||||||
|
) {
|
||||||
|
broadConsent.entry.forEach { it ->
|
||||||
|
mtbFile.metadata.researchConsents.add(mapOf(it.resource.id to it as IBaseResource))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addGenomeDbProvisions(
|
||||||
|
mtbFile: Mtb,
|
||||||
|
consentGnomeDe: Bundle
|
||||||
|
) {
|
||||||
|
consentGnomeDe.entry.forEach { it ->
|
||||||
|
{
|
||||||
|
val consent = it.resource as Consent
|
||||||
|
val provisionComponent = consent.provision.provision.firstOrNull()
|
||||||
|
val provisionCode =
|
||||||
|
provisionComponent?.code?.firstOrNull()?.coding?.firstOrNull()?.code
|
||||||
|
var isValidCode = true
|
||||||
|
if (provisionCode != null) {
|
||||||
|
var modelProjectConsentPurpose: ModelProjectConsentPurpose =
|
||||||
|
ModelProjectConsentPurpose.SEQUENCING
|
||||||
|
if (provisionCode == "Teilnahme") {
|
||||||
|
modelProjectConsentPurpose = ModelProjectConsentPurpose.SEQUENCING
|
||||||
|
} else if (provisionCode == "Fallidentifizierung") {
|
||||||
|
modelProjectConsentPurpose = ModelProjectConsentPurpose.CASE_IDENTIFICATION
|
||||||
|
} else if (provisionCode == "Rekontaktierung") {
|
||||||
|
modelProjectConsentPurpose = ModelProjectConsentPurpose.REIDENTIFICATION
|
||||||
|
} else {
|
||||||
|
isValidCode = false
|
||||||
|
}
|
||||||
|
if (isValidCode) mtbFile.metadata.modelProjectConsent.provisions.add(
|
||||||
|
Provision.builder().type(
|
||||||
|
ConsentProvision.forValue(provisionComponent.type.name)
|
||||||
|
).date(provisionComponent.period.start).purpose(
|
||||||
|
modelProjectConsentPurpose
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun <T> saveAndSend(request: MtbFileRequest<T>, pid: PatientId) {
|
private fun <T> saveAndSend(request: MtbFileRequest<T>, pid: PatientId) {
|
||||||
requestService.save(
|
requestService.save(
|
||||||
Request(
|
Request(
|
||||||
@ -126,7 +208,9 @@ class RequestProcessor(
|
|||||||
|
|
||||||
return null != lastMtbFileRequestForPatient
|
return null != lastMtbFileRequestForPatient
|
||||||
&& !isLastRequestDeletion
|
&& !isLastRequestDeletion
|
||||||
&& lastMtbFileRequestForPatient.fingerprint == fingerprint(pseudonymizedMtbFileRequest)
|
&& lastMtbFileRequestForPatient.fingerprint == fingerprint(
|
||||||
|
pseudonymizedMtbFileRequest
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processDeletion(patientId: PatientId, isConsented: TtpConsentStatus) {
|
fun processDeletion(patientId: PatientId, isConsented: TtpConsentStatus) {
|
||||||
|
@ -22,6 +22,7 @@ package dev.dnpm.etl.processor.pseudonym
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import de.ukw.ccc.bwhc.dto.*
|
import de.ukw.ccc.bwhc.dto.*
|
||||||
import de.ukw.ccc.bwhc.dto.Patient
|
import de.ukw.ccc.bwhc.dto.Patient
|
||||||
|
import dev.dnpm.etl.processor.config.JacksonConfig
|
||||||
import dev.pcvolkmer.mv64e.mtb.*
|
import dev.pcvolkmer.mv64e.mtb.*
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Nested
|
import org.junit.jupiter.api.Nested
|
||||||
@ -39,6 +40,9 @@ import java.util.*
|
|||||||
|
|
||||||
@ExtendWith(MockitoExtension::class)
|
@ExtendWith(MockitoExtension::class)
|
||||||
class ExtensionsTest {
|
class ExtensionsTest {
|
||||||
|
fun getObjectMapper() : ObjectMapper {
|
||||||
|
return JacksonConfig().objectMapper()
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
inner class UsingBwhcDatamodel {
|
inner class UsingBwhcDatamodel {
|
||||||
@ -46,13 +50,14 @@ class ExtensionsTest {
|
|||||||
val FAKE_MTB_FILE_PATH = "fake_MTBFile.json"
|
val FAKE_MTB_FILE_PATH = "fake_MTBFile.json"
|
||||||
val CLEAN_PATIENT_ID = "5dad2f0b-49c6-47d8-a952-7b9e9e0f7549"
|
val CLEAN_PATIENT_ID = "5dad2f0b-49c6-47d8-a952-7b9e9e0f7549"
|
||||||
|
|
||||||
|
|
||||||
private fun fakeMtbFile(): MtbFile {
|
private fun fakeMtbFile(): MtbFile {
|
||||||
val mtbFile = ClassPathResource(FAKE_MTB_FILE_PATH).inputStream
|
val mtbFile = ClassPathResource(FAKE_MTB_FILE_PATH).inputStream
|
||||||
return ObjectMapper().readValue(mtbFile, MtbFile::class.java)
|
return getObjectMapper().readValue(mtbFile, MtbFile::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MtbFile.serialized(): String {
|
private fun MtbFile.serialized(): String {
|
||||||
return ObjectMapper().writeValueAsString(this)
|
return getObjectMapper().writeValueAsString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -211,11 +216,11 @@ class ExtensionsTest {
|
|||||||
|
|
||||||
private fun fakeMtbFile(): Mtb {
|
private fun fakeMtbFile(): Mtb {
|
||||||
val mtbFile = ClassPathResource(FAKE_MTB_FILE_PATH).inputStream
|
val mtbFile = ClassPathResource(FAKE_MTB_FILE_PATH).inputStream
|
||||||
return ObjectMapper().readValue(mtbFile, Mtb::class.java)
|
return getObjectMapper().readValue(mtbFile, Mtb::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Mtb.serialized(): String {
|
private fun Mtb.serialized(): String {
|
||||||
return ObjectMapper().writeValueAsString(this)
|
return getObjectMapper().writeValueAsString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -25,6 +25,7 @@ import dev.dnpm.etl.processor.Fingerprint
|
|||||||
import dev.dnpm.etl.processor.PatientId
|
import dev.dnpm.etl.processor.PatientId
|
||||||
import dev.dnpm.etl.processor.PatientPseudonym
|
import dev.dnpm.etl.processor.PatientPseudonym
|
||||||
import dev.dnpm.etl.processor.config.AppConfigProperties
|
import dev.dnpm.etl.processor.config.AppConfigProperties
|
||||||
|
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||||
import dev.dnpm.etl.processor.monitoring.Request
|
import dev.dnpm.etl.processor.monitoring.Request
|
||||||
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
||||||
@ -59,7 +60,7 @@ class RequestProcessorTest {
|
|||||||
private lateinit var requestService: RequestService
|
private lateinit var requestService: RequestService
|
||||||
private lateinit var applicationEventPublisher: ApplicationEventPublisher
|
private lateinit var applicationEventPublisher: ApplicationEventPublisher
|
||||||
private lateinit var appConfigProperties: AppConfigProperties
|
private lateinit var appConfigProperties: AppConfigProperties
|
||||||
|
private lateinit var gicsConsentService : GicsConsentService
|
||||||
private lateinit var requestProcessor: RequestProcessor
|
private lateinit var requestProcessor: RequestProcessor
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@ -68,7 +69,8 @@ class RequestProcessorTest {
|
|||||||
@Mock transformationService: TransformationService,
|
@Mock transformationService: TransformationService,
|
||||||
@Mock sender: RestMtbFileSender,
|
@Mock sender: RestMtbFileSender,
|
||||||
@Mock requestService: RequestService,
|
@Mock requestService: RequestService,
|
||||||
@Mock applicationEventPublisher: ApplicationEventPublisher
|
@Mock applicationEventPublisher: ApplicationEventPublisher,
|
||||||
|
@Mock gicsConsentService: GicsConsentService
|
||||||
) {
|
) {
|
||||||
this.pseudonymizeService = pseudonymizeService
|
this.pseudonymizeService = pseudonymizeService
|
||||||
this.transformationService = transformationService
|
this.transformationService = transformationService
|
||||||
@ -76,6 +78,7 @@ class RequestProcessorTest {
|
|||||||
this.requestService = requestService
|
this.requestService = requestService
|
||||||
this.applicationEventPublisher = applicationEventPublisher
|
this.applicationEventPublisher = applicationEventPublisher
|
||||||
this.appConfigProperties = AppConfigProperties(null)
|
this.appConfigProperties = AppConfigProperties(null)
|
||||||
|
this.gicsConsentService = gicsConsentService
|
||||||
|
|
||||||
val objectMapper = ObjectMapper()
|
val objectMapper = ObjectMapper()
|
||||||
|
|
||||||
@ -86,7 +89,8 @@ class RequestProcessorTest {
|
|||||||
requestService,
|
requestService,
|
||||||
objectMapper,
|
objectMapper,
|
||||||
applicationEventPublisher,
|
applicationEventPublisher,
|
||||||
appConfigProperties
|
appConfigProperties,
|
||||||
|
gicsConsentService
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user