diff --git a/src/main/java/dev/dnpm/etl/processor/consent/BaseConsentService.java b/src/main/java/dev/dnpm/etl/processor/consent/BaseConsentService.java index 31a75e7..9af2aa3 100644 --- a/src/main/java/dev/dnpm/etl/processor/consent/BaseConsentService.java +++ b/src/main/java/dev/dnpm/etl/processor/consent/BaseConsentService.java @@ -1,5 +1,9 @@ package dev.dnpm.etl.processor.consent; +import ca.uhn.fhir.context.FhirContext; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import dev.dnpm.etl.processor.config.GIcsConfigProperties; import dev.pcvolkmer.mv64e.mtb.ConsentProvision; import dev.pcvolkmer.mv64e.mtb.ModelProjectConsentPurpose; @@ -8,7 +12,6 @@ import dev.pcvolkmer.mv64e.mtb.Provision; import java.io.IOException; import java.util.HashMap; import java.util.List; -import java.util.Map; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Consent; @@ -20,24 +23,38 @@ import org.slf4j.LoggerFactory; public abstract class BaseConsentService implements ICheckConsent { protected final GIcsConfigProperties gIcsConfigProperties; - protected Logger logger = LoggerFactory.getLogger(BaseConsentService.class); - public BaseConsentService(GIcsConfigProperties gIcsConfigProperties) { + private final ObjectMapper objectMapper; + protected Logger logger = LoggerFactory.getLogger(BaseConsentService.class); + static FhirContext fhirCtx = FhirContext.forR4(); + + public BaseConsentService(GIcsConfigProperties gIcsConfigProperties, + ObjectMapper objectMapper) { this.gIcsConfigProperties = gIcsConfigProperties; + this.objectMapper = objectMapper; } public void embedBroadConsentResources(Mtb mtbFile, Bundle broadConsent) { + for (Bundle.BundleEntryComponent entry : broadConsent.getEntry()) { Resource resource = entry.getResource(); if (resource instanceof Consent) { - Map consentMap = new HashMap<>(); - consentMap.put(resource.getIdElement().getIdPart(), resource); - mtbFile.getMetadata().getResearchConsents().add(consentMap); + // since jackson convertValue does not work here, + // we need another step to back to string, before we convert to object map + var asJsonString = fhirCtx.newJsonParser().encodeResourceToString(resource); + try { + var mapOfJson = objectMapper.readValue(asJsonString, + new TypeReference>() { + }); + mtbFile.getMetadata().getResearchConsents().add(mapOfJson); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } } } - public void addGenomeDbProvisions(Mtb mtbFile, Bundle consentGnomeDe) { + public void addGenomeDbProvisions(Mtb mtbFile, Bundle consentGnomeDe) { for (Bundle.BundleEntryComponent entry : consentGnomeDe.getEntry()) { Resource resource = entry.getResource(); if (!(resource instanceof Consent consentFhirResource)) { @@ -67,7 +84,8 @@ public abstract class BaseConsentService implements ICheckConsent { if (ModelProjectConsentPurpose.SEQUENCING.equals(modelProjectConsentPurpose)) { // CONVENTION: wrapping date is date of SEQUENCING consent - mtbFile.getMetadata().getModelProjectConsent().setDate(consentFhirResource.getDateTime()); + mtbFile.getMetadata().getModelProjectConsent() + .setDate(consentFhirResource.getDateTime()); } Provision provision = Provision.builder() @@ -79,12 +97,15 @@ public abstract class BaseConsentService implements ICheckConsent { mtbFile.getMetadata().getModelProjectConsent().getProvisions().add(provision); } catch (IOException ioe) { - logger.error("Provision code '" + provisionCode + "' is unknown and cannot be mapped.", ioe.toString()); + logger.error( + "Provision code '" + provisionCode + "' is unknown and cannot be mapped.", + ioe.toString()); } } if (!mtbFile.getMetadata().getModelProjectConsent().getProvisions().isEmpty()) { - mtbFile.getMetadata().getModelProjectConsent().setVersion(gIcsConfigProperties.getGenomeDeConsentVersion()); + mtbFile.getMetadata().getModelProjectConsent() + .setVersion(gIcsConfigProperties.getGenomeDeConsentVersion()); } } } diff --git a/src/main/java/dev/dnpm/etl/processor/consent/GicsConsentService.java b/src/main/java/dev/dnpm/etl/processor/consent/GicsConsentService.java index 937bea0..40f1b84 100644 --- a/src/main/java/dev/dnpm/etl/processor/consent/GicsConsentService.java +++ b/src/main/java/dev/dnpm/etl/processor/consent/GicsConsentService.java @@ -2,6 +2,7 @@ package dev.dnpm.etl.processor.consent; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.DataFormatException; +import com.fasterxml.jackson.databind.ObjectMapper; import dev.dnpm.etl.processor.config.AppFhirConfig; import dev.dnpm.etl.processor.config.GIcsConfigProperties; import java.util.Date; @@ -51,8 +52,8 @@ public class GicsConsentService extends BaseConsentService { private String url; public GicsConsentService(GIcsConfigProperties gIcsConfigProperties, - RetryTemplate retryTemplate, RestTemplate restTemplate, AppFhirConfig appFhirConfig) { - super(gIcsConfigProperties); + RetryTemplate retryTemplate, RestTemplate restTemplate, AppFhirConfig appFhirConfig, ObjectMapper objectMapper) { + super(gIcsConfigProperties,objectMapper); this.retryTemplate = retryTemplate; this.restTemplate = restTemplate; diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt index d5a3bf3..fd559a5 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt @@ -184,12 +184,13 @@ class AppConfiguration { @Bean @ConditionalOnProperty(name = ["app.consent.gics.enabled"], havingValue = "true") fun gicsConsentService( gIcsConfigProperties: GIcsConfigProperties, - retryTemplate: RetryTemplate, restTemplate: RestTemplate, appFhirConfig: AppFhirConfig): ICheckConsent { + retryTemplate: RetryTemplate, restTemplate: RestTemplate, appFhirConfig: AppFhirConfig, getObjectMapper: ObjectMapper): ICheckConsent { return GicsConsentService( gIcsConfigProperties, retryTemplate, restTemplate, - appFhirConfig + appFhirConfig, + getObjectMapper ) } 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 b2b4dc7..77f3399 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt @@ -25,7 +25,6 @@ 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 -import org.hl7.fhir.r4.model.Consent /** Replaces patient ID with generated patient pseudonym * @@ -295,11 +294,12 @@ infix fun Mtb.pseudonymizeWith(pseudonymizeService: PseudonymizeService) { this.metadata?.researchConsents?.forEach { it -> val entry = it ?: return@forEach - val key = entry.keys.first() - val consent = entry[key] as? Consent ?: return@forEach - val patRef= "Patient/$patientPseudonym" - consent.patient?.setReference(patRef) - consent.patient?.display = null + if (entry.contains("patient")) { + // here we expect only a patient reference any other data like display + // need to be removed, since may contain unsecure data + entry.remove("patient") + entry["patient"] = mapOf("reference" to "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 1f6bed4..7965a6b 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt @@ -36,6 +36,7 @@ import dev.dnpm.etl.processor.pseudonym.anonymizeContentWith import dev.dnpm.etl.processor.pseudonym.ensureMetaDataIsInitialized import dev.dnpm.etl.processor.pseudonym.pseudonymizeWith import dev.pcvolkmer.mv64e.mtb.Mtb +import dev.pcvolkmer.mv64e.mtb.MvhSubmissionType import org.apache.commons.codec.binary.Base32 import org.apache.commons.codec.digest.DigestUtils import org.hl7.fhir.r4.model.Consent @@ -122,6 +123,10 @@ class RequestProcessor( ) consentService.addGenomeDbProvisions(mtbFile, genomeDeConsent) + + // fixme: currently we do not have information about submission type + if (!genomeDeConsent.entry.isEmpty()) mtbFile.metadata.type = MvhSubmissionType.INITIAL + consentService.embedBroadConsentResources(mtbFile, broadConsent) val broadConsentStatus = consentService.getProvisionTypeByPolicyCode( diff --git a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt index 894ab01..dcbc4d5 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt @@ -251,7 +251,8 @@ class ExtensionsTest { private fun addConsentData(mtbFile: Mtb) { val gIcsConfigProperties = GIcsConfigProperties("", "", "", true) - val baseConsentService = object : BaseConsentService(gIcsConfigProperties) { + val baseConsentService = object : BaseConsentService(gIcsConfigProperties, + JacksonConfig().objectMapper()) { override fun getTtpBroadConsentStatus(personIdentifierValue: String?): TtpConsentStatus? { throw NotImplementedError("dummy") }