feat: Init backend

This commit is contained in:
2025-02-21 08:26:58 +01:00
parent 84e701131f
commit e7557ce2e2
29 changed files with 1802 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package com.betriebsratkanzlei.legalconsenthub
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.config.EnableJpaAuditing
@SpringBootApplication
@EnableJpaAuditing
class LegalconsenthubApplication
fun main(args: Array<String>) {
runApplication<LegalconsenthubApplication>(*args)
}

View File

@@ -0,0 +1,38 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.formelement.FormElement
import jakarta.persistence.CascadeType
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
import jakarta.persistence.OneToMany
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import java.time.OffsetDateTime
import java.util.Date
import java.util.UUID
@Entity
@EntityListeners(AuditingEntityListener::class)
class ApplicationForm(
@Id
@GeneratedValue
var id: UUID? = null,
@OneToMany(mappedBy = "applicationForm", cascade = [CascadeType.ALL], orphanRemoval = true)
var formElements: MutableList<FormElement> = mutableListOf(),
@CreatedDate
@Column(nullable = false)
var createdAt: LocalDateTime? = null,
@LastModifiedDate
@Column(nullable = false)
var modifiedAt: LocalDateTime? = null
// TODO LastModifiedBy User einfügen
)

View File

@@ -0,0 +1,46 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub_api.api.ApplicationFormApi
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import java.util.UUID
@RestController
class ApplicationFormController(
val applicationFormService: ApplicationFormService,
val pagedApplicationFormMapper: PagedApplicationFormMapper,
val applicationFormMapper: ApplicationFormMapper,
) : ApplicationFormApi {
override fun createApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ResponseEntity<ApplicationFormDto> {
return ResponseEntity.ok(
applicationFormMapper.toApplicationFormDto(
applicationFormService.createApplicationForm(createApplicationFormDto)
)
)
}
override fun deleteApplicationForm(id: UUID): ResponseEntity<Unit> {
applicationFormService.deleteApplicationFormByID(id)
return ResponseEntity.noContent().build()
}
override fun getAllApplicationForms(): ResponseEntity<PagedApplicationFormDto> {
return ResponseEntity.ok(
pagedApplicationFormMapper.toPagedApplicationFormDto(
applicationFormService.getApplicationForms()
)
)
}
override fun getApplicationFormById(id: UUID): ResponseEntity<ApplicationFormDto> {
return ResponseEntity.ok(
applicationFormMapper.toApplicationFormDto(
applicationFormService.getApplicationFormById(id)
)
)
}
}

View File

@@ -0,0 +1,35 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
import org.springframework.stereotype.Component
import java.time.LocalDateTime
@Component
class ApplicationFormMapper(private val formElementMapper: FormElementMapper) {
fun toApplicationFormDto(applicationForm: ApplicationForm): ApplicationFormDto {
return ApplicationFormDto(
id = applicationForm.id ?: throw IllegalStateException("ApplicationForm ID must not be null!"),
formElements = applicationForm.formElements.map { formElementMapper.toFormElementDto(it) },
createdAt = applicationForm.createdAt ?: LocalDateTime.now(),
modifiedAt = applicationForm.modifiedAt ?: LocalDateTime.now()
)
}
fun toApplicationForm(applicationForm: ApplicationFormDto): ApplicationForm {
return ApplicationForm(
id = applicationForm.id,
formElements = applicationForm.formElements.map { formElementMapper.toFormElement(it) }.toMutableList(),
createdAt = applicationForm.createdAt,
modifiedAt = applicationForm.modifiedAt
)
}
fun toApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ApplicationForm {
val applicationForm = ApplicationForm()
applicationForm.formElements = createApplicationFormDto.formElements
.map { formElementMapper.toFormElement(it, applicationForm) }
.toMutableList()
return applicationForm
}
}

View File

@@ -0,0 +1,8 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
import java.util.UUID
@Repository
interface ApplicationFormRepository : JpaRepository<ApplicationForm, UUID>

View File

@@ -0,0 +1,61 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotCreatedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotDeletedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotUpdatedException
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import java.util.UUID
@Service
class ApplicationFormService(
private val applicationFormRepository: ApplicationFormRepository,
private val applicationFormMapper: ApplicationFormMapper
) {
fun createApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ApplicationForm {
val applicationForm = applicationFormMapper.toApplicationForm(createApplicationFormDto)
val savedApplicationForm: ApplicationForm
try {
savedApplicationForm = applicationFormRepository.save(applicationForm)
} catch (e: Exception) {
throw ApplicationFormNotCreatedException(e)
}
return savedApplicationForm
}
fun getApplicationFormById(id: UUID): ApplicationForm {
return applicationFormRepository.findById(id).orElseThrow { ApplicationFormNotFoundException(id) }
}
fun getApplicationForms(): Page<ApplicationForm> {
val pageable = PageRequest.of(0, 10)
return applicationFormRepository.findAll(pageable)
}
fun updateApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {
val applicationForm = applicationFormMapper.toApplicationForm(applicationFormDto)
val updatedApplicationForm: ApplicationForm
try {
updatedApplicationForm = applicationFormRepository.save(applicationForm)
} catch (e: Exception) {
throw ApplicationFormNotUpdatedException(e, applicationFormDto.id)
}
return updatedApplicationForm
}
fun deleteApplicationFormByID(id: UUID) {
try {
applicationFormRepository.deleteById(id)
} catch (e: Exception) {
throw ApplicationFormNotDeletedException(e)
}
}
}

