1
0
mirror of https://github.com/pcvolkmer/mv64e-etl-processor synced 2025-09-13 17:02:52 +00:00

feat: check consent for DNPM 2.1 requests (#126)

Co-authored-by: Jakub Lidke <jakub.lidke@uni-marburg.de>
This commit is contained in:
2025-08-15 12:37:42 +02:00
committed by GitHub
parent be513f305a
commit 3eb1c79cec
21 changed files with 934 additions and 286 deletions

View File

@@ -4,10 +4,10 @@ public enum ConsentDomain {
/**
* MII Broad consent
*/
BroadConsent,
BROAD_CONSENT,
/**
* GenomDe Modelvohaben §64e
* GenomDe Modellvorhaben §64e
*/
Modelvorhaben64e
MODELLVORHABEN_64E
}

View File

@@ -4,17 +4,9 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import dev.dnpm.etl.processor.config.AppFhirConfig;
import dev.dnpm.etl.processor.config.GIcsConfigProperties;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.StringType;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,112 +14,152 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.retry.TerminatedRetryException;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.Date;
public class GicsConsentService implements IGetConsent {
/**
* Service to request Consent from remote gICS installation
*
* @since 0.11
*/
public class GicsConsentService implements IConsentService {
private final Logger log = LoggerFactory.getLogger(GicsConsentService.class);
public static final String IS_CONSENTED_ENDPOINT = "/$isConsented";
public static final String IS_POLICY_STATES_FOR_PERSON_ENDPOINT = "/$currentPolicyStatesForPerson";
private final RetryTemplate retryTemplate;
private final RestTemplate restTemplate;
private final FhirContext fhirContext;
private final HttpHeaders httpHeader;
private final GIcsConfigProperties gIcsConfigProperties;
private String url;
public GicsConsentService(GIcsConfigProperties gIcsConfigProperties,
RetryTemplate retryTemplate, RestTemplate restTemplate, AppFhirConfig appFhirConfig) {
public GicsConsentService(
GIcsConfigProperties gIcsConfigProperties,
RetryTemplate retryTemplate,
RestTemplate restTemplate,
AppFhirConfig appFhirConfig
) {
this.retryTemplate = retryTemplate;
this.restTemplate = restTemplate;
this.fhirContext = appFhirConfig.fhirContext();
httpHeader = buildHeader(gIcsConfigProperties.getUsername(),
gIcsConfigProperties.getPassword());
this.gIcsConfigProperties = gIcsConfigProperties;
log.info("GicsConsentService initialized...");
}
public String getGicsUri(String endpoint) {
if (url == null) {
final String gIcsBaseUri = gIcsConfigProperties.getUri();
if (StringUtils.isBlank(gIcsBaseUri)) {
throw new IllegalArgumentException(
"gICS base URL is empty - should call gICS with false configuration.");
}
url = UriComponentsBuilder.fromUriString(gIcsBaseUri).path(endpoint)
.toUriString();
}
return url;
}
@NotNull
private static HttpHeaders buildHeader(String gPasUserName, String gPasPassword) {
var headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
if (StringUtils.isBlank(gPasUserName) || StringUtils.isBlank(gPasPassword)) {
return headers;
}
headers.setBasicAuth(gPasUserName, gPasPassword);
return headers;
}
protected static Parameters getIsConsentedRequestParam(GIcsConfigProperties configProperties,
String personIdentifierValue) {
protected Parameters getFhirRequestParameters(
String personIdentifierValue
) {
var result = new Parameters();
result.addParameter(new ParametersParameterComponent().setName("personIdentifier").setValue(
new Identifier().setValue(personIdentifierValue)
.setSystem(configProperties.getPersonIdentifierSystem())));
result.addParameter(new ParametersParameterComponent().setName("domain")
.setValue(new StringType().setValue(configProperties.getBroadConsentDomainName())));
result.addParameter(new ParametersParameterComponent().setName("policy").setValue(
new Coding().setCode(configProperties.getBroadConsentPolicyCode())
.setSystem(configProperties.getBroadConsentPolicySystem())));
result.addParameter(
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
);
result.addParameter(
new ParametersParameterComponent()
.setName("domain")
.setValue(
new StringType()
.setValue(this.gIcsConfigProperties.getBroadConsentDomainName())
)
);
result.addParameter(
new ParametersParameterComponent()
.setName("policy")
.setValue(
new Coding()
.setCode(this.gIcsConfigProperties.getBroadConsentPolicyCode())
.setSystem(this.gIcsConfigProperties.getBroadConsentPolicySystem())
)
);
/*
* is mandatory parameter, but we ignore it via additional configuration parameter
* 'ignoreVersionNumber'.
*/
result.addParameter(new ParametersParameterComponent().setName("version")
.setValue(new StringType().setValue("1.1")));
result.addParameter(
new ParametersParameterComponent()
.setName("version")
.setValue(new StringType().setValue("1.1")
)
);
/* add config parameter with:
* ignoreVersionNumber -> true ->> Reason is we cannot know which policy version each patient
* has possibly signed or not, therefore we are happy with any version found.
* unknownStateIsConsideredAsDecline -> true
*/
var config = new ParametersParameterComponent().setName("config").addPart(
new ParametersParameterComponent().setName("ignoreVersionNumber")
.setValue(new BooleanType().setValue(true))).addPart(
new ParametersParameterComponent().setName("unknownStateIsConsideredAsDecline")
.setValue(new BooleanType().setValue(false)));
var config = new ParametersParameterComponent()
.setName("config")
.addPart(
new ParametersParameterComponent()
.setName("ignoreVersionNumber")
.setValue(new BooleanType().setValue(true))
)
.addPart(
new ParametersParameterComponent()
.setName("unknownStateIsConsideredAsDecline")
.setValue(new BooleanType().setValue(false))
);
result.addParameter(config);
return result;
}
private URI endpointUri(String endpoint) {
assert this.gIcsConfigProperties.getUri() != null;
return UriComponentsBuilder.fromUriString(this.gIcsConfigProperties.getUri()).path(endpoint).build().toUri();
}
private HttpHeaders headersWithHttpBasicAuth() {
assert this.gIcsConfigProperties.getUri() != null;
var headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
if (
StringUtils.isBlank(this.gIcsConfigProperties.getUsername())
|| StringUtils.isBlank(this.gIcsConfigProperties.getPassword())
) {
return headers;
}
headers.setBasicAuth(this.gIcsConfigProperties.getUsername(), this.gIcsConfigProperties.getPassword());
return headers;
}
protected String callGicsApi(Parameters parameter, String endpoint) {
var parameterAsXml = fhirContext.newXmlParser().encodeResourceToString(parameter);
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.httpHeader);
ResponseEntity<String> responseEntity;
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.headersWithHttpBasicAuth());
try {
var url = getGicsUri(endpoint);
var responseEntity = retryTemplate.execute(
ctx -> restTemplate.exchange(endpointUri(endpoint), HttpMethod.POST, requestEntity, String.class)
);
responseEntity = retryTemplate.execute(
ctx -> restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class));
if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody();
} else {
var msg = String.format(
"Trusted party system reached but request failed! code: '%s' response: '%s'",
responseEntity.getStatusCode(), responseEntity.getBody());
log.error(msg);
return null;
}
} catch (RestClientException e) {
var msg = String.format("Get consents status request failed reason: '%s",
e.getMessage());
e.getMessage());
log.error(msg);
return null;
@@ -137,39 +169,32 @@ public class GicsConsentService implements IGetConsent {
terminatedRetryException.getMessage());
log.error(msg);
return null;
}
if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody();
} else {
var msg = String.format(
"Trusted party system reached but request failed! code: '%s' response: '%s'",
responseEntity.getStatusCode(), responseEntity.getBody());
log.error(msg);
return null;
}
}
@Override
public TtpConsentStatus getTtpBroadConsentStatus(String personIdentifierValue) {
var parameter = GicsConsentService.getIsConsentedRequestParam(gIcsConfigProperties,
personIdentifierValue);
var consentStatusResponse = callGicsApi(parameter,
GicsConsentService.IS_CONSENTED_ENDPOINT);
var consentStatusResponse = callGicsApi(
getFhirRequestParameters(personIdentifierValue),
GicsConsentService.IS_CONSENTED_ENDPOINT
);
return evaluateConsentResponse(consentStatusResponse);
}
protected Bundle currentConsentForPersonAndTemplate(String personIdentifierValue,
ConsentDomain targetConsentDomain, Date requestDate) {
protected Bundle currentConsentForPersonAndTemplate(
String personIdentifierValue,
ConsentDomain consentDomain,
Date requestDate
) {
String consentDomain = getConsentDomain(targetConsentDomain);
var requestParameter = GicsConsentService.buildRequestParameterCurrentPolicyStatesForPerson(
gIcsConfigProperties, personIdentifierValue, requestDate, consentDomain);
var requestParameter = buildRequestParameterCurrentPolicyStatesForPerson(
personIdentifierValue,
requestDate,
consentDomain
);
var consentDataSerialized = callGicsApi(requestParameter,
GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT);
GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT);
if (consentDataSerialized == null) {
// error occurred - should not process further!
@@ -177,15 +202,15 @@ public class GicsConsentService implements IGetConsent {
"consent data request failed - stopping processing! - try again or fix other problems first.");
}
var iBaseResource = fhirContext.newJsonParser()
.parseResource(consentDataSerialized);
.parseResource(consentDataSerialized);
if (iBaseResource instanceof OperationOutcome) {
// log error - very likely a configuration error
String errorMessage =
"Consent request failed! Check outcome:\n " + consentDataSerialized;
log.error(errorMessage);
throw new IllegalStateException(errorMessage);
} else if (iBaseResource instanceof Bundle) {
return (Bundle) iBaseResource;
} else if (iBaseResource instanceof Bundle bundle) {
return bundle;
} else {
String errorMessage = "Consent request failed! Unexpected response received! -> "
+ consentDataSerialized;
@@ -195,40 +220,52 @@ public class GicsConsentService implements IGetConsent {
}
@NotNull
private String getConsentDomain(ConsentDomain targetConsentDomain) {
String consentDomain;
switch (targetConsentDomain) {
case BroadConsent -> consentDomain = gIcsConfigProperties.getBroadConsentDomainName();
case Modelvorhaben64e ->
consentDomain = gIcsConfigProperties.getGenomDeConsentDomainName();
default -> throw new IllegalArgumentException(
"target ConsentDomain is missing but must be provided!");
}
return consentDomain;
private String getConsentDomainName(ConsentDomain targetConsentDomain) {
return switch (targetConsentDomain) {
case BROAD_CONSENT -> gIcsConfigProperties.getBroadConsentDomainName();
case MODELLVORHABEN_64E -> gIcsConfigProperties.getGenomDeConsentDomainName();
};
}
protected static Parameters buildRequestParameterCurrentPolicyStatesForPerson(
GIcsConfigProperties gIcsConfigProperties, String personIdentifierValue, Date requestDate,
String targetDomain) {
protected Parameters buildRequestParameterCurrentPolicyStatesForPerson(
String personIdentifierValue,
Date requestDate,
ConsentDomain consentDomain
) {
var requestParameter = new Parameters();
requestParameter.addParameter(new ParametersParameterComponent().setName("personIdentifier")
.setValue(new Identifier().setValue(personIdentifierValue)
.setSystem(gIcsConfigProperties.getPersonIdentifierSystem())));
requestParameter.addParameter(
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
);
requestParameter.addParameter(new ParametersParameterComponent().setName("domain")
.setValue(new StringType().setValue(targetDomain)));
requestParameter.addParameter(
new ParametersParameterComponent()
.setName("domain")
.setValue(new StringType().setValue(getConsentDomainName(consentDomain)))
);
Parameters nestedConfigParameters = new Parameters();
nestedConfigParameters.addParameter(
new ParametersParameterComponent().setName("idMatchingType").setValue(
new Coding().setSystem(
"https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType")
.setCode("AT_LEAST_ONE"))).addParameter("ignoreVersionNumber", false)
nestedConfigParameters
.addParameter(
new ParametersParameterComponent()
.setName("idMatchingType")
.setValue(new Coding()
.setSystem("https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType")
.setCode("AT_LEAST_ONE")
)
)
.addParameter("ignoreVersionNumber", false)
.addParameter("unknownStateIsConsideredAsDecline", false)
.addParameter("requestDate", new DateType().setValue(requestDate));
requestParameter.addParameter(new ParametersParameterComponent().setName("config").addPart()
.setResource(nestedConfigParameters));
requestParameter.addParameter(
new ParametersParameterComponent().setName("config").addPart().setResource(nestedConfigParameters)
);
return requestParameter;
}
@@ -254,7 +291,7 @@ public class GicsConsentService implements IGetConsent {
}
} else if (response instanceof OperationOutcome outcome) {
log.error("failed to get consent status from ttp. probably configuration error. "
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
}
} catch (DataFormatException dfe) {
@@ -265,17 +302,6 @@ public class GicsConsentService implements IGetConsent {
@Override
public Bundle getConsent(String patientId, Date requestDate, ConsentDomain consentDomain) {
switch (consentDomain) {
case BroadConsent -> {
return currentConsentForPersonAndTemplate(patientId, ConsentDomain.BroadConsent,
requestDate);
}
case Modelvorhaben64e -> {
return currentConsentForPersonAndTemplate(patientId,
ConsentDomain.Modelvorhaben64e, requestDate);
}
}
return new Bundle();
return currentConsentForPersonAndTemplate(patientId, consentDomain, requestDate);
}
}

View File

@@ -3,7 +3,7 @@ package dev.dnpm.etl.processor.consent;
import java.util.Date;
import org.hl7.fhir.r4.model.Bundle;
public interface IGetConsent {
public interface IConsentService {
/**
* Get broad consent status for a patient identifier

View File

@@ -5,11 +5,11 @@ import org.hl7.fhir.r4.model.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConsentByMtbFile implements IGetConsent {
public class MtbFileConsentService implements IConsentService {
private static final Logger log = LoggerFactory.getLogger(ConsentByMtbFile.class);
private static final Logger log = LoggerFactory.getLogger(MtbFileConsentService.class);
public ConsentByMtbFile() {
public MtbFileConsentService() {
log.info("ConsentCheckFileBased initialized...");
}

View File

@@ -73,8 +73,8 @@ data class GIcsConfigProperties(
*
*/
val uri: String?,
val username: String?,
val password: String?,
val username: String? = null,
val password: String? = null,
/**
* gICS specific system

View File

@@ -20,9 +20,9 @@
package dev.dnpm.etl.processor.config
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.consent.ConsentByMtbFile
import dev.dnpm.etl.processor.consent.MtbFileConsentService
import dev.dnpm.etl.processor.consent.GicsConsentService
import dev.dnpm.etl.processor.consent.IGetConsent
import dev.dnpm.etl.processor.consent.IConsentService
import dev.dnpm.etl.processor.monitoring.*
import dev.dnpm.etl.processor.pseudonym.AnonymizingGenerator
import dev.dnpm.etl.processor.pseudonym.Generator
@@ -218,7 +218,7 @@ class AppConfiguration {
retryTemplate: RetryTemplate,
restTemplate: RestTemplate,
appFhirConfig: AppFhirConfig
): IGetConsent {
): IConsentService {
return GicsConsentService(
gIcsConfigProperties,
retryTemplate,
@@ -234,7 +234,7 @@ class AppConfiguration {
gIcsConfigProperties: GIcsConfigProperties,
getObjectMapper: ObjectMapper,
appFhirConfig: AppFhirConfig,
gicsConsentService: IGetConsent
gicsConsentService: IConsentService
): ConsentProcessor {
return ConsentProcessor(
configProperties,
@@ -261,8 +261,8 @@ class AppConfiguration {
@Bean
@ConditionalOnMissingBean
fun iGetConsentService(): IGetConsent {
return ConsentByMtbFile()
fun iGetConsentService(): IConsentService {
return MtbFileConsentService()
}
}
@@ -271,13 +271,9 @@ class GicsEnabledCondition :
AnyNestedCondition(ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN) {
@ConditionalOnProperty(name = ["app.consent.service"], havingValue = "gics")
@ConditionalOnProperty(name = ["app.consent.gics.uri"])
class OnGicsServiceSelected {
// Just for Condition
}
@ConditionalOnProperty(name = ["app.consent.gics.enabled"], havingValue = "true")
class OnGicsEnabled {
// Just for Condition
}
}

View File

@@ -20,6 +20,7 @@
package dev.dnpm.etl.processor.config
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.consent.ConsentEvaluator
import dev.dnpm.etl.processor.input.KafkaInputListener
import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
@@ -100,9 +101,10 @@ class AppKafkaConfiguration {
@ConditionalOnProperty(value = ["app.kafka.input-topic"])
fun kafkaInputListener(
requestProcessor: RequestProcessor,
objectMapper: ObjectMapper
objectMapper: ObjectMapper,
consentEvaluator: ConsentEvaluator
): KafkaInputListener {
return KafkaInputListener(requestProcessor, objectMapper)
return KafkaInputListener(requestProcessor, consentEvaluator, objectMapper)
}
@Bean
@@ -113,4 +115,4 @@ class AppKafkaConfiguration {
return KafkaConnectionCheckService(consumerFactory.createConsumer(), connectionCheckUpdateProducer)
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.consent
import dev.pcvolkmer.mv64e.mtb.ConsentProvision
import dev.pcvolkmer.mv64e.mtb.ModelProjectConsentPurpose
import dev.pcvolkmer.mv64e.mtb.Mtb
import org.springframework.stereotype.Service
/**
* Evaluates consent using provided consent service and file based consent information
*/
@Service
class ConsentEvaluator(
private val consentService: IConsentService
) {
fun check(mtbFile: Mtb): ConsentEvaluation {
val ttpConsentStatus = consentService.getTtpBroadConsentStatus(mtbFile.patient.id)
val consentGiven = ttpConsentStatus == TtpConsentStatus.BROAD_CONSENT_GIVEN
|| ttpConsentStatus == TtpConsentStatus.GENOM_DE_CONSENT_SEQUENCING_PERMIT
// Aktuell nur Modellvorhaben Consent im File
|| ttpConsentStatus == TtpConsentStatus.UNKNOWN_CHECK_FILE && mtbFile.metadata?.modelProjectConsent?.provisions?.any {
it.purpose == ModelProjectConsentPurpose.SEQUENCING
&& it.type == ConsentProvision.PERMIT
} == true
return ConsentEvaluation(ttpConsentStatus, consentGiven)
}
}
data class ConsentEvaluation(private val ttpConsentStatus: TtpConsentStatus, private val consentGiven: Boolean) {
/**
* Checks if any required consent is present
*/
fun hasConsent(): Boolean {
return consentGiven
}
/**
* Returns the consent status
*/
fun getStatus(): TtpConsentStatus {
if (ttpConsentStatus == TtpConsentStatus.UNKNOWN_CHECK_FILE) {
// in case ttp check is disabled - we propagate rejected status anyway
return TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED
}
return ttpConsentStatus
}
}

View File

@@ -23,9 +23,9 @@ import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.CustomMediaType
import dev.dnpm.etl.processor.PatientId
import dev.dnpm.etl.processor.RequestId
import dev.dnpm.etl.processor.consent.ConsentEvaluator
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
@@ -34,6 +34,7 @@ import org.springframework.kafka.listener.MessageListener
class KafkaInputListener(
private val requestProcessor: RequestProcessor,
private val consentEvaluator: ConsentEvaluator,
private val objectMapper: ObjectMapper
) : MessageListener<String, String> {
private val logger = LoggerFactory.getLogger(KafkaInputListener::class.java)
@@ -70,8 +71,7 @@ class KafkaInputListener(
RequestId("")
}
// 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()) {
if (consentEvaluator.check(mtbFile).hasConsent()) {
logger.debug("Accepted MTB File for processing")
if (requestId.isBlank()) {
requestProcessor.processMtbFile(mtbFile)

View File

@@ -21,7 +21,7 @@ package dev.dnpm.etl.processor.input
import dev.dnpm.etl.processor.CustomMediaType
import dev.dnpm.etl.processor.PatientId
import dev.dnpm.etl.processor.consent.IGetConsent
import dev.dnpm.etl.processor.consent.ConsentEvaluator
import dev.dnpm.etl.processor.consent.TtpConsentStatus
import dev.dnpm.etl.processor.services.RequestProcessor
import dev.pcvolkmer.mv64e.mtb.Mtb
@@ -34,9 +34,8 @@ import org.springframework.web.bind.annotation.*
@RequestMapping(path = ["mtbfile", "mtb"])
class MtbFileRestController(
private val requestProcessor: RequestProcessor,
private val iGetConsent: IGetConsent
private val consentEvaluator: ConsentEvaluator
) {
private val logger = LoggerFactory.getLogger(MtbFileRestController::class.java)
@GetMapping
@@ -46,8 +45,15 @@ class MtbFileRestController(
@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)
val consentEvaluation = consentEvaluator.check(mtbFile)
if (consentEvaluation.hasConsent()) {
logger.debug("Accepted MTB File (DNPM V2) for processing")
requestProcessor.processMtbFile(mtbFile)
} else {
logger.debug("Accepted MTB File (DNPM V2) and process deletion")
val patientId = PatientId(mtbFile.patient.id)
requestProcessor.processDeletion(patientId, consentEvaluation.getStatus())
}
return ResponseEntity.accepted().build()
}

View File

@@ -6,9 +6,9 @@ import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.config.GIcsConfigProperties
import dev.dnpm.etl.processor.consent.ConsentByMtbFile
import dev.dnpm.etl.processor.consent.MtbFileConsentService
import dev.dnpm.etl.processor.consent.ConsentDomain
import dev.dnpm.etl.processor.consent.IGetConsent
import dev.dnpm.etl.processor.consent.IConsentService
import dev.dnpm.etl.processor.pseudonym.ensureMetaDataIsInitialized
import dev.pcvolkmer.mv64e.mtb.*
import org.apache.commons.lang3.NotImplementedException
@@ -31,7 +31,7 @@ class ConsentProcessor(
private val gIcsConfigProperties: GIcsConfigProperties,
private val objectMapper: ObjectMapper,
private val fhirContext: FhirContext,
private val consentService: IGetConsent
private val consentService: IConsentService
) {
private var logger: Logger = LoggerFactory.getLogger("ConsentProcessor")
@@ -49,7 +49,7 @@ class ConsentProcessor(
*
*/
fun consentGatedCheckAndTryEmbedding(mtbFile: Mtb): Boolean {
if (consentService is ConsentByMtbFile) {
if (consentService is MtbFileConsentService) {
// consent check is disabled
return true
}
@@ -70,7 +70,7 @@ class ConsentProcessor(
* broad consent
*/
val broadConsent = consentService.getConsent(
personIdentifierValue, requestDate, ConsentDomain.BroadConsent
personIdentifierValue, requestDate, ConsentDomain.BROAD_CONSENT
)
val broadConsentHasBeenAsked = !broadConsent.entry.isEmpty()
@@ -78,7 +78,7 @@ class ConsentProcessor(
if (!broadConsentHasBeenAsked) return false
val genomeDeConsent = consentService.getConsent(
personIdentifierValue, requestDate, ConsentDomain.Modelvorhaben64e
personIdentifierValue, requestDate, ConsentDomain.MODELLVORHABEN_64E
)
addGenomeDbProvisions(mtbFile, genomeDeConsent)
@@ -88,11 +88,11 @@ class ConsentProcessor(
embedBroadConsentResources(mtbFile, broadConsent)
val broadConsentStatus = getProvisionTypeByPolicyCode(
broadConsent, requestDate, ConsentDomain.BroadConsent
broadConsent, requestDate, ConsentDomain.BROAD_CONSENT
)
val genomDeSequencingStatus = getProvisionTypeByPolicyCode(
genomeDeConsent, requestDate, ConsentDomain.Modelvorhaben64e
genomeDeConsent, requestDate, ConsentDomain.MODELLVORHABEN_64E
)
if (Consent.ConsentProvisionType.NULL == broadConsentStatus) {
@@ -204,10 +204,10 @@ class ConsentProcessor(
): Consent.ConsentProvisionType {
val code: String?
val system: String?
if (ConsentDomain.BroadConsent == consentDomain) {
if (ConsentDomain.BROAD_CONSENT == consentDomain) {
code = gIcsConfigProperties.broadConsentPolicyCode
system = gIcsConfigProperties.broadConsentPolicySystem
} else if (ConsentDomain.Modelvorhaben64e == consentDomain) {
} else if (ConsentDomain.MODELLVORHABEN_64E == consentDomain) {
code = gIcsConfigProperties.genomeDePolicyCode
system = gIcsConfigProperties.genomeDePolicySystem
} else {
@@ -279,4 +279,4 @@ class ConsentProcessor(
return isRequestDateAfterOrEqualStart <= 0 && isRequestDateBeforeOrEqualEnd >= 0
}
}
}