mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-01 14:12:55 +00:00
refactor: renamed misleading enum value TtpConsentStatus.IGNORED to TtpConsentStatus.UNKNOWN_CHECK_FILE also impl. ConsentCheckedIgnored has been renamed to ConsentCheckFileBased - since consent status should never be ignored.
Also renamed ICheckConsent.isConsented ICheckConsent.getTtpConsentStatus since new method name is more descriptive.
This commit is contained in:
@ -91,7 +91,7 @@ Wurde die Verwendung von gPAS konfiguriert, so sind weitere Angaben zu konfiguri
|
||||
Ab gIcs Version 2.13.0 kann per [REST-Schnittstelle](https://simplifier.net/guide/ttp-fhir-gateway-ig/ImplementationGuide-markdown-Einwilligungsmanagement-Operations-isConsented?version=current) der Einwilligungsstatus abgefragt werden.
|
||||
Vor der MTB-Übertragung kann der zum Sendezeitpunkt verfügbarer Einwilligungsstatus über Endpunkt *isConsented* abgefragt werden.
|
||||
|
||||
Falls diese Prüfung aktiviert wurde, wird der Einwilligungsstatus dem in der MTB Datei vorgezogen und überschreibt diesen.
|
||||
Falls diese Prüfung aktiviert wurde, wird der Einwilligungsstatus dem in der MTB Datei vorgezogen und der Wert in der MTB-Datei wird dabei ignoriert.
|
||||
Falls in diesem Fall die Statusprüfung fehlschlägt, wird Status **abgelehnt** angenommen.
|
||||
Ist die Prüfung über gIcs deaktiviert, wird der eingetragene Einwilligungsstatus der übermittelten MTB Datei geprüft.
|
||||
|
||||
|
@ -23,7 +23,7 @@ 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.ConsentCheckedIgnored
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.security.TokenRepository
|
||||
@ -55,7 +55,7 @@ import org.springframework.test.web.servlet.post
|
||||
classes = [
|
||||
MtbFileRestController::class,
|
||||
AppSecurityConfiguration::class,
|
||||
ConsentCheckedIgnored::class, ICheckConsent::class
|
||||
ConsentCheckFileBased::class, ICheckConsent::class
|
||||
]
|
||||
)
|
||||
@MockitoBean(types = [TokenRepository::class, RequestProcessor::class])
|
||||
@ -143,7 +143,7 @@ class MtbFileRestControllerTest {
|
||||
status { isAccepted() }
|
||||
}
|
||||
|
||||
verify(requestProcessor, times(1)).processDeletion(anyValueClass(), eq(TtpConsentStatus.IGNORED))
|
||||
verify(requestProcessor, times(1)).processDeletion(anyValueClass(), eq(TtpConsentStatus.UNKNOWN_CHECK_FILE))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -0,0 +1,9 @@
|
||||
package dev.dnpm.etl.processor.consent;
|
||||
|
||||
public class ConsentCheckFileBased implements ICheckConsent{
|
||||
|
||||
@Override
|
||||
public TtpConsentStatus getTtpConsentStatus(String personIdentifierValue) {
|
||||
return TtpConsentStatus.UNKNOWN_CHECK_FILE;
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package dev.dnpm.etl.processor.consent;
|
||||
|
||||
public class ConsentCheckedIgnored implements ICheckConsent{
|
||||
|
||||
@Override
|
||||
public TtpConsentStatus isConsented(String personIdentifierValue) {
|
||||
return TtpConsentStatus.IGNORED;
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ public class GicsConsentService implements ICheckConsent {
|
||||
throw new IllegalArgumentException(
|
||||
"gICS base URL is empty - should call gICS with false configuration.");
|
||||
}
|
||||
url = UriComponentsBuilder.fromHttpUrl(gIcsBaseUri).path(IS_CONSENTED_ENDPOINT)
|
||||
url = UriComponentsBuilder.fromUriString(gIcsBaseUri).path(IS_CONSENTED_ENDPOINT)
|
||||
.toUriString();
|
||||
}
|
||||
return url;
|
||||
@ -147,7 +147,7 @@ public class GicsConsentService implements ICheckConsent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TtpConsentStatus isConsented(String personIdentifierValue) {
|
||||
public TtpConsentStatus getTtpConsentStatus(String personIdentifierValue) {
|
||||
var parameter = GicsConsentService.getIsConsentedParam(gIcsConfigProperties,
|
||||
personIdentifierValue);
|
||||
|
||||
@ -176,10 +176,8 @@ public class GicsConsentService implements ICheckConsent {
|
||||
return TtpConsentStatus.CONSENT_MISSING_OR_REJECTED;
|
||||
}
|
||||
} else if (response instanceof OperationOutcome outcome) {
|
||||
|
||||
log.error(
|
||||
"failed to get consent status from ttp. probably configuration error. outcome: ",
|
||||
fhirContext.newJsonParser().encodeToString(outcome));
|
||||
log.error("failed to get consent status from ttp. probably configuration error. "
|
||||
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
|
||||
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
|
@ -3,6 +3,6 @@ package dev.dnpm.etl.processor.consent;
|
||||
|
||||
public interface ICheckConsent {
|
||||
|
||||
TtpConsentStatus isConsented(String personIdentifierValue);
|
||||
TtpConsentStatus getTtpConsentStatus(String personIdentifierValue);
|
||||
|
||||
}
|
||||
|
@ -7,12 +7,14 @@ public enum TtpConsentStatus {
|
||||
CONSENTED,
|
||||
|
||||
CONSENT_MISSING_OR_REJECTED,
|
||||
|
||||
/**
|
||||
* Due technical problems consent status is unknown
|
||||
*/
|
||||
FAILED_TO_ASK,
|
||||
|
||||
/**
|
||||
* We assume received files are consented
|
||||
* Consent status is validate via file property 'consent.status'
|
||||
*/
|
||||
IGNORED
|
||||
UNKNOWN_CHECK_FILE
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
package dev.dnpm.etl.processor.config
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckedIgnored
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.ICheckConsent
|
||||
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||
import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult
|
||||
@ -183,7 +183,7 @@ class AppConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
fun constService(): ICheckConsent {
|
||||
return ConsentCheckedIgnored()
|
||||
return ConsentCheckFileBased()
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -77,12 +77,12 @@ class KafkaInputListener(
|
||||
} else {
|
||||
logger.debug("Accepted MTB File and process deletion")
|
||||
if (requestId.isBlank()) {
|
||||
requestProcessor.processDeletion(patientId, TtpConsentStatus.IGNORED)
|
||||
requestProcessor.processDeletion(patientId, TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
} else {
|
||||
requestProcessor.processDeletion(
|
||||
patientId,
|
||||
requestId,
|
||||
TtpConsentStatus.IGNORED
|
||||
TtpConsentStatus.UNKNOWN_CHECK_FILE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class MtbFileRestController(
|
||||
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
|
||||
fun mtbFile(@RequestBody mtbFile: MtbFile): ResponseEntity<Unit> {
|
||||
val consentStatusBooleanPair = checkConsentStatus(mtbFile)
|
||||
var ttpConsentStatus = consentStatusBooleanPair.first
|
||||
val ttpConsentStatus = consentStatusBooleanPair.first
|
||||
val isConsentOK = consentStatusBooleanPair.second
|
||||
if (isConsentOK) {
|
||||
logger.debug("Accepted MTB File (bwHC V1) for processing")
|
||||
@ -63,14 +63,14 @@ class MtbFileRestController(
|
||||
}
|
||||
|
||||
private fun checkConsentStatus(mtbFile: MtbFile): Pair<TtpConsentStatus, Boolean> {
|
||||
var ttpConsentStatus = constService.isConsented(mtbFile.patient.id)
|
||||
var ttpConsentStatus = constService.getTtpConsentStatus(mtbFile.patient.id)
|
||||
|
||||
val isConsentOK =
|
||||
(ttpConsentStatus.equals(TtpConsentStatus.IGNORED) && mtbFile.consent.status == Consent.Status.ACTIVE) ||
|
||||
(ttpConsentStatus.equals(TtpConsentStatus.UNKNOWN_CHECK_FILE) && mtbFile.consent.status == Consent.Status.ACTIVE) ||
|
||||
ttpConsentStatus.equals(
|
||||
TtpConsentStatus.CONSENTED
|
||||
)
|
||||
if (ttpConsentStatus.equals(TtpConsentStatus.IGNORED) && mtbFile.consent.status == Consent.Status.REJECTED) {
|
||||
if (ttpConsentStatus.equals(TtpConsentStatus.UNKNOWN_CHECK_FILE) && mtbFile.consent.status == Consent.Status.REJECTED) {
|
||||
// in case ttp check is disabled - we propagate rejected status anyway
|
||||
ttpConsentStatus = TtpConsentStatus.CONSENT_MISSING_OR_REJECTED
|
||||
}
|
||||
@ -87,7 +87,7 @@ class MtbFileRestController(
|
||||
@DeleteMapping(path = ["{patientId}"])
|
||||
fun deleteData(@PathVariable patientId: String): ResponseEntity<Unit> {
|
||||
logger.debug("Accepted patient ID to process deletion")
|
||||
requestProcessor.processDeletion(PatientId(patientId), TtpConsentStatus.IGNORED)
|
||||
requestProcessor.processDeletion(PatientId(patientId), TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
return ResponseEntity.accepted().build()
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ class RequestProcessor(
|
||||
val requestStatus: RequestStatus = when (isConsented) {
|
||||
TtpConsentStatus.CONSENT_MISSING_OR_REJECTED -> RequestStatus.NO_CONSENT
|
||||
TtpConsentStatus.FAILED_TO_ASK -> RequestStatus.ERROR
|
||||
TtpConsentStatus.CONSENTED, TtpConsentStatus.IGNORED -> RequestStatus.UNKNOWN
|
||||
TtpConsentStatus.CONSENTED, TtpConsentStatus.UNKNOWN_CHECK_FILE -> RequestStatus.UNKNOWN
|
||||
}
|
||||
|
||||
requestService.save(
|
||||
|
@ -48,7 +48,7 @@ public class GicsConsentServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void isConsented() {
|
||||
void getTtpConsentStatus() {
|
||||
final Parameters responseConsented = new Parameters().addParameter(
|
||||
new ParametersParameterComponent().setName("consented")
|
||||
.setValue(new BooleanType().setValue(true)));
|
||||
@ -59,7 +59,7 @@ public class GicsConsentServiceTest {
|
||||
.encodeResourceToString(responseConsented),
|
||||
MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.isConsented("123456");
|
||||
var consentStatus = gicsConsentService.getTtpConsentStatus("123456");
|
||||
assertThat(consentStatus).isEqualTo(TtpConsentStatus.CONSENTED);
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ public class GicsConsentServiceTest {
|
||||
.encodeResourceToString(responseRevoced),
|
||||
MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.isConsented("123456");
|
||||
var consentStatus = gicsConsentService.getTtpConsentStatus("123456");
|
||||
assertThat(consentStatus).isEqualTo(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED);
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ public class GicsConsentServiceTest {
|
||||
.encodeResourceToString(responseErrorOutcome),
|
||||
MediaType.APPLICATION_JSON));
|
||||
|
||||
var consentStatus = gicsConsentService.isConsented("123456");
|
||||
var consentStatus = gicsConsentService.getTtpConsentStatus("123456");
|
||||
assertThat(consentStatus).isEqualTo(TtpConsentStatus.FAILED_TO_ASK);
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ class KafkaInputListenerTest {
|
||||
|
||||
verify(requestProcessor, times(1)).processDeletion(
|
||||
anyValueClass(),
|
||||
eq(TtpConsentStatus.IGNORED)
|
||||
eq(TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
)
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ class KafkaInputListenerTest {
|
||||
)
|
||||
)
|
||||
verify(requestProcessor, times(1)).processDeletion(anyValueClass(), anyValueClass(), eq(
|
||||
TtpConsentStatus.IGNORED))
|
||||
TtpConsentStatus.UNKNOWN_CHECK_FILE))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -181,7 +181,7 @@ class KafkaInputListenerTest {
|
||||
)
|
||||
)
|
||||
verify(requestProcessor, times(0)).processDeletion(anyValueClass(), anyValueClass(), eq(
|
||||
TtpConsentStatus.IGNORED))
|
||||
TtpConsentStatus.UNKNOWN_CHECK_FILE))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.ConsentCheckedIgnored
|
||||
import dev.dnpm.etl.processor.consent.ConsentCheckFileBased
|
||||
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||
@ -67,7 +67,9 @@ class MtbFileRestControllerTest {
|
||||
@Mock requestProcessor: RequestProcessor
|
||||
) {
|
||||
this.requestProcessor = requestProcessor
|
||||
val controller = MtbFileRestController(requestProcessor, ConsentCheckedIgnored())
|
||||
val controller = MtbFileRestController(requestProcessor,
|
||||
ConsentCheckFileBased()
|
||||
)
|
||||
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||
}
|
||||
|
||||
@ -113,7 +115,7 @@ class MtbFileRestControllerTest {
|
||||
|
||||
verify(requestProcessor, times(1)).processDeletion(
|
||||
anyValueClass(),
|
||||
org.mockito.kotlin.eq(TtpConsentStatus.IGNORED)
|
||||
org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -147,7 +149,7 @@ class MtbFileRestControllerTest {
|
||||
@ValueSource(strings = ["ACTIVE", "REJECTED"])
|
||||
fun shouldProcessPostRequest(status: String) {
|
||||
|
||||
whenever(gicsConsentService.isConsented(any())).thenReturn(TtpConsentStatus.CONSENTED)
|
||||
whenever(gicsConsentService.getTtpConsentStatus(any())).thenReturn(TtpConsentStatus.CONSENTED)
|
||||
|
||||
mockMvc.post("/mtbfile") {
|
||||
content =
|
||||
@ -167,7 +169,7 @@ class MtbFileRestControllerTest {
|
||||
@ValueSource(strings = ["ACTIVE", "REJECTED"])
|
||||
fun shouldProcessPostRequestWithRejectedConsent(status: String) {
|
||||
|
||||
whenever(gicsConsentService.isConsented(any())).thenReturn(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED)
|
||||
whenever(gicsConsentService.getTtpConsentStatus(any())).thenReturn(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED)
|
||||
|
||||
mockMvc.post("/mtbfile") {
|
||||
content =
|
||||
@ -197,9 +199,9 @@ class MtbFileRestControllerTest {
|
||||
|
||||
verify(requestProcessor, times(1)).processDeletion(
|
||||
anyValueClass(),
|
||||
org.mockito.kotlin.eq(TtpConsentStatus.IGNORED)
|
||||
org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
)
|
||||
verify(gicsConsentService, times(0)).isConsented(any())
|
||||
verify(gicsConsentService, times(0)).getTtpConsentStatus(any())
|
||||
|
||||
}
|
||||
}
|
||||
@ -217,7 +219,9 @@ class MtbFileRestControllerTest {
|
||||
@Mock requestProcessor: RequestProcessor
|
||||
) {
|
||||
this.requestProcessor = requestProcessor
|
||||
val controller = MtbFileRestController(requestProcessor, ConsentCheckedIgnored())
|
||||
val controller = MtbFileRestController(requestProcessor,
|
||||
ConsentCheckFileBased()
|
||||
)
|
||||
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||
}
|
||||
|
||||
@ -264,7 +268,7 @@ class MtbFileRestControllerTest {
|
||||
|
||||
verify(requestProcessor, times(1)).processDeletion(
|
||||
anyValueClass(), org.mockito.kotlin.eq(
|
||||
TtpConsentStatus.IGNORED
|
||||
TtpConsentStatus.UNKNOWN_CHECK_FILE
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -282,7 +286,9 @@ class MtbFileRestControllerTest {
|
||||
@Mock requestProcessor: RequestProcessor
|
||||
) {
|
||||
this.requestProcessor = requestProcessor
|
||||
val controller = MtbFileRestController(requestProcessor, ConsentCheckedIgnored())
|
||||
val controller = MtbFileRestController(requestProcessor,
|
||||
ConsentCheckFileBased()
|
||||
)
|
||||
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||
}
|
||||
|
||||
|
@ -344,7 +344,7 @@ class RequestProcessorTest {
|
||||
MtbFileSender.Response(status = RequestStatus.UNKNOWN)
|
||||
}.whenever(sender).send(any<DeleteRequest>())
|
||||
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.IGNORED)
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
|
||||
val requestCaptor = argumentCaptor<Request>()
|
||||
verify(requestService, times(1)).save(requestCaptor.capture())
|
||||
@ -362,7 +362,7 @@ class RequestProcessorTest {
|
||||
MtbFileSender.Response(status = RequestStatus.SUCCESS)
|
||||
}.whenever(sender).send(any<DeleteRequest>())
|
||||
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.IGNORED)
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
|
||||
val eventCaptor = argumentCaptor<ResponseEvent>()
|
||||
verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
|
||||
@ -380,7 +380,7 @@ class RequestProcessorTest {
|
||||
MtbFileSender.Response(status = RequestStatus.ERROR)
|
||||
}.whenever(sender).send(any<DeleteRequest>())
|
||||
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.IGNORED)
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
|
||||
val eventCaptor = argumentCaptor<ResponseEvent>()
|
||||
verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
|
||||
@ -392,7 +392,7 @@ class RequestProcessorTest {
|
||||
fun testShouldSendDeleteRequestWithPseudonymErrorAndSaveErrorRequestStatus() {
|
||||
doThrow(RuntimeException()).whenever(pseudonymizeService).patientPseudonym(anyValueClass())
|
||||
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.IGNORED)
|
||||
this.requestProcessor.processDeletion(TEST_PATIENT_ID, isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE)
|
||||
|
||||
val requestCaptor = argumentCaptor<Request>()
|
||||
verify(requestService, times(1)).save(requestCaptor.capture())
|
||||
|
Reference in New Issue
Block a user