View File

@@ -0,0 +1,44 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
import com.betriebsratkanzlei.legalconsenthub.formelement.FormElement
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateFormElementDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementDto
import org.springframework.stereotype.Component
@Component
class FormElementMapper(
private val formOptionMapper: FormOptionMapper,
private val applicationFormRepository: ApplicationFormRepository
) {
fun toFormElementDto(formElement: FormElement): FormElementDto {
return FormElementDto(
id = formElement.id ?: throw IllegalStateException("ApplicationForm ID must not be null!"),
options = formElement.options.map { formOptionMapper.toFormOptionDto(it) },
type = formElement.type,
applicationFormId = formElement.applicationForm?.id
?: throw IllegalStateException("ApplicationForm ID must not be null!")
)
}
fun toFormElement(formElement: FormElementDto): FormElement {
val applicationForm = applicationFormRepository.findById(formElement.applicationFormId)
.orElseThrow { ApplicationFormNotFoundException(formElement.applicationFormId) }
return FormElement(
id = formElement.id,
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
type = formElement.type,
applicationForm = applicationForm
)
}
fun toFormElement(formElement: CreateFormElementDto, applicationForm: ApplicationForm): FormElement {
return FormElement(
id = null,
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
type = formElement.type,
applicationForm = applicationForm
)
}
}

View File

@@ -0,0 +1,26 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.formelement.FormOption
import com.betriebsratkanzlei.legalconsenthub_api.model.FormOptionDto
import org.springframework.stereotype.Component
@Component
class FormOptionMapper {
fun toFormOptionDto(formOption: FormOption): FormOptionDto {
return FormOptionDto(
value = formOption.value,
label = formOption.label,
processingPurpose = formOption.processingPurpose,
employeeDataCategory = formOption.employeeDataCategory
)
}
fun toFormOption(formOptionDto: FormOptionDto): FormOption {
return FormOption(
value = formOptionDto.value,
label = formOptionDto.label,
processingPurpose = formOptionDto.processingPurpose,
employeeDataCategory = formOptionDto.employeeDataCategory
)
}
}

View File

@@ -0,0 +1,26 @@
package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
import org.springframework.data.domain.Page
import org.springframework.stereotype.Component
@Component
class PagedApplicationFormMapper(private val applicationFormMapper: ApplicationFormMapper) {
fun toPagedApplicationFormDto(pagedApplicationForm: Page<ApplicationForm>): PagedApplicationFormDto {
return PagedApplicationFormDto(
content = pagedApplicationForm.content.map { applicationFormMapper.toApplicationFormDto(it) },
number = pagedApplicationForm.number,
propertySize = pagedApplicationForm.size,
numberOfElements = pagedApplicationForm.numberOfElements,
last = pagedApplicationForm.isLast,
totalPages = pagedApplicationForm.totalPages,
totalElements = pagedApplicationForm.totalElements,
empty = pagedApplicationForm.isEmpty,
first = pagedApplicationForm.isFirst,
)
}
// fun toApplicationForm(applicationForm: ApplicationFormDto): ApplicationForm {}
// fun toApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ApplicationForm
}

View File

@@ -0,0 +1,3 @@
package com.betriebsratkanzlei.legalconsenthub.error
class ApplicationFormNotCreatedException(e: Exception): RuntimeException("Couldn't create application form", e)

View File

@@ -0,0 +1,3 @@
package com.betriebsratkanzlei.legalconsenthub.error
class ApplicationFormNotDeletedException(e: Exception): RuntimeException("Couldn't delete application form", e)

View File

@@ -0,0 +1,5 @@
package com.betriebsratkanzlei.legalconsenthub.error
import java.util.UUID
class ApplicationFormNotFoundException(id: UUID): RuntimeException("Couldn't find application form with ID: $id")

View File

@@ -0,0 +1,5 @@
package com.betriebsratkanzlei.legalconsenthub.error
import java.util.UUID
class ApplicationFormNotUpdatedException(e: Exception, id: UUID): RuntimeException("Couldn't update application form with ID: $id", e)

View File

