summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md17
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt4
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt180
3 files changed, 126 insertions, 75 deletions
diff --git a/README.md b/README.md
index 5d76a96..8575aff 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,16 @@ Die Erkennung von Duplikaten ist normalerweise immer aktiv, kann jedoch über de
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung direkt an das bwHC-Backend gesendet.
+Ein HTTP Request kann, angenommen die Installation erfolgte auf dem Host `dnpm.example.com` an nachfolgende URLs gesendet werden:
+
+| HTTP-Request | URL | Consent-Status im Datensatz | Bemerkung |
+|--------------|-----------------------------------------|-----------------------------|---------------------------------------------------------------------------------|
+| POST | `https://dnpm.example.com/mtb` | ACTIVE | Die Anwendung verarbeitet den eingehenden Datensatz |
+| POST | `https://dnpm.example.com/mtb` | REJECT | Die Anwendung sendet einen Lösch-Request für die im Datensatz angegebene Pat-ID |
+| DELETE | `https://dnpm.example.com/mtb/12345678` | - | Die Anwendung sendet einen Lösch-Request für Pat-ID `12345678` |
+
+Anstelle des Pfads `/mtb` kann auch, wie in Version 0.9 und älter üblich, `/mtbfile` verwendet werden.
+
### Datenübermittlung mit Apache Kafka
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung an Apache Kafka übergeben.
@@ -42,6 +52,9 @@ In Versionen des ETL-Processors **nach Version 0.10** werden die folgenden Konfi
* `APP_KAFKA_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_TOPIC`
* `APP_KAFKA_RESPONSE_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`
+Der Pfad zum Versenden von MTB-Daten ist nun offiziell `/mtb`.
+In Versionen **nach Version 0.10** wird die Unterstützung des Pfads `/mtbfile` entfernt.
+
### Pseudonymisierung der Patienten-ID
Wenn eine URI zu einer gPAS-Instanz (Version >= 2023.1.0) angegeben ist, wird diese verwendet.
@@ -161,7 +174,7 @@ zur Nutzung des MTB-File-Endpunkts eine HTTP-Basic-Authentifizierung voraussetze
![Tokenverwaltung](docs/tokens.png)
-In diesem Fall können den Endpunkt für das Onkostar-Plugin **[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)** wie folgt konfigurieren:
+In diesem Fall kann der Endpunkt für das Onkostar-Plugin **[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)** wie folgt konfiguriert werden:
```
https://testonkostar:MTg1NTL...NGU4@etl.example.com/mtbfile
@@ -266,7 +279,7 @@ Dieses Vorgehen empfiehlt sich, wenn Sie gespeicherte Records nachgelagert für
### Antworten und Statusauswertung
-Anfragen and bwHC-Backend aus Versionen bis 0.9.x wurden wie folgt behandelt:
+Anfragen an das bwHC-Backend aus Versionen bis 0.9.x wurden wie folgt behandelt:
| HTTP-Response | Status |
|----------------|-----------|
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
index ded485c..123a84f 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt
@@ -1,7 +1,7 @@
/*
* This file is part of ETL-Processor
*
- * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
+ * 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
@@ -28,7 +28,7 @@ import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
-@RequestMapping(path = ["mtbfile"])
+@RequestMapping(path = ["mtbfile", "mtb"])
class MtbFileRestController(
private val requestProcessor: RequestProcessor,
) {
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt
index 3e5b53a..ade27b4 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt
@@ -1,7 +1,7 @@
/*
* This file is part of ETL-Processor
*
- * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
+ * 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
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import de.ukw.ccc.bwhc.dto.*
import dev.dnpm.etl.processor.services.RequestProcessor
import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock
@@ -40,62 +41,122 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders
@ExtendWith(MockitoExtension::class)
class MtbFileRestControllerTest {
- private lateinit var mockMvc: MockMvc
+ private val objectMapper = ObjectMapper()
- private lateinit var requestProcessor: RequestProcessor
+ @Nested
+ inner class BwhcRequests {
- private val objectMapper = ObjectMapper()
+ private lateinit var mockMvc: MockMvc
+
+ private lateinit var requestProcessor: RequestProcessor
+
+ @BeforeEach
+ fun setup(
+ @Mock requestProcessor: RequestProcessor
+ ) {
+ this.requestProcessor = requestProcessor
+ val controller = MtbFileRestController(requestProcessor)
+ this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
+ }
+
+ @Test
+ fun shouldProcessPostRequest() {
+ mockMvc.post("/mtbfile") {
+ content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.ACTIVE))
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ verify(requestProcessor, times(1)).processMtbFile(any())
+ }
+
+ @Test
+ fun shouldProcessPostRequestWithRejectedConsent() {
+ mockMvc.post("/mtbfile") {
+ content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.REJECTED))
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ verify(requestProcessor, times(1)).processDeletion(anyValueClass())
+ }
+
+ @Test
+ fun shouldProcessDeleteRequest() {
+ mockMvc.delete("/mtbfile/TEST_12345678").andExpect {
+ status {
+ isAccepted()
+ }
+ }
- @BeforeEach
- fun setup(
- @Mock requestProcessor: RequestProcessor
- ) {
- this.requestProcessor = requestProcessor
- val controller = MtbFileRestController(requestProcessor)
- this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
+ verify(requestProcessor, times(1)).processDeletion(anyValueClass())
+ }
}
- @Test
- fun shouldProcessMtbFilePostRequest() {
- val mtbFile = MtbFile.builder()
- .withPatient(
- Patient.builder()
- .withId("TEST_12345678")
- .withBirthDate("2000-08-08")
- .withGender(Patient.Gender.MALE)
- .build()
- )
- .withConsent(
- Consent.builder()
- .withId("1")
- .withStatus(Consent.Status.ACTIVE)
- .withPatient("TEST_12345678")
- .build()
- )
- .withEpisode(
- Episode.builder()
- .withId("1")
- .withPatient("TEST_12345678")
- .withPeriod(PeriodStart("2023-08-08"))
- .build()
- )
- .build()
+ @Nested
+ inner class BwhcRequestsWithAlias {
+
+ private lateinit var mockMvc: MockMvc
- mockMvc.post("/mtbfile") {
- content = objectMapper.writeValueAsString(mtbFile)
- contentType = MediaType.APPLICATION_JSON
- }.andExpect {
- status {
- isAccepted()
+ private lateinit var requestProcessor: RequestProcessor
+
+ @BeforeEach
+ fun setup(
+ @Mock requestProcessor: RequestProcessor
+ ) {
+ this.requestProcessor = requestProcessor
+ val controller = MtbFileRestController(requestProcessor)
+ this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
+ }
+
+ @Test
+ fun shouldProcessPostRequest() {
+ mockMvc.post("/mtb") {
+ content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.ACTIVE))
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
}
+
+ verify(requestProcessor, times(1)).processMtbFile(any())
}
- verify(requestProcessor, times(1)).processMtbFile(any())
+ @Test
+ fun shouldProcessPostRequestWithRejectedConsent() {
+ mockMvc.post("/mtb") {
+ content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.REJECTED))
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ verify(requestProcessor, times(1)).processDeletion(anyValueClass())
+ }
+
+ @Test
+ fun shouldProcessDeleteRequest() {
+ mockMvc.delete("/mtb/TEST_12345678").andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ verify(requestProcessor, times(1)).processDeletion(anyValueClass())
+ }
}
- @Test
- fun shouldProcessMtbFilePostRequestWithRejectedConsent() {
- val mtbFile = MtbFile.builder()
+ companion object {
+ fun bwhcMtbFileContent(consentStatus: Consent.Status) = MtbFile.builder()
.withPatient(
Patient.builder()
.withId("TEST_12345678")
@@ -106,7 +167,7 @@ class MtbFileRestControllerTest {
.withConsent(
Consent.builder()
.withId("1")
- .withStatus(Consent.Status.REJECTED)
+ .withStatus(consentStatus)
.withPatient("TEST_12345678")
.build()
)
@@ -118,28 +179,5 @@ class MtbFileRestControllerTest {
.build()
)
.build()
-
- mockMvc.post("/mtbfile") {
- content = objectMapper.writeValueAsString(mtbFile)
- contentType = MediaType.APPLICATION_JSON
- }.andExpect {
- status {
- isAccepted()
- }
- }
-
- verify(requestProcessor, times(1)).processDeletion(anyValueClass())
}
-
- @Test
- fun shouldProcessMtbFileDeleteRequest() {
- mockMvc.delete("/mtbfile/TEST_12345678").andExpect {
- status {
- isAccepted()
- }
- }
-
- verify(requestProcessor, times(1)).processDeletion(anyValueClass())
- }
-
-} \ No newline at end of file
+}