summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/config/AppConfigProperties.kt13
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt12
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt4
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/pseudonym/VfpsPseudonymGenerator.kt82
4 files changed, 110 insertions, 1 deletions
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfigProperties.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfigProperties.kt
index f0766a4..5cec5eb 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfigProperties.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfigProperties.kt
@@ -63,6 +63,18 @@ data class GPasConfigProperties(
}
}
+@ConfigurationProperties(VfpsConfigProperties.NAME)
+data class VfpsConfigProperties(
+ val uri: String? = null,
+ val patientNamespace: String = "etl-processor",
+ val genomDeTanNamespace: String = "ccdn",
+ val token: String? = null,
+) {
+ companion object {
+ const val NAME = "app.pseudonymize.vfps"
+ }
+}
+
@ConfigurationProperties(ConsentConfigProperties.NAME)
data class ConsentConfigProperties(
var service: ConsentService = ConsentService.NONE,
@@ -177,6 +189,7 @@ data class UserProperties(
enum class PseudonymGenerator {
BUILDIN,
GPAS,
+ VFPS,
}
enum class ConsentService {
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt
index 54f4c6f..44fd719 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt
@@ -68,6 +68,7 @@ import kotlin.time.toJavaDuration
AppConfigProperties::class,
PseudonymizeConfigProperties::class,
GPasConfigProperties::class,
+ VfpsConfigProperties::class,
ConsentConfigProperties::class,
GIcsConfigProperties::class,
]
@@ -257,6 +258,17 @@ class AppConfiguration {
)
}
+ @ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "VFPS")
+ @Bean
+ fun vfpsPseudonymGenerator(
+ configProperties: VfpsConfigProperties,
+ retryTemplate: RetryTemplate,
+ restTemplate: RestTemplate,
+ ): Generator {
+ logger.info("Selected 'VfpsPseudonym Generator'")
+ return VfpsPseudonymGenerator(configProperties, retryTemplate, restTemplate)
+ }
+
@Bean
fun jdbcConfiguration(): AbstractJdbcConfiguration {
return AppJdbcConfiguration()
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
index 9eec9f3..c74345d 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt
@@ -30,7 +30,9 @@ class PseudonymizeService(
) {
fun patientPseudonym(patientId: PatientId): PatientPseudonym =
when (generator) {
- is GpasPseudonymGenerator -> PatientPseudonym(generator.generate(patientId.value))
+ is GpasPseudonymGenerator,
+ is VfpsPseudonymGenerator,
+ -> PatientPseudonym(generator.generate(patientId.value))
else ->
PatientPseudonym("${configProperties.prefix}_${generator.generate(patientId.value)}")
}
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/VfpsPseudonymGenerator.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/VfpsPseudonymGenerator.kt
new file mode 100644
index 0000000..0a616b5
--- /dev/null
+++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/VfpsPseudonymGenerator.kt
@@ -0,0 +1,82 @@
+package dev.dnpm.etl.processor.pseudonym
+
+import dev.dnpm.etl.processor.config.VfpsConfigProperties
+import org.springframework.http.HttpEntity
+import org.springframework.http.HttpHeaders
+import org.springframework.http.MediaType
+import org.springframework.retry.support.RetryTemplate
+import org.springframework.web.client.RestClientException
+import org.springframework.web.client.RestTemplate
+import org.springframework.web.client.postForObject
+import org.springframework.web.util.UriComponentsBuilder
+
+class VfpsPseudonymGenerator(
+ private val configProperties: VfpsConfigProperties,
+ private val retryTemplate: RetryTemplate,
+ private val restTemplate: RestTemplate,
+) : Generator {
+ private val uri =
+ configProperties.uri?.takeIf { it.isNotBlank() }
+ ?: throw IllegalArgumentException("vFPS URI must be configured")
+
+ private val headers =
+ HttpHeaders().apply {
+ contentType = MediaType.APPLICATION_JSON
+ configProperties.token
+ ?.takeIf { it.isNotBlank() }
+ ?.let { setBearerAuth(it) }
+ }
+
+ override fun generate(id: String): String =
+ execute {
+ retryTemplate.execute<String, Exception> {
+ request(configProperties.patientNamespace, "pseudonyms", id)
+ }
+ }
+
+ override fun generateGenomDeTan(id: String): String =
+ execute {
+ request(configProperties.genomDeTanNamespace, "pseudonyms:append", id)
+ }
+
+ private fun request(
+ namespace: String,
+ operation: String,
+ id: String,
+ ): String {
+ val url =
+ UriComponentsBuilder
+ .fromUriString(uri)
+ .pathSegment("v1", "namespaces", namespace, operation)
+ .build()
+ .encode()
+ .toUri()
+
+ val response =
+ restTemplate.postForObject<VfpsResponse>(
+ url,
+ HttpEntity(mapOf("originalValue" to id), headers),
+ )
+
+ return response
+ ?.pseudonym
+ ?.pseudonymValue
+ ?.takeIf { it.isNotBlank() }
+ ?: throw PseudonymRequestFailed("No pseudonym returned from vFPS")
+ }
+
+ private fun execute(action: () -> String): String =
+ try {
+ action()
+ } catch (ex: RestClientException) {
+ throw PseudonymRequestFailed("vFPS request failed", ex)
+ }
+}
+
+private data class VfpsResponse(
+ val pseudonym: VfpsPseudonym? = null,
+)
+
+private data class VfpsPseudonym(
+ val pseudonymValue: String? = null,
+)