@@ -0,0 +1,53 @@
package com.betriebsratkanzlei.legalconsenthub.error
import com.betriebsratkanzlei.legalconsenthub_api.model.ProblemDetails
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.ResponseStatus
import java.net.URI
@ControllerAdvice
class ExceptionHandler {
var logger = LoggerFactory.getLogger(ExceptionHandler::class.java)
@ResponseBody
@ExceptionHandler(ApplicationFormNotFoundException::class)
@ResponseStatus(HttpStatus.NOT_FOUND)
fun handleNotFoundError(e: Exception): ResponseEntity<ProblemDetails> {
logger.warn(e.message, e)
return ResponseEntity.status(HttpStatus.NOT_FOUND).contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(
ProblemDetails(
title = "Not Found",
status = HttpStatus.NOT_FOUND.value(),
type = URI.create("about:blank"),
detail = e.message ?: "Something went wrong"
)
)
}
@ResponseBody
@ExceptionHandler(
ApplicationFormNotCreatedException::class,
ApplicationFormNotUpdatedException::class,
ApplicationFormNotDeletedException::class,
)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
fun handleInternalServerError(e: Exception): ResponseEntity<ProblemDetails> {
logger.warn(e.message, e)
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(
ProblemDetails(
title = "Internal Server Error",
status = HttpStatus.INTERNAL_SERVER_ERROR.value(),
type = URI.create("about:blank"),
detail = e.message ?: "Something went wrong"
)
)
}
}

View File

@@ -0,0 +1,32 @@
package com.betriebsratkanzlei.legalconsenthub.formelement;
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementType
import jakarta.persistence.CollectionTable
import jakarta.persistence.Column
import jakarta.persistence.ElementCollection
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import java.util.UUID;
@Entity
class FormElement (
@Id
@GeneratedValue
var id: UUID? = null,
@ManyToOne
@JoinColumn(name = "application_form_id", nullable = false)
var applicationForm: ApplicationForm? = null,
@ElementCollection
@CollectionTable(name = "form_element_options", joinColumns = [JoinColumn(name = "form_element_id")])
var options: MutableList<FormOption> = mutableListOf(),
@Column(nullable = false)
var type: FormElementType
)

View File

@@ -0,0 +1,21 @@
package com.betriebsratkanzlei.legalconsenthub.formelement;
import com.betriebsratkanzlei.legalconsenthub_api.model.EmployeeDataCategory
import com.betriebsratkanzlei.legalconsenthub_api.model.ProcessingPurpose;
import jakarta.persistence.Column
import jakarta.persistence.Embeddable
@Embeddable
class FormOption(
@Column(nullable = false, name = "option_value")
var value: String,
@Column(nullable = false)
var label: String,
@Column(nullable = false)
var processingPurpose: ProcessingPurpose,
@Column(nullable = false)
var employeeDataCategory: EmployeeDataCategory
)

View File

@@ -0,0 +1,17 @@
spring:
application:
name: legalconsenthub
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:testdb
username: sa
password: password
jpa:
database-platform: org.hibernate.dialect.H2Dialect
# http://localhost:8080/h2-console
h2:
console:
enabled: true

View File

@@ -0,0 +1,33 @@
spring:
application:
name: legalconsenthub
datasource:
hikari:
auto-commit: false
url: jdbc:h2:mem:legalconsenthub-database
username: user
password: pw
jpa:
show-sql: true
hibernate:
ddl-auto: create
database-platform: org.hibernate.dialect.PostgreSQLDialect
properties:
hibernate:
format_sql: true
jdbc:
batch_size: 100
order_inserts: true
enable_lazy_load_no_trans: true
liquibase:
enabled: true
drop-first: false
change-log: classpath:/db/changelog/db.changelog-master.yaml
default-schema: public
sql:
init:
platform: h2

View File

@@ -0,0 +1,3 @@
databaseChangeLog:
- include:
file: db/migrations/001-schema.sql

View File

@@ -0,0 +1,34 @@
create table application_form
(
created_at timestamp(6) not null,
modified_at timestamp(6) not null,
id uuid not null,
primary key (id)
);
create table form_element_options
(
employee_data_category tinyint not null check (employee_data_category between 0 and 3),
processing_purpose tinyint not null check (processing_purpose between 0 and 3),
form_element_id uuid not null,
label varchar(255) not null,
option_value varchar(255) not null
);
create table form_element
(
type tinyint not null check (type between 0 and 4),
application_form_id uuid not null,
id uuid not null,
primary key (id)
);
alter table if exists form_element_options
add constraint FKnq0lpby5nspv1xi27n9el6us6
foreign key (form_element_id)
references form_element;
alter table if exists form_element
add constraint FKdniyq3l10lncw48tft15js5gb
foreign key (application_form_id)
references application_form;

View File

@@ -0,0 +1,13 @@
package com.betriebsratkanzlei.legalconsenthub
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
class LegalconsenthubApplicationTests {
@Test
fun contextLoads() {
}
}