mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-17 12:52:54 +00:00
fix: added missing genomeDe consent version and date; moved embedding consent resources into base class of GicsConsentService
This commit is contained in:
@ -0,0 +1,91 @@
|
||||
package dev.dnpm.etl.processor.consent;
|
||||
|
||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties;
|
||||
import dev.pcvolkmer.mv64e.mtb.ConsentProvision;
|
||||
import dev.pcvolkmer.mv64e.mtb.ModelProjectConsentPurpose;
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb;
|
||||
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;
|
||||
import org.hl7.fhir.r4.model.Consent.ProvisionComponent;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.slf4j.Logger;
|
||||
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) {
|
||||
this.gIcsConfigProperties = gIcsConfigProperties;
|
||||
}
|
||||
|
||||
public void embedBroadConsentResources(Mtb mtbFile, Bundle broadConsent) {
|
||||
for (Bundle.BundleEntryComponent entry : broadConsent.getEntry()) {
|
||||
Resource resource = entry.getResource();
|
||||
if (resource instanceof Consent) {
|
||||
Map<String, Object> consentMap = new HashMap<>();
|
||||
consentMap.put(resource.getIdElement().getIdPart(), resource);
|
||||
mtbFile.getMetadata().getResearchConsents().add(consentMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addGenomeDbProvisions(Mtb mtbFile, Bundle consentGnomeDe) {
|
||||
for (Bundle.BundleEntryComponent entry : consentGnomeDe.getEntry()) {
|
||||
Resource resource = entry.getResource();
|
||||
if (!(resource instanceof Consent consentFhirResource)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We expect only one provision in collection, therefore get first or none
|
||||
List<ProvisionComponent> provisions = consentFhirResource.getProvision().getProvision();
|
||||
if (provisions.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var provisionComponent = provisions.getFirst();
|
||||
|
||||
String provisionCode = null;
|
||||
if (provisionComponent.getCode() != null && !provisionComponent.getCode().isEmpty()) {
|
||||
CodeableConcept codeableConcept = provisionComponent.getCode().getFirst();
|
||||
if (codeableConcept.getCoding() != null && !codeableConcept.getCoding().isEmpty()) {
|
||||
provisionCode = codeableConcept.getCoding().getFirst().getCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (provisionCode != null) {
|
||||
try {
|
||||
ModelProjectConsentPurpose modelProjectConsentPurpose =
|
||||
ModelProjectConsentPurpose.forValue(provisionCode);
|
||||
|
||||
if (ModelProjectConsentPurpose.SEQUENCING.equals(modelProjectConsentPurpose)) {
|
||||
// CONVENTION: wrapping date is date of SEQUENCING consent
|
||||
mtbFile.getMetadata().getModelProjectConsent().setDate(consentFhirResource.getDateTime());
|
||||
}
|
||||
|
||||
Provision provision = Provision.builder()
|
||||
.type(ConsentProvision.valueOf(provisionComponent.getType().name()))
|
||||
.date(provisionComponent.getPeriod().getStart())
|
||||
.purpose(modelProjectConsentPurpose)
|
||||
.build();
|
||||
|
||||
mtbFile.getMetadata().getModelProjectConsent().getProvisions().add(provision);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package dev.dnpm.etl.processor.consent;
|
||||
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb;
|
||||
import java.util.Date;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentProvisionType;
|
||||
import org.slf4j.Logger;
|
||||
@ -40,4 +42,14 @@ public class ConsentCheckFileBased implements ICheckConsent{
|
||||
Date requestDate, ConsentDomain consentDomain) {
|
||||
return ConsentProvisionType.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embedBroadConsentResources(Mtb mtbFile, Bundle broadConsent) {
|
||||
throw new NotImplementedException("not intended to be implemented here!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGenomeDbProvisions(Mtb mtbFile, Bundle consentGnomeDe) {
|
||||
throw new NotImplementedException("not intended to be implemented here!");
|
||||
}
|
||||
}
|
||||
|
@ -38,12 +38,10 @@ import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
|
||||
public class GicsConsentService implements ICheckConsent {
|
||||
public class GicsConsentService extends BaseConsentService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(GicsConsentService.class);
|
||||
|
||||
private final GIcsConfigProperties gIcsConfigProperties;
|
||||
|
||||
public static final String IS_CONSENTED_ENDPOINT = "/$isConsented";
|
||||
public static final String IS_POLICY_STATES_FOR_PERSON_ENDPOINT = "/$currentPolicyStatesForPerson";
|
||||
private final RetryTemplate retryTemplate;
|
||||
@ -54,7 +52,8 @@ public class GicsConsentService implements ICheckConsent {
|
||||
|
||||
public GicsConsentService(GIcsConfigProperties gIcsConfigProperties,
|
||||
RetryTemplate retryTemplate, RestTemplate restTemplate, AppFhirConfig appFhirConfig) {
|
||||
this.gIcsConfigProperties = gIcsConfigProperties;
|
||||
super(gIcsConfigProperties);
|
||||
|
||||
this.retryTemplate = retryTemplate;
|
||||
this.restTemplate = restTemplate;
|
||||
this.fhirContext = appFhirConfig.fhirContext();
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dev.dnpm.etl.processor.consent;
|
||||
|
||||
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb;
|
||||
import java.util.Date;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentProvisionType;
|
||||
@ -36,8 +36,8 @@ public interface ICheckConsent {
|
||||
* @return consent policies as bundle; <p>if empty patient has not been asked, yet.</p>
|
||||
*/
|
||||
default Bundle getGenomDeConsent(String personIdentifierValue, Date requestDate) {
|
||||
return currentConsentForPersonAndTemplate(personIdentifierValue, ConsentDomain.Modelvorhaben64e,
|
||||
requestDate);
|
||||
return currentConsentForPersonAndTemplate(personIdentifierValue,
|
||||
ConsentDomain.Modelvorhaben64e, requestDate);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,12 +50,17 @@ public interface ICheckConsent {
|
||||
*/
|
||||
Bundle currentConsentForPersonAndTemplate(String personIdentifierValue,
|
||||
ConsentDomain targetConsentDomain, Date requestDate);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param consentBundle consent resource
|
||||
* @param requestDate date which must be within validation period of provision
|
||||
* @return type of provision, will be {@link ConsentProvisionType#NULL} if none is found.
|
||||
*/
|
||||
ConsentProvisionType getProvisionTypeByPolicyCode(Bundle consentBundle,
|
||||
Date requestDate, ConsentDomain consentDomain);
|
||||
ConsentProvisionType getProvisionTypeByPolicyCode(Bundle consentBundle, Date requestDate,
|
||||
ConsentDomain consentDomain);
|
||||
|
||||
|
||||
void embedBroadConsentResources(Mtb mtbFile, Bundle broadConsent);
|
||||
|
||||
void addGenomeDbProvisions(Mtb mtbFile, Bundle consentGnomeDe);
|
||||
}
|
||||
|
@ -107,7 +107,13 @@ data class GIcsConfigProperties(
|
||||
/**
|
||||
* Consent Policy which should be used for consent check
|
||||
*/
|
||||
val genomeDePolicySystem: String = "https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV"
|
||||
val genomeDePolicySystem: String = "https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV",
|
||||
|
||||
/**
|
||||
* Consent version (fixed version)
|
||||
*
|
||||
*/
|
||||
val genomeDeConsentVersion: String = "2.0"
|
||||
) {
|
||||
companion object {
|
||||
const val NAME = "app.consent.gics"
|
||||
|
@ -34,21 +34,16 @@ import dev.dnpm.etl.processor.output.*
|
||||
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
|
||||
import dev.dnpm.etl.processor.pseudonym.anonymizeContentWith
|
||||
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.MvhMetadata
|
||||
import dev.pcvolkmer.mv64e.mtb.Provision
|
||||
import org.apache.commons.codec.binary.Base32
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import org.hl7.fhir.r4.model.Consent
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.stereotype.Service
|
||||
import java.io.IOException
|
||||
import java.lang.RuntimeException
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
@ -96,7 +91,7 @@ class RequestProcessor(
|
||||
* @return true if consent is given
|
||||
*
|
||||
*/
|
||||
fun consentGatedCheck(mtbFile: Mtb): Boolean {
|
||||
fun consentGatedCheckAndTryEmbedding(mtbFile: Mtb): Boolean {
|
||||
if (consentService == null) {
|
||||
// consent check seems to be disabled
|
||||
return true
|
||||
@ -127,8 +122,8 @@ class RequestProcessor(
|
||||
personIdentifierValue, requestDate
|
||||
)
|
||||
|
||||
addGenomeDbProvisions(mtbFile, genomeDeConsent)
|
||||
embedBroadConsentResources(mtbFile, broadConsent)
|
||||
consentService.addGenomeDbProvisions(mtbFile, genomeDeConsent)
|
||||
consentService.embedBroadConsentResources(mtbFile, broadConsent)
|
||||
|
||||
val broadConsentStatus = consentService.getProvisionTypeByPolicyCode(
|
||||
broadConsent,
|
||||
@ -157,20 +152,25 @@ class RequestProcessor(
|
||||
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()
|
||||
}
|
||||
} else
|
||||
if (mtbFile.metadata.modelProjectConsent.provisions != null) {
|
||||
// make sure list can be changed
|
||||
mtbFile.metadata.modelProjectConsent.provisions =
|
||||
mtbFile.metadata.modelProjectConsent.provisions.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
fun processMtbFile(mtbFile: Mtb, requestId: RequestId) {
|
||||
val pid = PatientId(extractPatientIdentifier(mtbFile))
|
||||
|
||||
if (consentGatedCheck(mtbFile)) {
|
||||
if (consentGatedCheckAndTryEmbedding(mtbFile)) {
|
||||
mtbFile pseudonymizeWith pseudonymizeService
|
||||
mtbFile anonymizeContentWith pseudonymizeService
|
||||
val request = DnpmV2MtbFileRequest(requestId, transformationService.transform(mtbFile))
|
||||
@ -186,49 +186,6 @@ class RequestProcessor(
|
||||
}
|
||||
|
||||
|
||||
fun embedBroadConsentResources(
|
||||
mtbFile: Mtb, broadConsent: Bundle
|
||||
) {
|
||||
broadConsent.entry.forEach { it ->
|
||||
mtbFile.metadata.researchConsents.add(mapOf(it.resource.id to it.resource as Consent))
|
||||
}
|
||||
}
|
||||
|
||||
fun addGenomeDbProvisions(
|
||||
mtbFile: Mtb, consentGnomeDe: Bundle
|
||||
) {
|
||||
consentGnomeDe.entry.forEach { it ->
|
||||
{
|
||||
val consentFhirResource = it.resource as Consent
|
||||
|
||||
// we expect only one provision in collection, therefore get first or none
|
||||
val provisionComponent = consentFhirResource.provision.provision.firstOrNull()
|
||||
val provisionCode =
|
||||
provisionComponent?.code?.firstOrNull()?.coding?.firstOrNull()?.code
|
||||
|
||||
if (provisionCode != null) {
|
||||
try {
|
||||
val modelProjectConsentPurpose: ModelProjectConsentPurpose =
|
||||
ModelProjectConsentPurpose.valueOf(provisionCode)
|
||||
mtbFile.metadata.modelProjectConsent.provisions.add(
|
||||
Provision.builder().type(
|
||||
ConsentProvision.forValue(provisionComponent.type.name)
|
||||
).date(provisionComponent.period.start).purpose(
|
||||
modelProjectConsentPurpose
|
||||
).build()
|
||||
)
|
||||
} catch (ioe: IOException) {
|
||||
logger.error(
|
||||
"provision code '$provisionCode' is unknown and cannot be mapped.",
|
||||
ioe.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> saveAndSend(request: MtbFileRequest<T>, pid: PatientId) {
|
||||
requestService.save(
|
||||
Request(
|
||||
|
Reference in New Issue
Block a user