mirror of
https://github.com/pcvolkmer/mv64e-etl-processor
synced 2025-09-13 17:02:52 +00:00
refactor: remove obsolete bwHC data model V1.0 (#129)
This commit is contained in:
@@ -24,7 +24,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ConfigurationProperties(AppConfigProperties.NAME)
|
||||
data class AppConfigProperties(
|
||||
var bwhcUri: String?,
|
||||
var transformations: List<TransformationProperties> = listOf(),
|
||||
var maxRetryAttempts: Int = 3,
|
||||
var duplicationDetection: Boolean = true,
|
||||
@@ -128,8 +127,7 @@ data class GIcsConfigProperties(
|
||||
data class RestTargetProperties(
|
||||
val uri: String?,
|
||||
val username: String?,
|
||||
val password: String?,
|
||||
val isBwhc: Boolean = false,
|
||||
val password: String?
|
||||
) {
|
||||
companion object {
|
||||
const val NAME = "app.rest"
|
||||
|
@@ -24,7 +24,6 @@ import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
||||
import dev.dnpm.etl.processor.monitoring.ReportService
|
||||
import dev.dnpm.etl.processor.monitoring.RestConnectionCheckService
|
||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||
import dev.dnpm.etl.processor.output.RestBwhcMtbFileSender
|
||||
import dev.dnpm.etl.processor.output.RestDipMtbFileSender
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
@@ -57,11 +56,6 @@ class AppRestConfiguration {
|
||||
retryTemplate: RetryTemplate,
|
||||
reportService: ReportService,
|
||||
): MtbFileSender {
|
||||
if (restTargetProperties.isBwhc) {
|
||||
logger.info("Selected 'RestBwhcMtbFileSender'")
|
||||
return RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService)
|
||||
}
|
||||
|
||||
logger.info("Selected 'RestDipMtbFileSender'")
|
||||
return RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService)
|
||||
}
|
||||
|
@@ -20,13 +20,13 @@
|
||||
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.CustomMediaType
|
||||
import dev.dnpm.etl.processor.PatientId
|
||||
import dev.dnpm.etl.processor.RequestId
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||
import dev.pcvolkmer.mv64e.mtb.ConsentProvision
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.http.MediaType
|
||||
@@ -40,7 +40,7 @@ class KafkaInputListener(
|
||||
|
||||
override fun onMessage(record: ConsumerRecord<String, String>) {
|
||||
when (guessMimeType(record)) {
|
||||
MediaType.APPLICATION_JSON_VALUE -> handleBwhcMessage(record)
|
||||
MediaType.APPLICATION_JSON_VALUE -> handleDnpmV2Message(record)
|
||||
CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON_VALUE -> handleDnpmV2Message(record)
|
||||
else -> {
|
||||
/* ignore other messages */
|
||||
@@ -57,8 +57,11 @@ class KafkaInputListener(
|
||||
return record.headers().headers("contentType")?.firstOrNull()?.value().contentToString()
|
||||
}
|
||||
|
||||
private fun handleBwhcMessage(record: ConsumerRecord<String, String>) {
|
||||
val mtbFile = objectMapper.readValue(record.value(), MtbFile::class.java)
|
||||
private fun handleDnpmV2Message(record: ConsumerRecord<String, String>) {
|
||||
// Do not handle DNPM-V2 for now
|
||||
logger.warn("Ignoring MTB File in DNPM V2 format: Not implemented yet")
|
||||
|
||||
val mtbFile = objectMapper.readValue(record.value(), Mtb::class.java)
|
||||
val patientId = PatientId(mtbFile.patient.id)
|
||||
val firstRequestIdHeader = record.headers().headers("requestId")?.firstOrNull()
|
||||
val requestId = if (null != firstRequestIdHeader) {
|
||||
@@ -67,7 +70,8 @@ class KafkaInputListener(
|
||||
RequestId("")
|
||||
}
|
||||
|
||||
if (mtbFile.consent.status == Consent.Status.ACTIVE) {
|
||||
// TODO: Use MV Consent for now - needs to be replaced with proper consent evaluation
|
||||
if (mtbFile.metadata.modelProjectConsent.provisions.filter { it.type == ConsentProvision.PERMIT }.isNotEmpty()) {
|
||||
logger.debug("Accepted MTB File for processing")
|
||||
if (requestId.isBlank()) {
|
||||
requestProcessor.processMtbFile(mtbFile)
|
||||
@@ -88,9 +92,4 @@ class KafkaInputListener(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDnpmV2Message(record: ConsumerRecord<String, String>) {
|
||||
// Do not handle DNPM-V2 for now
|
||||
logger.warn("Ignoring MTB File in DNPM V2 format: Not implemented yet")
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -19,8 +19,6 @@
|
||||
|
||||
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.CustomMediaType
|
||||
import dev.dnpm.etl.processor.PatientId
|
||||
import dev.dnpm.etl.processor.consent.IGetConsent
|
||||
@@ -46,23 +44,7 @@ class MtbFileRestController(
|
||||
return ResponseEntity.ok("Test")
|
||||
}
|
||||
|
||||
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
|
||||
fun mtbFile(@RequestBody mtbFile: MtbFile): ResponseEntity<Unit> {
|
||||
val consentStatusBooleanPair = checkConsentStatus(mtbFile)
|
||||
val ttpConsentStatus = consentStatusBooleanPair.first
|
||||
val isConsentOK = consentStatusBooleanPair.second
|
||||
if (isConsentOK) {
|
||||
logger.debug("Accepted MTB File (bwHC V1) for processing")
|
||||
requestProcessor.processMtbFile(mtbFile)
|
||||
} else {
|
||||
logger.debug("Accepted MTB File (bwHC V1) and process deletion")
|
||||
val patientId = PatientId(mtbFile.patient.id)
|
||||
requestProcessor.processDeletion(patientId, ttpConsentStatus)
|
||||
}
|
||||
return ResponseEntity.accepted().build()
|
||||
}
|
||||
|
||||
@PostMapping(consumes = [CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON_VALUE])
|
||||
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE, CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON_VALUE])
|
||||
fun mtbFile(@RequestBody mtbFile: Mtb): ResponseEntity<Unit> {
|
||||
logger.debug("Accepted MTB File (DNPM V2) for processing")
|
||||
requestProcessor.processMtbFile(mtbFile)
|
||||
@@ -76,17 +58,4 @@ class MtbFileRestController(
|
||||
return ResponseEntity.accepted().build()
|
||||
}
|
||||
|
||||
private fun checkConsentStatus(mtbFile: MtbFile): Pair<TtpConsentStatus, Boolean> {
|
||||
var ttpConsentStatus = iGetConsent.getTtpBroadConsentStatus(mtbFile.patient.id)
|
||||
|
||||
val isConsentOK = (ttpConsentStatus == TtpConsentStatus.UNKNOWN_CHECK_FILE && mtbFile.consent.status == Consent.Status.ACTIVE)
|
||||
|| ttpConsentStatus == TtpConsentStatus.BROAD_CONSENT_GIVEN
|
||||
|
||||
if (ttpConsentStatus == TtpConsentStatus.UNKNOWN_CHECK_FILE && mtbFile.consent.status == Consent.Status.REJECTED) {
|
||||
// in case ttp check is disabled - we propagate rejected status anyway
|
||||
ttpConsentStatus = TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED
|
||||
}
|
||||
return Pair(ttpConsentStatus, isConsentOK)
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -128,15 +128,11 @@ class RestConnectionCheckService(
|
||||
fun check() {
|
||||
result = try {
|
||||
val available = restTemplate.getForEntity(
|
||||
if (restTargetProperties.isBwhc) {
|
||||
UriComponentsBuilder.fromUriString(restTargetProperties.uri.toString()).path("").toUriString()
|
||||
} else {
|
||||
UriComponentsBuilder.fromUriString(restTargetProperties.uri.toString())
|
||||
.pathSegment("mtb")
|
||||
.pathSegment("kaplan-meier")
|
||||
.pathSegment("config")
|
||||
.toUriString()
|
||||
},
|
||||
UriComponentsBuilder.fromUriString(restTargetProperties.uri.toString())
|
||||
.pathSegment("mtb")
|
||||
.pathSegment("kaplan-meier")
|
||||
.pathSegment("config")
|
||||
.toUriString(),
|
||||
String::class.java
|
||||
).statusCode == HttpStatus.OK
|
||||
|
||||
@@ -267,4 +263,4 @@ class GIcsConnectionCheckService(
|
||||
override fun connectionAvailable(): ConnectionCheckResult.GIcsConnectionCheckResult {
|
||||
return this.result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,11 @@
|
||||
package dev.dnpm.etl.processor.output
|
||||
|
||||
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.CustomMediaType
|
||||
import dev.dnpm.etl.processor.config.KafkaProperties
|
||||
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
import dev.pcvolkmer.mv64e.mtb.MvhMetadata
|
||||
import org.apache.kafka.clients.producer.ProducerRecord
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.http.MediaType
|
||||
@@ -50,9 +50,6 @@ class KafkaMtbFileSender(
|
||||
objectMapper.writeValueAsString(request)
|
||||
)
|
||||
when (request) {
|
||||
is BwhcV1MtbFileRequest -> record.headers()
|
||||
.add("contentType", MediaType.APPLICATION_JSON_VALUE.toByteArray())
|
||||
|
||||
is DnpmV2MtbFileRequest -> record.headers()
|
||||
.add(
|
||||
"contentType",
|
||||
@@ -75,13 +72,8 @@ class KafkaMtbFileSender(
|
||||
}
|
||||
|
||||
override fun send(request: DeleteRequest): MtbFileSender.Response {
|
||||
val dummyMtbFile = MtbFile.builder()
|
||||
.withConsent(
|
||||
Consent.builder()
|
||||
.withPatient(request.patientId.value)
|
||||
.withStatus(Consent.Status.REJECTED)
|
||||
.build()
|
||||
)
|
||||
val dummyMtbFile = Mtb.builder()
|
||||
.metadata(MvhMetadata())
|
||||
.build()
|
||||
|
||||
return try {
|
||||
@@ -92,7 +84,7 @@ class KafkaMtbFileSender(
|
||||
key(request),
|
||||
// Always use old BwhcV1FileRequest with Consent REJECT
|
||||
objectMapper.writeValueAsString(
|
||||
BwhcV1MtbFileRequest(
|
||||
DnpmV2MtbFileRequest(
|
||||
request.requestId,
|
||||
dummyMtbFile
|
||||
)
|
||||
@@ -119,7 +111,6 @@ class KafkaMtbFileSender(
|
||||
|
||||
private fun key(request: MtbRequest): String {
|
||||
return when (request) {
|
||||
is BwhcV1MtbFileRequest -> "{\"pid\": \"${request.content.patient.id}\"}"
|
||||
is DnpmV2MtbFileRequest -> "{\"pid\": \"${request.content.patient.id}\"}"
|
||||
is DeleteRequest -> "{\"pid\": \"${request.patientId.value}\"}"
|
||||
else -> throw IllegalArgumentException("Unsupported request type: ${request::class.simpleName}")
|
||||
|
@@ -19,7 +19,6 @@
|
||||
|
||||
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.pcvolkmer.mv64e.mtb.Mtb
|
||||
@@ -35,15 +34,6 @@ sealed interface MtbFileRequest<out T> : MtbRequest {
|
||||
fun patientPseudonym(): PatientPseudonym
|
||||
}
|
||||
|
||||
data class BwhcV1MtbFileRequest(
|
||||
override val requestId: RequestId,
|
||||
override val content: MtbFile
|
||||
) : MtbFileRequest<MtbFile> {
|
||||
override fun patientPseudonym(): PatientPseudonym {
|
||||
return PatientPseudonym(content.patient.id)
|
||||
}
|
||||
}
|
||||
|
||||
data class DnpmV2MtbFileRequest(
|
||||
override val requestId: RequestId,
|
||||
override val content: Mtb
|
||||
|
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of ETL-Processor
|
||||
*
|
||||
* Copyright (c) 2025 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.output
|
||||
|
||||
import dev.dnpm.etl.processor.PatientPseudonym
|
||||
import dev.dnpm.etl.processor.config.RestTargetProperties
|
||||
import dev.dnpm.etl.processor.monitoring.ReportService
|
||||
import org.springframework.retry.support.RetryTemplate
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import org.springframework.web.util.UriComponentsBuilder
|
||||
|
||||
class RestBwhcMtbFileSender(
|
||||
restTemplate: RestTemplate,
|
||||
private val restTargetProperties: RestTargetProperties,
|
||||
retryTemplate: RetryTemplate,
|
||||
reportService: ReportService,
|
||||
) : RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) {
|
||||
|
||||
override fun sendUrl(): String {
|
||||
return UriComponentsBuilder
|
||||
.fromUriString(restTargetProperties.uri.toString())
|
||||
.pathSegment("MTBFile")
|
||||
.toUriString()
|
||||
}
|
||||
|
||||
override fun deleteUrl(patientId: PatientPseudonym): String {
|
||||
return UriComponentsBuilder
|
||||
.fromUriString(restTargetProperties.uri.toString())
|
||||
.pathSegment("Patient")
|
||||
.pathSegment(patientId.value)
|
||||
.toUriString()
|
||||
}
|
||||
|
||||
}
|
@@ -108,7 +108,6 @@ abstract class RestMtbFileSender(
|
||||
val password = restTargetProperties.password
|
||||
val headers = HttpHeaders()
|
||||
headers.contentType = when (request) {
|
||||
is BwhcV1MtbFileRequest -> MediaType.APPLICATION_JSON
|
||||
is DnpmV2MtbFileRequest -> CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
|
||||
else -> MediaType.APPLICATION_JSON
|
||||
}
|
||||
|
@@ -19,217 +19,12 @@
|
||||
|
||||
package dev.dnpm.etl.processor.pseudonym
|
||||
|
||||
import de.ukw.ccc.bwhc.dto.MtbFile
|
||||
import dev.dnpm.etl.processor.PatientId
|
||||
import dev.pcvolkmer.mv64e.mtb.ModelProjectConsent
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
import dev.pcvolkmer.mv64e.mtb.MvhMetadata
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
|
||||
/** Replaces patient ID with generated patient pseudonym
|
||||
*
|
||||
* @param pseudonymizeService The pseudonymizeService to be used
|
||||
* @return The MTB file containing patient pseudonymes
|
||||
*/
|
||||
infix fun MtbFile.pseudonymizeWith(pseudonymizeService: PseudonymizeService) {
|
||||
val patientPseudonym = pseudonymizeService.patientPseudonym(PatientId(this.patient.id)).value
|
||||
|
||||
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
|
||||
it.tumorMorphology?.patient = patientPseudonym
|
||||
}
|
||||
this.lastGuidelineTherapies?.forEach { it.patient = patientPseudonym }
|
||||
this.molecularPathologyFindings?.forEach { it.patient = patientPseudonym }
|
||||
this.molecularTherapies?.forEach { molecularTherapy ->
|
||||
molecularTherapy.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.responses?.forEach { it.patient = patientPseudonym }
|
||||
this.studyInclusionRequests?.forEach { it.patient = patientPseudonym }
|
||||
this.specimens?.forEach { it.patient = patientPseudonym }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new hash of content IDs with given prefix except for patient IDs
|
||||
*
|
||||
* @param pseudonymizeService The pseudonymizeService to be used
|
||||
* @return The MTB file containing rehashed content IDs
|
||||
*/
|
||||
infix fun MtbFile.anonymizeContentWith(pseudonymizeService: PseudonymizeService) {
|
||||
val prefix = pseudonymizeService.prefix()
|
||||
|
||||
fun anonymize(id: String): String {
|
||||
val hash = DigestUtils.sha256Hex("$prefix-$id").substring(0, 41).lowercase()
|
||||
return "$prefix$hash"
|
||||
}
|
||||
|
||||
this.episode?.apply {
|
||||
id = id?.let {
|
||||
anonymize(it)
|
||||
}
|
||||
}
|
||||
this.carePlans?.onEach { carePlan ->
|
||||
carePlan?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
diagnosis = diagnosis?.let { anonymize(it) }
|
||||
geneticCounsellingRequest = geneticCounsellingRequest?.let { anonymize(it) }
|
||||
rebiopsyRequests = rebiopsyRequests.map { it?.let { anonymize(it) } }
|
||||
recommendations = recommendations.map { it?.let { anonymize(it) } }
|
||||
studyInclusionRequests = studyInclusionRequests.map { it?.let { anonymize(it) } }
|
||||
}
|
||||
}
|
||||
this.claims?.onEach { claim ->
|
||||
claim?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
therapy = therapy?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.claimResponses?.onEach { claimResponse ->
|
||||
claimResponse?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
claim = claim?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.consent?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
this.diagnoses?.onEach { diagnosis ->
|
||||
diagnosis?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
histologyResults = histologyResults?.map { it?.let { anonymize(it) } }
|
||||
}
|
||||
}
|
||||
this.ecogStatus?.onEach { ecogStatus ->
|
||||
ecogStatus?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.familyMemberDiagnoses?.onEach { familyMemberDiagnosis ->
|
||||
familyMemberDiagnosis?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.geneticCounsellingRequests?.onEach { geneticCounsellingRequest ->
|
||||
geneticCounsellingRequest?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.histologyReevaluationRequests?.onEach { histologyReevaluationRequest ->
|
||||
histologyReevaluationRequest?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.histologyReports?.onEach { histologyReport ->
|
||||
histologyReport?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
tumorMorphology?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
tumorCellContent?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lastGuidelineTherapies?.onEach { lastGuidelineTherapy ->
|
||||
lastGuidelineTherapy?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
diagnosis = diagnosis?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.molecularPathologyFindings?.onEach { molecularPathologyFinding ->
|
||||
molecularPathologyFinding?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.molecularTherapies?.onEach { molecularTherapy ->
|
||||
molecularTherapy?.apply {
|
||||
history?.onEach { history ->
|
||||
history?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
basedOn = basedOn?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ngsReports?.onEach { ngsReport ->
|
||||
ngsReport?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
tumorCellContent?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
simpleVariants?.onEach { simpleVariant ->
|
||||
simpleVariant?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.previousGuidelineTherapies?.onEach { previousGuidelineTherapy ->
|
||||
previousGuidelineTherapy?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
diagnosis = diagnosis?.let { anonymize(it) }
|
||||
medication.forEach { medication ->
|
||||
medication?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.rebiopsyRequests?.onEach { rebiopsyRequest ->
|
||||
rebiopsyRequest?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
specimen = specimen?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.recommendations?.onEach { recommendation ->
|
||||
recommendation?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
diagnosis = diagnosis?.let { anonymize(it) }
|
||||
ngsReport = ngsReport?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.responses?.onEach { response ->
|
||||
response?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
therapy = therapy?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.studyInclusionRequests?.onEach { studyInclusionRequest ->
|
||||
studyInclusionRequest?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
reason = reason?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
this.specimens?.onEach { specimen ->
|
||||
specimen?.apply {
|
||||
id = id?.let { anonymize(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Replaces patient ID with generated patient pseudonym
|
||||
*
|
||||
* @since 0.11.0
|
||||
@@ -353,4 +148,4 @@ fun Mtb.ensureMetaDataIsInitialized() {
|
||||
infix fun Mtb.addGenomDeTan(pseudonymizeService: PseudonymizeService)
|
||||
{
|
||||
this.metadata.transferTan = pseudonymizeService.genomDeTan(PatientId(this.patient.id))
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@
|
||||
package dev.dnpm.etl.processor.services
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.ukw.ccc.bwhc.dto.MtbFile
|
||||
import dev.dnpm.etl.processor.*
|
||||
import dev.dnpm.etl.processor.config.AppConfigProperties
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
@@ -28,7 +27,10 @@ import dev.dnpm.etl.processor.monitoring.Report
|
||||
import dev.dnpm.etl.processor.monitoring.Request
|
||||
import dev.dnpm.etl.processor.monitoring.RequestStatus
|
||||
import dev.dnpm.etl.processor.monitoring.RequestType
|
||||
import dev.dnpm.etl.processor.output.*
|
||||
import dev.dnpm.etl.processor.output.DeleteRequest
|
||||
import dev.dnpm.etl.processor.output.DnpmV2MtbFileRequest
|
||||
import dev.dnpm.etl.processor.output.MtbFileRequest
|
||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
|
||||
import dev.dnpm.etl.processor.pseudonym.addGenomDeTan
|
||||
import dev.dnpm.etl.processor.pseudonym.anonymizeContentWith
|
||||
@@ -42,7 +44,6 @@ import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.stereotype.Service
|
||||
import java.lang.RuntimeException
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
||||
@@ -59,17 +60,6 @@ class RequestProcessor(
|
||||
) {
|
||||
|
||||
private var logger: Logger = LoggerFactory.getLogger("RequestProcessor")
|
||||
fun processMtbFile(mtbFile: MtbFile) {
|
||||
processMtbFile(mtbFile, randomRequestId())
|
||||
}
|
||||
|
||||
fun processMtbFile(mtbFile: MtbFile, requestId: RequestId) {
|
||||
val pid = PatientId(mtbFile.patient.id)
|
||||
mtbFile pseudonymizeWith pseudonymizeService
|
||||
mtbFile anonymizeContentWith pseudonymizeService
|
||||
val request = BwhcV1MtbFileRequest(requestId, transformationService.transform(mtbFile))
|
||||
saveAndSend(request, pid)
|
||||
}
|
||||
|
||||
fun processMtbFile(mtbFile: Mtb) {
|
||||
processMtbFile(mtbFile, randomRequestId())
|
||||
@@ -144,7 +134,6 @@ class RequestProcessor(
|
||||
|
||||
private fun <T> isDuplication(pseudonymizedMtbFileRequest: MtbFileRequest<T>): Boolean {
|
||||
val patientPseudonym = when (pseudonymizedMtbFileRequest) {
|
||||
is BwhcV1MtbFileRequest -> PatientPseudonym(pseudonymizedMtbFileRequest.content.patient.id)
|
||||
is DnpmV2MtbFileRequest -> PatientPseudonym(pseudonymizedMtbFileRequest.content.patient.id)
|
||||
}
|
||||
|
||||
@@ -214,7 +203,6 @@ class RequestProcessor(
|
||||
|
||||
private fun <T> fingerprint(request: MtbFileRequest<T>): Fingerprint {
|
||||
return when (request) {
|
||||
is BwhcV1MtbFileRequest -> fingerprint(objectMapper.writeValueAsString(request.content))
|
||||
is DnpmV2MtbFileRequest -> fingerprint(objectMapper.writeValueAsString(request.content))
|
||||
}
|
||||
}
|
||||
|
@@ -22,14 +22,9 @@ package dev.dnpm.etl.processor.services
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.jayway.jsonpath.JsonPath
|
||||
import com.jayway.jsonpath.PathNotFoundException
|
||||
import de.ukw.ccc.bwhc.dto.MtbFile
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
|
||||
class TransformationService(private val objectMapper: ObjectMapper, private val transformations: List<Transformation>) {
|
||||
fun transform(mtbFile: MtbFile): MtbFile {
|
||||
val json = transform(objectMapper.writeValueAsString(mtbFile))
|
||||
return objectMapper.readValue(json, MtbFile::class.java)
|
||||
}
|
||||
|
||||
fun transform(mtbFile: Mtb): Mtb {
|
||||
val json = transform(objectMapper.writeValueAsString(mtbFile))
|
||||
|
Reference in New Issue
Block a user