feat(fullstack): Add test application form creation
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.test_data
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormService
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionDto
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class TestDataApplicationFormService(
|
||||
private val applicationFormService: ApplicationFormService,
|
||||
) {
|
||||
private val logger = LoggerFactory.getLogger(TestDataApplicationFormService::class.java)
|
||||
private val yamlMapper = ObjectMapper(YAMLFactory()).findAndRegisterModules()
|
||||
|
||||
fun createTestDataApplicationForm(organizationId: String): ApplicationForm {
|
||||
val seededDto = loadInitialFormDto()
|
||||
|
||||
// Load template sections from seed template YAML (deterministic, no DB dependency)
|
||||
val templateDto = loadInitialFormTemplateDto()
|
||||
val templateSections =
|
||||
templateDto.formElementSections.filter { it.isTemplate == true && !it.templateReference.isNullOrBlank() }
|
||||
|
||||
// Merge seeded sections with template sections
|
||||
// Add template sections that don't already exist as templates in the seeded form
|
||||
// (templates are needed for reactive section spawning even if spawned instances exist)
|
||||
val finalSections =
|
||||
seededDto.formElementSections +
|
||||
templateSections.filter { ts ->
|
||||
seededDto.formElementSections.none { seeded ->
|
||||
seeded.isTemplate == true && seeded.templateReference == ts.templateReference
|
||||
}
|
||||
}
|
||||
|
||||
val newFormDto =
|
||||
seededDto.copy(
|
||||
id = null,
|
||||
organizationId = organizationId,
|
||||
status = ApplicationFormStatus.DRAFT,
|
||||
name = "SAP S/4HANA (Copy ${System.currentTimeMillis()})",
|
||||
isTemplate = false,
|
||||
formElementSections = finalSections,
|
||||
)
|
||||
|
||||
validateSectionSpawningInvariants(newFormDto.formElementSections)
|
||||
|
||||
return applicationFormService.createApplicationForm(newFormDto)
|
||||
}
|
||||
|
||||
private fun loadInitialFormDto(): ApplicationFormDto =
|
||||
ClassPathResource(INITIAL_FORM_RESOURCE_PATH).inputStream.use { inputStream ->
|
||||
yamlMapper.readValue(inputStream, ApplicationFormDto::class.java)
|
||||
}
|
||||
|
||||
private fun loadInitialFormTemplateDto(): ApplicationFormDto =
|
||||
ClassPathResource(INITIAL_FORM_TEMPLATE_RESOURCE_PATH).inputStream.use { inputStream ->
|
||||
yamlMapper.readValue(inputStream, ApplicationFormDto::class.java)
|
||||
}
|
||||
|
||||
private fun validateSectionSpawningInvariants(sections: List<FormElementSectionDto>) {
|
||||
val templateRefs = sections.filter { it.isTemplate == true }.mapNotNull { it.templateReference }.toSet()
|
||||
|
||||
val spawnedWithoutTemplateRef =
|
||||
sections
|
||||
.filter {
|
||||
it.isTemplate != true &&
|
||||
!it.spawnedFromElementReference.isNullOrBlank() &&
|
||||
it.templateReference.isNullOrBlank()
|
||||
}.mapNotNull { it.title }
|
||||
|
||||
if (spawnedWithoutTemplateRef.isNotEmpty()) {
|
||||
val msg =
|
||||
"Invalid seeded form: spawned sections missing templateReference: " +
|
||||
spawnedWithoutTemplateRef.joinToString(", ")
|
||||
logger.error(msg)
|
||||
throw IllegalStateException(msg)
|
||||
}
|
||||
|
||||
val triggerTemplateRefs =
|
||||
sections
|
||||
.flatMap { it.formElementSubSections }
|
||||
.flatMap { it.formElements }
|
||||
.flatMap { it.sectionSpawnTriggers ?: emptyList() }
|
||||
.map { it.templateReference }
|
||||
.filter { it.isNotBlank() }
|
||||
.toSet()
|
||||
|
||||
val missingTemplateSections = triggerTemplateRefs.minus(templateRefs)
|
||||
if (missingTemplateSections.isNotEmpty()) {
|
||||
val msg =
|
||||
"Invalid seeded form: missing template sections for triggers: " +
|
||||
missingTemplateSections.joinToString(", ")
|
||||
logger.error(msg)
|
||||
throw IllegalStateException(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val INITIAL_FORM_RESOURCE_PATH = "seed/initial_application_form.yaml"
|
||||
private const val INITIAL_FORM_TEMPLATE_RESOURCE_PATH = "seed/initial_application_form_template.yaml"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.test_data
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormMapper
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.api.TestDataApi
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
class TestDataController(
|
||||
private val testDataApplicationFormService: TestDataApplicationFormService,
|
||||
private val applicationFormMapper: ApplicationFormMapper,
|
||||
) : TestDataApi {
|
||||
@PreAuthorize(
|
||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')",
|
||||
)
|
||||
override fun createTestDataApplicationForm(organizationId: String): ResponseEntity<ApplicationFormDto> =
|
||||
ResponseEntity.status(201).body(
|
||||
applicationFormMapper.toApplicationFormDto(
|
||||
testDataApplicationFormService.createTestDataApplicationForm(organizationId),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -403,7 +403,7 @@ formElementSections:
|
||||
formElementExpectedValue: Einführung
|
||||
formElementOperator: EQUALS
|
||||
sectionSpawnTriggers:
|
||||
- templateReference: ki_details_template
|
||||
- templateReference: ki_informationen_template
|
||||
sectionSpawnConditionType: SHOW
|
||||
sectionSpawnExpectedValue: Ja
|
||||
sectionSpawnOperator: EQUALS
|
||||
@@ -444,6 +444,8 @@ formElementSections:
|
||||
- title: Rollen und Berechtigungen
|
||||
shortTitle: Rollen/Berechtigungen
|
||||
description: Vollständiges Rollen- und Berechtigungskonzept für das IT-System
|
||||
templateReference: rollen_berechtigungen_template
|
||||
titleTemplate: Rollen und Berechtigungen
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -642,6 +644,8 @@ formElementSections:
|
||||
- title: Verarbeitung von Mitarbeiterdaten
|
||||
shortTitle: Mitarbeiterdaten
|
||||
description: Angaben zur Verarbeitung von personenbezogenen Arbeitnehmerdaten
|
||||
templateReference: verarbeitung_mitarbeiterdaten_template
|
||||
titleTemplate: Verarbeitung von Mitarbeiterdaten
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -727,7 +731,7 @@ formElementSections:
|
||||
label: Export/Weitergabe (Ja/Nein + Ziel)
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
- value: '["false", "true", "false", "true", "true"]'
|
||||
- value: '[false, true, false, true, true]'
|
||||
label: Leistungs-/Verhaltenskontrolle beabsichtigt?
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: SENSITIVE
|
||||
@@ -805,7 +809,7 @@ formElementSections:
|
||||
label: Schutzmaßnahmen/Governance
|
||||
processingPurpose: SYSTEM_OPERATION
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
- value: '["true", "true", "true"]'
|
||||
- value: '[true, true, true]'
|
||||
label: Audit-Logging erforderlich
|
||||
processingPurpose: SYSTEM_OPERATION
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
@@ -843,7 +847,7 @@ formElementSections:
|
||||
columnConfig:
|
||||
sourceTableReference: rollenstamm_tabelle
|
||||
sourceColumnIndex: 0
|
||||
- value: '["true", "true", "true", "true", "true"]'
|
||||
- value: '[true, true, true, true, true]'
|
||||
label: Sichtbar (Ja/Nein)
|
||||
processingPurpose: SYSTEM_OPERATION
|
||||
employeeDataCategory: NON_CRITICAL
|
||||
@@ -918,6 +922,8 @@ formElementSections:
|
||||
- title: Löschkonzept
|
||||
shortTitle: Löschkonzept
|
||||
description: Angaben zum Löschkonzept für Verarbeitungsvorgänge, Datenkategorien und Arbeitnehmerdaten
|
||||
templateReference: loeschkonzept_template
|
||||
titleTemplate: Löschkonzept
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1080,6 +1086,8 @@ formElementSections:
|
||||
- title: Schnittstellen
|
||||
shortTitle: Schnittstellen
|
||||
description: Angaben zu Schnittstellen zwischen IT-Systemen
|
||||
templateReference: schnittstellen_template
|
||||
titleTemplate: Schnittstellen
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1152,6 +1160,8 @@ formElementSections:
|
||||
- title: Datenschutz
|
||||
shortTitle: Datenschutz
|
||||
description: Datenschutzrechtliche Angaben zur Datenverarbeitung
|
||||
templateReference: datenschutz_template
|
||||
titleTemplate: Datenschutz
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1488,6 +1498,8 @@ formElementSections:
|
||||
- title: Modul SAP Finance and Controlling (FI/CO)
|
||||
shortTitle: SAP Finance and Controlling (FI/CO)
|
||||
description: Detaillierte Informationen zum Modul
|
||||
templateReference: module_details_template
|
||||
titleTemplate: 'Modul: {{triggerValue}}'
|
||||
spawnedFromElementReference: modul_1
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1532,7 +1544,7 @@ formElementSections:
|
||||
label: Analytische Funktionen
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
- value: '["true", "true", "true", "false"]'
|
||||
- value: '[true, true, true, false]'
|
||||
label: In Nutzung
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
@@ -1626,6 +1638,8 @@ formElementSections:
|
||||
- title: Modul SAP Human Capital Management (HCM)
|
||||
shortTitle: SAP Human Capital Management (HCM)
|
||||
description: Detaillierte Informationen zum Modul
|
||||
templateReference: module_details_template
|
||||
titleTemplate: 'Modul: {{triggerValue}}'
|
||||
spawnedFromElementReference: modul_2
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1670,7 +1684,7 @@ formElementSections:
|
||||
label: Analytische Funktionen
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
- value: '["true", "true", "true", "true", "true", "false"]'
|
||||
- value: '[true, true, true, true, true, false]'
|
||||
label: In Nutzung
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
@@ -1764,6 +1778,8 @@ formElementSections:
|
||||
- title: Modul SAP Supply Chain Management (SCM)
|
||||
shortTitle: SAP Supply Chain Management (SCM)
|
||||
description: Detaillierte Informationen zum Modul
|
||||
templateReference: module_details_template
|
||||
titleTemplate: 'Modul: {{triggerValue}}'
|
||||
spawnedFromElementReference: modul_3
|
||||
formElementSubSections:
|
||||
|
||||
@@ -1808,7 +1824,7 @@ formElementSections:
|
||||
label: Analytische Funktionen
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
- value: '["true", "true", "true", "false", "true"]'
|
||||
- value: '[true, true, true, false, true]'
|
||||
label: In Nutzung
|
||||
processingPurpose: DATA_ANALYSIS
|
||||
employeeDataCategory: REVIEW_REQUIRED
|
||||
@@ -1902,6 +1918,8 @@ formElementSections:
|
||||
- title: Auswirkungen auf Arbeitnehmer
|
||||
shortTitle: Auswirkungen auf AN
|
||||
description: Auswirkungen des IT-Systems auf Arbeitnehmer, Arbeitsabläufe und Arbeitsbedingungen
|
||||
templateReference: auswirkungen_arbeitnehmer_template
|
||||
titleTemplate: Auswirkungen auf Arbeitnehmer
|
||||
spawnedFromElementReference: art_der_massnahme
|
||||
formElementSubSections:
|
||||
|
||||
@@ -2187,6 +2205,9 @@ formElementSections:
|
||||
- title: Informationen zur Künstlichen Intelligenz
|
||||
shortTitle: KI-Informationen
|
||||
description: Detaillierte Angaben zum Einsatz von Künstlicher Intelligenz gemäß EU-KI-Verordnung
|
||||
templateReference: ki_informationen_template
|
||||
titleTemplate: Informationen zur Künstlichen Intelligenz
|
||||
spawnedFromElementReference: ki_einsatz
|
||||
formElementSubSections:
|
||||
|
||||
# Risk class selection
|
||||
|
||||
Reference in New Issue
Block a user