mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-16 20:32:54 +00:00
refactor: moved consent evaluation to new ConsentProcessor.kt
This commit is contained in:
@ -23,9 +23,9 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.ukw.ccc.bwhc.dto.*
|
||||
import dev.dnpm.etl.processor.anyValueClass
|
||||
import dev.dnpm.etl.processor.config.AppSecurityConfiguration
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.ConsentByMtbFile
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.IGetConsent
|
||||
import dev.dnpm.etl.processor.security.TokenRepository
|
||||
import dev.dnpm.etl.processor.security.UserRoleRepository
|
||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||
@ -55,7 +55,7 @@ import org.springframework.test.web.servlet.post
|
||||
classes = [
|
||||
MtbFileRestController::class,
|
||||
AppSecurityConfiguration::class,
|
||||
ConsentCheckFileBased::class, ICheckConsent::class
|
||||
ConsentByMtbFile::class, IGetConsent::class
|
||||
]
|
||||
)
|
||||
@MockitoBean(types = [TokenRepository::class, RequestProcessor::class])
|
||||
|
@ -1,18 +1,15 @@
|
||||
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;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ConsentCheckFileBased implements ICheckConsent {
|
||||
public class ConsentByMtbFile implements IGetConsent {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ConsentCheckFileBased.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(ConsentByMtbFile.class);
|
||||
|
||||
public ConsentCheckFileBased() {
|
||||
public ConsentByMtbFile() {
|
||||
log.info("ConsentCheckFileBased initialized...");
|
||||
}
|
||||
|
||||
@ -23,12 +20,12 @@ public class ConsentCheckFileBased implements ICheckConsent {
|
||||
|
||||
@Override
|
||||
public Bundle getBroadConsent(String personIdentifierValue, Date requestDate) {
|
||||
return ICheckConsent.super.getBroadConsent(personIdentifierValue, requestDate);
|
||||
return IGetConsent.super.getBroadConsent(personIdentifierValue, requestDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getGenomDeConsent(String personIdentifierValue, Date requestDate) {
|
||||
return ICheckConsent.super.getGenomDeConsent(personIdentifierValue, requestDate);
|
||||
return IGetConsent.super.getGenomDeConsent(personIdentifierValue, requestDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,10 +33,4 @@ public class ConsentCheckFileBased implements ICheckConsent {
|
||||
ConsentDomain targetConsentDomain, Date requestDate) {
|
||||
return new Bundle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsentProvisionType getProvisionTypeByPolicyCode(Bundle consentBundle,
|
||||
Date requestDate, ConsentDomain consentDomain) {
|
||||
return ConsentProvisionType.NULL;
|
||||
}
|
||||
}
|
@ -2,27 +2,18 @@ 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;
|
||||
import java.util.Optional;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
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.Consent;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentProvisionType;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentState;
|
||||
import org.hl7.fhir.r4.model.Consent.ProvisionComponent;
|
||||
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.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r4.model.Period;
|
||||
import org.hl7.fhir.r4.model.ResourceType;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
@ -39,7 +30,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
|
||||
public class GicsConsentService implements ICheckConsent {
|
||||
public class GicsConsentService implements IGetConsent {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(GicsConsentService.class);
|
||||
|
||||
@ -272,83 +263,4 @@ public class GicsConsentService implements ICheckConsent {
|
||||
return TtpConsentStatus.FAILED_TO_ASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
public ConsentProvisionType getProvisionTypeByPolicyCode(Bundle consentBundle,
|
||||
Date requestDate, ConsentDomain consentDomain) {
|
||||
String code;
|
||||
String system;
|
||||
if (ConsentDomain.BroadConsent == consentDomain) {
|
||||
code = gIcsConfigProperties.getBroadConsentPolicyCode();
|
||||
system = gIcsConfigProperties.getBroadConsentPolicySystem();
|
||||
} else if (ConsentDomain.Modelvorhaben64e == consentDomain) {
|
||||
code = gIcsConfigProperties.getGenomeDePolicyCode();
|
||||
system = gIcsConfigProperties.getGenomeDePolicySystem();
|
||||
} else {
|
||||
throw new NotImplementedException("unknown consent domain " + consentDomain.name());
|
||||
}
|
||||
|
||||
Optional<ConsentProvisionType> provisionTypeByPolicyCode = getProvisionTypeByPolicyCode(
|
||||
consentBundle, code,
|
||||
system, requestDate);
|
||||
return provisionTypeByPolicyCode.orElse(ConsentProvisionType.NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consentBundle consent resource
|
||||
* @param policyAndProvisionCode policyRule and provision code value
|
||||
* @param policyAndProvisionSystem policyRule and provision system value
|
||||
* @param requestDate date which must be within validation period of provision
|
||||
* @return type of provision, will be {@link ConsentProvisionType#NULL} if none is found.
|
||||
*/
|
||||
public Optional<ConsentProvisionType> getProvisionTypeByPolicyCode(Bundle consentBundle,
|
||||
String policyAndProvisionCode, String policyAndProvisionSystem, Date requestDate) {
|
||||
return consentBundle.getEntry().stream().filter(entry -> {
|
||||
if (entry.getResource().getResourceType() != ResourceType.Consent) {
|
||||
// no consent in bundle
|
||||
return false;
|
||||
}
|
||||
|
||||
Consent consent = (Consent) entry.getResource();
|
||||
|
||||
// consent ist active and its policy rule must fits search criteria
|
||||
return consent.getStatus() == ConsentState.ACTIVE && checkCoding(
|
||||
policyAndProvisionCode, policyAndProvisionSystem,
|
||||
consent.getPolicyRule().getCodingFirstRep()) && isIsRequestDateInRange(requestDate,
|
||||
consent.getProvision().getPeriod());
|
||||
|
||||
}).map(consentWithTargetPolicy -> {
|
||||
ProvisionComponent provision = ((Consent) consentWithTargetPolicy.getResource()).getProvision();
|
||||
var provisionComponentByCode = provision.getProvision().stream().filter(prov ->
|
||||
|
||||
checkCoding(policyAndProvisionCode, policyAndProvisionSystem,
|
||||
prov.getCodeFirstRep().getCodingFirstRep()) && isIsRequestDateInRange(
|
||||
requestDate, prov.getPeriod())
|
||||
|
||||
).findFirst();
|
||||
|
||||
if (provisionComponentByCode.isPresent()) {
|
||||
// actual provision we search for
|
||||
return provisionComponentByCode.get().getType();
|
||||
}
|
||||
// no fitting nested provision found - fall back to wrapping provision with default value
|
||||
return provision.getType();
|
||||
}).findFirst().or(() -> Optional.of(ConsentProvisionType.NULL));
|
||||
}
|
||||
|
||||
protected static boolean checkCoding(String researchAllowedPolicyOid,
|
||||
String researchAllowedPolicySystem, Coding coding) {
|
||||
|
||||
return coding.getSystem().equals(researchAllowedPolicySystem) && coding.getCode()
|
||||
.equals(researchAllowedPolicyOid);
|
||||
}
|
||||
|
||||
protected static boolean isIsRequestDateInRange(Date requestdate, Period provPeriod) {
|
||||
var isRequestDateAfterOrEqualStart = provPeriod.getStart().compareTo(requestdate);
|
||||
var isRequestDateBeforeOrEqualEnd = provPeriod.getEnd().compareTo(requestdate);
|
||||
return isRequestDateAfterOrEqualStart <= 0 && isRequestDateBeforeOrEqualEnd >= 0;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,8 @@ package dev.dnpm.etl.processor.consent;
|
||||
|
||||
import java.util.Date;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentProvisionType;
|
||||
|
||||
public interface ICheckConsent {
|
||||
public interface IGetConsent {
|
||||
|
||||
/**
|
||||
* Get broad consent status for a patient identifier
|
||||
@ -50,12 +49,4 @@ 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);
|
||||
|
||||
}
|
@ -20,8 +20,8 @@
|
||||
package dev.dnpm.etl.processor.config
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.ConsentByMtbFile
|
||||
import dev.dnpm.etl.processor.consent.IGetConsent
|
||||
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||
import dev.dnpm.etl.processor.monitoring.*
|
||||
import dev.dnpm.etl.processor.pseudonym.AnonymizingGenerator
|
||||
@ -212,7 +212,7 @@ class AppConfiguration {
|
||||
fun gicsConsentService(
|
||||
gIcsConfigProperties: GIcsConfigProperties,
|
||||
retryTemplate: RetryTemplate, restTemplate: RestTemplate, appFhirConfig: AppFhirConfig
|
||||
): ICheckConsent {
|
||||
): IGetConsent {
|
||||
return GicsConsentService(
|
||||
gIcsConfigProperties,
|
||||
retryTemplate,
|
||||
@ -227,7 +227,7 @@ class AppConfiguration {
|
||||
gIcsConfigProperties: GIcsConfigProperties,
|
||||
getObjectMapper: ObjectMapper,
|
||||
appFhirConfig: AppFhirConfig,
|
||||
gicsConsentService: ICheckConsent
|
||||
gicsConsentService: IGetConsent
|
||||
): ConsentProcessor {
|
||||
return ConsentProcessor(
|
||||
gIcsConfigProperties,
|
||||
@ -253,8 +253,8 @@ class AppConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun constService(): ICheckConsent {
|
||||
return ConsentCheckFileBased()
|
||||
fun iGetConsentService(): IGetConsent {
|
||||
return ConsentByMtbFile()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ 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.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.IGetConsent
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
@ -35,7 +35,7 @@ import org.springframework.web.bind.annotation.*
|
||||
@RestController
|
||||
@RequestMapping(path = ["mtbfile", "mtb"])
|
||||
class MtbFileRestController(
|
||||
private val requestProcessor: RequestProcessor, private val iCheckConsent: ICheckConsent
|
||||
private val requestProcessor: RequestProcessor, private val iGetConsent: IGetConsent
|
||||
) {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(MtbFileRestController::class.java)
|
||||
@ -63,7 +63,7 @@ class MtbFileRestController(
|
||||
}
|
||||
|
||||
private fun checkConsentStatus(mtbFile: MtbFile): Pair<TtpConsentStatus, Boolean> {
|
||||
var ttpConsentStatus = iCheckConsent.getTtpBroadConsentStatus(mtbFile.patient.id)
|
||||
var ttpConsentStatus = iGetConsent.getTtpBroadConsentStatus(mtbFile.patient.id)
|
||||
|
||||
val isConsentOK =
|
||||
(ttpConsentStatus.equals(TtpConsentStatus.UNKNOWN_CHECK_FILE) && mtbFile.consent.status == Consent.Status.ACTIVE) ||
|
||||
|
@ -6,12 +6,14 @@ import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties
|
||||
import dev.dnpm.etl.processor.consent.ConsentDomain
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.IGetConsent
|
||||
import dev.dnpm.etl.processor.pseudonym.ensureMetaDataIsInitialized
|
||||
import dev.pcvolkmer.mv64e.mtb.*
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import org.hl7.fhir.r4.model.CodeableConcept
|
||||
import org.hl7.fhir.r4.model.Consent
|
||||
import org.apache.commons.lang3.NotImplementedException
|
||||
import org.hl7.fhir.r4.model.*
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent
|
||||
import org.hl7.fhir.r4.model.Coding
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentState
|
||||
import org.hl7.fhir.r4.model.Consent.ProvisionComponent
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
@ -23,9 +25,10 @@ import java.util.*
|
||||
|
||||
@Service
|
||||
class ConsentProcessor(
|
||||
private val gIcsConfigProperties: GIcsConfigProperties, private val objectMapper: ObjectMapper,
|
||||
private val gIcsConfigProperties: GIcsConfigProperties,
|
||||
private val objectMapper: ObjectMapper,
|
||||
private val fhirContext: FhirContext,
|
||||
private val consentService: ICheckConsent?
|
||||
private val consentService: IGetConsent?
|
||||
) {
|
||||
private var logger: Logger = LoggerFactory.getLogger("ConsentProcessor")
|
||||
|
||||
@ -80,11 +83,11 @@ class ConsentProcessor(
|
||||
|
||||
embedBroadConsentResources(mtbFile, broadConsent)
|
||||
|
||||
val broadConsentStatus = consentService.getProvisionTypeByPolicyCode(
|
||||
val broadConsentStatus = getProvisionTypeByPolicyCode(
|
||||
broadConsent, requestDate, ConsentDomain.BroadConsent
|
||||
)
|
||||
|
||||
val genomDeSequencingStatus = consentService.getProvisionTypeByPolicyCode(
|
||||
val genomDeSequencingStatus = getProvisionTypeByPolicyCode(
|
||||
genomeDeConsent, requestDate, ConsentDomain.Modelvorhaben64e
|
||||
)
|
||||
|
||||
@ -92,27 +95,22 @@ class ConsentProcessor(
|
||||
// bc not asked
|
||||
return false
|
||||
}
|
||||
if (Consent.ConsentProvisionType.PERMIT == broadConsentStatus ||
|
||||
Consent.ConsentProvisionType.PERMIT == genomDeSequencingStatus
|
||||
) return true
|
||||
if (Consent.ConsentProvisionType.PERMIT == broadConsentStatus || Consent.ConsentProvisionType.PERMIT == genomDeSequencingStatus) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public fun embedBroadConsentResources(mtbFile: Mtb, broadConsent: Bundle) {
|
||||
fun embedBroadConsentResources(mtbFile: Mtb, broadConsent: Bundle) {
|
||||
for (entry in broadConsent.getEntry()) {
|
||||
val resource = entry.getResource()
|
||||
if (resource is Consent) {
|
||||
// since jackson convertValue does not work here,
|
||||
// we need another step to back to string, before we convert to object map
|
||||
val asJsonString =
|
||||
fhirContext.newJsonParser().encodeResourceToString(resource)
|
||||
val asJsonString = fhirContext.newJsonParser().encodeResourceToString(resource)
|
||||
try {
|
||||
val mapOfJson: HashMap<String?, Any?>? =
|
||||
objectMapper.readValue<HashMap<String?, Any?>?>(
|
||||
asJsonString,
|
||||
object : TypeReference<HashMap<String?, Any?>?>() {
|
||||
})
|
||||
asJsonString, object : TypeReference<HashMap<String?, Any?>?>() {})
|
||||
mtbFile.metadata.researchConsents.add(mapOfJson)
|
||||
} catch (e: JsonProcessingException) {
|
||||
throw RuntimeException(e)
|
||||
@ -121,7 +119,7 @@ class ConsentProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
public fun addGenomeDbProvisions(mtbFile: Mtb, consentGnomeDe: Bundle) {
|
||||
fun addGenomeDbProvisions(mtbFile: Mtb, consentGnomeDe: Bundle) {
|
||||
for (entry in consentGnomeDe.getEntry()) {
|
||||
val resource = entry.getResource()
|
||||
if (resource !is Consent) {
|
||||
@ -157,8 +155,7 @@ class ConsentProcessor(
|
||||
val provision = Provision.builder()
|
||||
.type(ConsentProvision.valueOf(provisionComponent.getType().name))
|
||||
.date(provisionComponent.getPeriod().getStart())
|
||||
.purpose(modelProjectConsentPurpose)
|
||||
.build()
|
||||
.purpose(modelProjectConsentPurpose).build()
|
||||
|
||||
mtbFile.metadata.modelProjectConsent.provisions.add(provision)
|
||||
} catch (ioe: IOException) {
|
||||
@ -183,4 +180,89 @@ class ConsentProcessor(
|
||||
mtbFile.metadata.type = MvhSubmissionType.INITIAL
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consentBundle consent resource
|
||||
* @param requestDate date which must be within validation period of provision
|
||||
* @return type of provision, will be [org.hl7.fhir.r4.model.Consent.ConsentProvisionType.NULL] if none is found.
|
||||
*/
|
||||
fun getProvisionTypeByPolicyCode(
|
||||
consentBundle: Bundle, requestDate: Date?, consentDomain: ConsentDomain
|
||||
): Consent.ConsentProvisionType {
|
||||
val code: String?
|
||||
val system: String?
|
||||
if (ConsentDomain.BroadConsent == consentDomain) {
|
||||
code = gIcsConfigProperties.broadConsentPolicyCode
|
||||
system = gIcsConfigProperties.broadConsentPolicySystem
|
||||
} else if (ConsentDomain.Modelvorhaben64e == consentDomain) {
|
||||
code = gIcsConfigProperties.genomeDePolicyCode
|
||||
system = gIcsConfigProperties.genomeDePolicySystem
|
||||
} else {
|
||||
throw NotImplementedException("unknown consent domain " + consentDomain.name)
|
||||
}
|
||||
|
||||
val provisionTypeByPolicyCode = getProvisionTypeByPolicyCode(
|
||||
consentBundle, code, system, requestDate
|
||||
)
|
||||
return provisionTypeByPolicyCode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consentBundle consent resource
|
||||
* @param policyAndProvisionCode policyRule and provision code value
|
||||
* @param policyAndProvisionSystem policyRule and provision system value
|
||||
* @param requestDate date which must be within validation period of provision
|
||||
* @return type of provision, will be [org.hl7.fhir.r4.model.Consent.ConsentProvisionType.NULL] if none is found.
|
||||
*/
|
||||
fun getProvisionTypeByPolicyCode(
|
||||
consentBundle: Bundle,
|
||||
policyAndProvisionCode: String?,
|
||||
policyAndProvisionSystem: String?,
|
||||
requestDate: Date?
|
||||
): Consent.ConsentProvisionType {
|
||||
val entriesOfInterest = consentBundle.entry.filter { entry ->
|
||||
entry.resource.isResource && entry.resource.resourceType == ResourceType.Consent && (entry.resource as Consent).status == ConsentState.ACTIVE && checkCoding(
|
||||
policyAndProvisionCode,
|
||||
policyAndProvisionSystem,
|
||||
(entry.resource as Consent).policyRule.codingFirstRep
|
||||
) && isIsRequestDateInRange(
|
||||
requestDate, (entry.resource as Consent).provision.period
|
||||
)
|
||||
}.map { consentWithTargetPolicy: BundleEntryComponent ->
|
||||
val provision = (consentWithTargetPolicy.getResource() as Consent).getProvision()
|
||||
val provisionComponentByCode =
|
||||
provision.getProvision().stream().filter { prov: ProvisionComponent? ->
|
||||
checkCoding(
|
||||
policyAndProvisionCode,
|
||||
policyAndProvisionSystem,
|
||||
prov!!.getCodeFirstRep().getCodingFirstRep()
|
||||
) && isIsRequestDateInRange(
|
||||
requestDate, prov.getPeriod()
|
||||
)
|
||||
}.findFirst()
|
||||
if (provisionComponentByCode.isPresent) {
|
||||
// actual provision we search for
|
||||
return@map provisionComponentByCode.get().getType()
|
||||
} else {
|
||||
if (provision.type != null) return provision.type
|
||||
|
||||
}
|
||||
return Consent.ConsentProvisionType.NULL
|
||||
}.firstOrNull()
|
||||
|
||||
if (entriesOfInterest == null) return Consent.ConsentProvisionType.NULL
|
||||
return entriesOfInterest
|
||||
}
|
||||
|
||||
fun checkCoding(
|
||||
researchAllowedPolicyOid: String?, researchAllowedPolicySystem: String?, coding: Coding
|
||||
): Boolean {
|
||||
return coding.getSystem() == researchAllowedPolicySystem && (coding.getCode() == researchAllowedPolicyOid)
|
||||
}
|
||||
|
||||
fun isIsRequestDateInRange(requestdate: Date?, provPeriod: Period): Boolean {
|
||||
val isRequestDateAfterOrEqualStart = provPeriod.getStart().compareTo(requestdate)
|
||||
val isRequestDateBeforeOrEqualEnd = provPeriod.getEnd().compareTo(requestdate)
|
||||
return isRequestDateAfterOrEqualStart <= 0 && isRequestDateBeforeOrEqualEnd >= 0
|
||||
}
|
||||
|
||||
}
|
@ -23,8 +23,6 @@ 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.ConsentDomain
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.monitoring.Report
|
||||
import dev.dnpm.etl.processor.monitoring.Request
|
||||
@ -33,19 +31,15 @@ import dev.dnpm.etl.processor.monitoring.RequestType
|
||||
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.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
|
||||
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.Clock
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
||||
@ -83,7 +77,7 @@ class RequestProcessor(
|
||||
val pid = PatientId(extractPatientIdentifier(mtbFile))
|
||||
|
||||
val isConsentOk = consentProcessor != null &&
|
||||
consentProcessor.consentGatedCheckAndTryEmbedding(mtbFile) || consentProcessor == null;
|
||||
consentProcessor.consentGatedCheckAndTryEmbedding(mtbFile) || consentProcessor == null
|
||||
if (isConsentOk) {
|
||||
mtbFile pseudonymizeWith pseudonymizeService
|
||||
mtbFile anonymizeContentWith pseudonymizeService
|
||||
@ -190,7 +184,7 @@ class RequestProcessor(
|
||||
)
|
||||
)
|
||||
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
requestService.save(
|
||||
Request(
|
||||
uuid = requestId,
|
||||
|
@ -3,20 +3,13 @@ package dev.dnpm.etl.processor.consent;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dev.dnpm.etl.processor.config.AppConfiguration;
|
||||
import dev.dnpm.etl.processor.config.AppFhirConfig;
|
||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Date;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Consent.ConsentProvisionType;
|
||||
import org.hl7.fhir.r4.model.Identifier;
|
||||
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
|
||||
@ -27,17 +20,13 @@ import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
|
||||
|
||||
@ContextConfiguration(classes = {AppConfiguration.class, ObjectMapper.class})
|
||||
@TestPropertySource(properties = {"app.consent.gics.enabled=true",
|
||||
"app.consent.gics.uri=http://localhost:8090/ttp-fhir/fhir/gics"})
|
||||
@ -63,7 +52,6 @@ public class GicsConsentServiceTest {
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
mockRestServiceServer = MockRestServiceServer.createServer(appConfiguration.restTemplate());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -72,12 +60,10 @@ public class GicsConsentServiceTest {
|
||||
new ParametersParameterComponent().setName("consented")
|
||||
.setValue(new BooleanType().setValue(true)));
|
||||
|
||||
mockRestServiceServer.expect(
|
||||
requestTo("http://localhost:8090/ttp-fhir/fhir/gics"
|
||||
+ GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||
.encodeResourceToString(responseConsented),
|
||||
MediaType.APPLICATION_JSON));
|
||||
mockRestServiceServer.expect(requestTo(
|
||||
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT))
|
||||
.andRespond(withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||
.encodeResourceToString(responseConsented), MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
|
||||
assertThat(consentStatus).isEqualTo(TtpConsentStatus.BROAD_CONSENT_GIVEN);
|
||||
@ -89,11 +75,10 @@ public class GicsConsentServiceTest {
|
||||
new ParametersParameterComponent().setName("consented")
|
||||
.setValue(new BooleanType().setValue(false)));
|
||||
|
||||
mockRestServiceServer.expect(
|
||||
requestTo("http://localhost:8090/ttp-fhir/fhir/gics"
|
||||
+ GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||
.encodeResourceToString(responseRevoced),
|
||||
mockRestServiceServer.expect(requestTo(
|
||||
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT))
|
||||
.andRespond(withSuccess(
|
||||
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(responseRevoced),
|
||||
MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
|
||||
@ -104,15 +89,13 @@ public class GicsConsentServiceTest {
|
||||
@Test
|
||||
void gicsParameterInvalid() {
|
||||
final OperationOutcome responseErrorOutcome = new OperationOutcome().addIssue(
|
||||
new OperationOutcomeIssueComponent().setSeverity(
|
||||
IssueSeverity.ERROR).setCode(IssueType.PROCESSING)
|
||||
.setDiagnostics("Invalid policy parameter..."));
|
||||
new OperationOutcomeIssueComponent().setSeverity(IssueSeverity.ERROR)
|
||||
.setCode(IssueType.PROCESSING).setDiagnostics("Invalid policy parameter..."));
|
||||
|
||||
mockRestServiceServer.expect(
|
||||
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||
.encodeResourceToString(responseErrorOutcome),
|
||||
MediaType.APPLICATION_JSON));
|
||||
.encodeResourceToString(responseErrorOutcome), MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
|
||||
assertThat(consentStatus).isEqualTo(TtpConsentStatus.FAILED_TO_ASK);
|
||||
@ -122,51 +105,19 @@ public class GicsConsentServiceTest {
|
||||
void buildRequestParameterCurrentPolicyStatesForPersonTest() {
|
||||
|
||||
String pid = "12345678";
|
||||
var result = GicsConsentService.buildRequestParameterCurrentPolicyStatesForPerson(gIcsConfigProperties,
|
||||
pid, Date.from(Instant.now()),gIcsConfigProperties.getGenomDeConsentDomainName());
|
||||
var result = GicsConsentService.buildRequestParameterCurrentPolicyStatesForPerson(
|
||||
gIcsConfigProperties, pid, Date.from(Instant.now()),
|
||||
gIcsConfigProperties.getGenomDeConsentDomainName());
|
||||
|
||||
assertThat(result.getParameter().size()).as("should contain 3 parameter resources").isEqualTo(3);
|
||||
assertThat(result.getParameter().size()).as("should contain 3 parameter resources")
|
||||
.isEqualTo(3);
|
||||
|
||||
assertThat(((StringType)result.getParameter("domain").getValue()).getValue()).isEqualTo(gIcsConfigProperties.getGenomDeConsentDomainName());
|
||||
assertThat(((Identifier)result.getParameter("personIdentifier").getValue()).getValue()).isEqualTo(pid);
|
||||
assertThat(((StringType) result.getParameter("domain").getValue()).getValue()).isEqualTo(
|
||||
gIcsConfigProperties.getGenomDeConsentDomainName());
|
||||
assertThat(
|
||||
((Identifier) result.getParameter("personIdentifier").getValue()).getValue()).isEqualTo(
|
||||
pid);
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-07-23T00:00:00+02:00,PERMIT,expect permit",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-06-23T00:00:00+02:00,PERMIT,expect permit date is exactly on start",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2055-06-23T00:00:00+02:00,PERMIT,expect permit date is exactly on end",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2021-06-23T00:00:00+02:00,NULL,date is before start",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2060-06-23T00:00:00+02:00,NULL,date is after end",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,XXXX,2025-07-23T00:00:00+02:00,NULL,system not found - therefore expect NULL",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.27,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-07-23T00:00:00+02:00,DENY,provision is denied"})
|
||||
void getProvisionTypeByPolicyCode(String code, String system, String timeStamp, String expected,
|
||||
String desc) {
|
||||
|
||||
var testData = getDummyBroadConsent();
|
||||
|
||||
Date requestDate = Date.from(OffsetDateTime.parse(timeStamp).toInstant());
|
||||
|
||||
var result = gicsConsentService.getProvisionTypeByPolicyCode(testData, code, system, requestDate);
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result).isNotEmpty();
|
||||
|
||||
assertThat(result.get()).as(desc).isEqualTo(ConsentProvisionType.valueOf(expected));
|
||||
}
|
||||
|
||||
private Bundle getDummyBroadConsent() {
|
||||
|
||||
InputStream bundle;
|
||||
try {
|
||||
bundle = new ClassPathResource(
|
||||
"fake_broadConsent_gics_response_permit.json").getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return FhirContext.forR4().newJsonParser().parseResource(Bundle.class, bundle);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.ukw.ccc.bwhc.dto.*
|
||||
import de.ukw.ccc.bwhc.dto.Consent.Status
|
||||
import dev.dnpm.etl.processor.CustomMediaType
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.ConsentByMtbFile
|
||||
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||
@ -68,7 +68,7 @@ class MtbFileRestControllerTest {
|
||||
) {
|
||||
this.requestProcessor = requestProcessor
|
||||
val controller = MtbFileRestController(requestProcessor,
|
||||
ConsentCheckFileBased()
|
||||
ConsentByMtbFile()
|
||||
)
|
||||
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||
}
|
||||
@ -220,7 +220,7 @@ class MtbFileRestControllerTest {
|
||||
) {
|
||||
this.requestProcessor = requestProcessor
|
||||
val controller = MtbFileRestController(requestProcessor,
|
||||
ConsentCheckFileBased()
|
||||
ConsentByMtbFile()
|
||||
)
|
||||
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import de.ukw.ccc.bwhc.dto.Patient
|
||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties
|
||||
import dev.dnpm.etl.processor.config.JacksonConfig
|
||||
import dev.dnpm.etl.processor.services.ConsentProcessor
|
||||
import dev.dnpm.etl.processor.services.TransformationServiceTest
|
||||
import dev.dnpm.etl.processor.services.ConsentProcessorTest
|
||||
import dev.pcvolkmer.mv64e.mtb.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
@ -252,7 +252,7 @@ class ExtensionsTest {
|
||||
|
||||
|
||||
val bundle = Bundle()
|
||||
val dummyConsent = TransformationServiceTest.getDummyConsent()
|
||||
val dummyConsent = ConsentProcessorTest.getDummyGenomDeConsent()
|
||||
dummyConsent.patient.reference = "Patient/$CLEAN_PATIENT_ID"
|
||||
bundle.addEntry().resource = dummyConsent
|
||||
|
||||
|
@ -0,0 +1,160 @@
|
||||
package dev.dnpm.etl.processor.services
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties
|
||||
import dev.dnpm.etl.processor.config.JacksonConfig
|
||||
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||
import dev.pcvolkmer.mv64e.mtb.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import org.hl7.fhir.r4.model.CodeableConcept
|
||||
import org.hl7.fhir.r4.model.Coding
|
||||
import org.hl7.fhir.r4.model.Consent
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.CsvSource
|
||||
import org.mockito.Mock
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.time.Instant
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
|
||||
@ExtendWith(MockitoExtension::class)
|
||||
class ConsentProcessorTest {
|
||||
|
||||
private lateinit var gicsConsentService: GicsConsentService
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
private lateinit var gIcsConfigProperties: GIcsConfigProperties
|
||||
private lateinit var fhirContext: FhirContext
|
||||
private lateinit var consentProcessor: ConsentProcessor
|
||||
|
||||
@BeforeEach
|
||||
fun setups(
|
||||
@Mock gicsConsentService: GicsConsentService,
|
||||
) {
|
||||
|
||||
this.gIcsConfigProperties = GIcsConfigProperties(null, null, null, true)
|
||||
val jacksonConfig = JacksonConfig()
|
||||
this.objectMapper = jacksonConfig.objectMapper()
|
||||
this.fhirContext = JacksonConfig.fhirContext()
|
||||
this.gicsConsentService = gicsConsentService
|
||||
|
||||
this.consentProcessor =
|
||||
ConsentProcessor(gIcsConfigProperties, objectMapper, fhirContext, gicsConsentService)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun consentOk() {
|
||||
assertThat(consentProcessor.toString()).isNotNull
|
||||
// prep gICS response
|
||||
doAnswer { getDummyBroadConsentBundle() }.whenever(gicsConsentService)
|
||||
.getBroadConsent(any(), any())
|
||||
doAnswer { Bundle() }.whenever(gicsConsentService)
|
||||
.getGenomDeConsent(any(), any())
|
||||
|
||||
val inputMtb = Mtb.builder()
|
||||
.patient(Patient.builder().id("d611d429-5003-11f0-a144-661e92ac9503").build()).build()
|
||||
val checkResult = consentProcessor.consentGatedCheckAndTryEmbedding(inputMtb)
|
||||
|
||||
assertThat(checkResult).isTrue
|
||||
assertThat(inputMtb.metadata.researchConsents).hasSize(13)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getDummyGenomDeConsent(): Consent {
|
||||
val consent = Consent()
|
||||
consent.id = "consent 1 id"
|
||||
consent.patient.reference = "Patient/1234-pat1"
|
||||
|
||||
consent.provision.setType(
|
||||
Consent.ConsentProvisionType.fromCode(
|
||||
"deny"
|
||||
)
|
||||
)
|
||||
consent.provision.period.start =
|
||||
Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
consent.provision.period.end =
|
||||
Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
|
||||
val addProvision1 = consent.provision.addProvision()
|
||||
addProvision1.setType(Consent.ConsentProvisionType.fromCode("permit"))
|
||||
addProvision1.period.start = Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
addProvision1.period.end = Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
addProvision1.code.addLast(
|
||||
CodeableConcept(
|
||||
Coding(
|
||||
"https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV",
|
||||
"Teilnahme",
|
||||
"Teilnahme am Modellvorhaben und Einwilligung zur Genomsequenzierung"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val addProvision2 = consent.provision.addProvision()
|
||||
addProvision2.setType(Consent.ConsentProvisionType.fromCode("deny"))
|
||||
addProvision2.period.start = Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
addProvision2.period.end = Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
addProvision2.code.addLast(
|
||||
CodeableConcept(
|
||||
Coding(
|
||||
"https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV",
|
||||
"Rekontaktierung",
|
||||
"Re-Identifizierung meiner Daten über die Vertrauensstelle beim Robert Koch-Institut und in die erneute Kontaktaufnahme durch meine behandelnde Ärztin oder meinen behandelnden Arzt"
|
||||
)
|
||||
)
|
||||
)
|
||||
return consent
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-07-23T00:00:00+02:00,PERMIT,expect permit",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-06-23T00:00:00+02:00,PERMIT,expect permit date is exactly on start",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2055-06-23T00:00:00+02:00,PERMIT,expect permit date is exactly on end",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2021-06-23T00:00:00+02:00,NULL,date is before start",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2060-06-23T00:00:00+02:00,NULL,date is after end",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.8,XXXX,2025-07-23T00:00:00+02:00,NULL,system not found - therefore expect NULL",
|
||||
"2.16.840.1.113883.3.1937.777.24.5.3.27,urn:oid:2.16.840.1.113883.3.1937.777.24.5.3,2025-07-23T00:00:00+02:00,DENY,provision is denied"
|
||||
)
|
||||
fun getProvisionTypeByPolicyCode(
|
||||
code: String?, system: String?, timeStamp: String, expected: String?,
|
||||
desc: String?
|
||||
) {
|
||||
val testData = getDummyBroadConsentBundle()
|
||||
|
||||
val requestDate = Date.from(OffsetDateTime.parse(timeStamp).toInstant())
|
||||
|
||||
val result: Consent.ConsentProvisionType =
|
||||
consentProcessor.getProvisionTypeByPolicyCode(testData, code, system, requestDate)
|
||||
assertThat(result).isNotNull()
|
||||
|
||||
|
||||
assertThat(result).`as`(desc)
|
||||
.isEqualTo(Consent.ConsentProvisionType.valueOf(expected!!))
|
||||
}
|
||||
|
||||
fun getDummyBroadConsentBundle(): Bundle {
|
||||
val bundle: InputStream?
|
||||
try {
|
||||
bundle = ClassPathResource(
|
||||
"fake_broadConsent_gics_response_permit.json"
|
||||
).getInputStream()
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
||||
return FhirContext.forR4().newJsonParser()
|
||||
.parseResource<Bundle>(Bundle::class.java, bundle)
|
||||
}
|
||||
|
||||
}
|
@ -34,8 +34,6 @@ import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||
import dev.pcvolkmer.mv64e.mtb.MvhMetadata
|
||||
import dev.pcvolkmer.mv64e.mtb.Provision
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource
|
||||
import org.hl7.fhir.r4.model.CodeableConcept
|
||||
import org.hl7.fhir.r4.model.Coding
|
||||
import java.time.Instant
|
||||
import java.util.Date
|
||||
|
||||
@ -145,7 +143,7 @@ class TransformationServiceTest {
|
||||
.date(Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))).build()
|
||||
)
|
||||
).build()
|
||||
val consent = getDummyConsent()
|
||||
val consent = ConsentProcessorTest.getDummyGenomDeConsent()
|
||||
|
||||
mvhMetadata.researchConsents = mutableListOf()
|
||||
mvhMetadata.researchConsents.add(mapOf(consent.id to consent as IBaseResource))
|
||||
@ -157,51 +155,5 @@ class TransformationServiceTest {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getDummyConsent(): org.hl7.fhir.r4.model.Consent {
|
||||
val modelVorhabenConsent = org.hl7.fhir.r4.model.Consent()
|
||||
modelVorhabenConsent.id = "consent 1 id"
|
||||
modelVorhabenConsent.patient.reference = "Patient/1234-pat1"
|
||||
|
||||
modelVorhabenConsent.provision.setType(
|
||||
org.hl7.fhir.r4.model.Consent.ConsentProvisionType.fromCode(
|
||||
"deny"
|
||||
)
|
||||
)
|
||||
modelVorhabenConsent.provision.period.start =
|
||||
Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
modelVorhabenConsent.provision.period.end =
|
||||
Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
|
||||
|
||||
val addProvision1 = modelVorhabenConsent.provision.addProvision()
|
||||
addProvision1.setType(org.hl7.fhir.r4.model.Consent.ConsentProvisionType.fromCode("permit"))
|
||||
addProvision1.period.start = Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
addProvision1.period.end = Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
addProvision1.code.addLast(
|
||||
CodeableConcept(
|
||||
Coding(
|
||||
"https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV",
|
||||
"Teilnahme",
|
||||
"Teilnahme am Modellvorhaben und Einwilligung zur Genomsequenzierung"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val addProvision2 = modelVorhabenConsent.provision.addProvision()
|
||||
addProvision2.setType(org.hl7.fhir.r4.model.Consent.ConsentProvisionType.fromCode("deny"))
|
||||
addProvision2.period.start = Date.from(Instant.parse("2025-06-23T00:00:00.00Z"))
|
||||
addProvision2.period.end = Date.from(Instant.parse("3000-01-01T00:00:00.00Z"))
|
||||
addProvision2.code.addLast(
|
||||
CodeableConcept(
|
||||
Coding(
|
||||
"https://ths-greifswald.de/fhir/CodeSystem/gics/Policy/GenomDE_MV",
|
||||
"Rekontaktierung",
|
||||
"Re-Identifizierung meiner Daten über die Vertrauensstelle beim Robert Koch-Institut und in die erneute Kontaktaufnahme durch meine behandelnde Ärztin oder meinen behandelnden Arzt"
|
||||
)
|
||||
)
|
||||
)
|
||||
return modelVorhabenConsent
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user