diff --git a/legalconsenthub-backend/api/legalconsenthub.yml b/legalconsenthub-backend/api/legalconsenthub.yml index 89c45e4..af782cb 100644 --- a/legalconsenthub-backend/api/legalconsenthub.yml +++ b/legalconsenthub-backend/api/legalconsenthub.yml @@ -14,6 +14,7 @@ security: - bearerAuth: [] paths: + ####### Application Forms ####### /application-forms: get: summary: Get all ApplicationForms @@ -133,6 +134,7 @@ paths: "503": $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + ####### Application Form Templates ####### /application-form-templates: get: summary: Get all ApplicationFormTemplates @@ -246,6 +248,7 @@ paths: "503": $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + ####### Users ####### /users/{id}: parameters: - name: id @@ -291,54 +294,7 @@ paths: "503": $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - /comments: - get: - summary: Get all comments - operationId: getAllComments - tags: - - comment - responses: - "200": - description: Paged list of comments - content: - application/json: - schema: - $ref: "#/components/schemas/PagedCommentDto" - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - post: - summary: Create a new comment - operationId: createComment - tags: - - comment - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateCommentDto" - responses: - "201": - description: Successfully created comment - content: - application/json: - schema: - $ref: "#/components/schemas/CommentDto" - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - + ####### Comments ####### /comments/{id}: parameters: - name: id @@ -347,14 +303,20 @@ paths: schema: type: string format: uuid - get: - summary: Get a specific comment - operationId: getCommentById + put: + summary: Update a comment + operationId: updateComment tags: - comment + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CommentDto" responses: "200": - description: Get comment by ID + description: Successfully updated comment content: application/json: schema: @@ -384,6 +346,77 @@ paths: "503": $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + /application-forms/{applicationFormId}/comments: + parameters: + - name: applicationFormId + in: path + required: true + schema: + type: string + format: uuid + get: + summary: Get comments for specific application form + operationId: getCommentsByApplicationFormId + tags: + - comment + responses: + "200": + description: Get comments for application form ID + content: + application/json: + schema: + $ref: "#/components/schemas/PagedCommentDto" + "400": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" + "401": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" + "500": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" + "503": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + + /application-forms/{applicationFormId}/form-elements/{formElementId}/comments: + parameters: + - name: applicationFormId + in: path + required: true + schema: + type: string + format: uuid + - name: formElementId + in: path + required: true + schema: + type: string + format: uuid + post: + summary: Create a new comment for a form element + operationId: createComment + tags: + - comment + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateCommentDto" + responses: + "201": + description: Successfully created comment + content: + application/json: + schema: + $ref: "#/components/schemas/CommentDto" + "400": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" + "401": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" + "500": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" + "503": + $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + + ####### Roles ####### /roles: get: summary: Get all roles @@ -479,6 +512,7 @@ paths: "503": $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" + ####### Files ####### /files: get: summary: Get all files @@ -656,8 +690,6 @@ components: $ref: "#/components/schemas/FormOptionDto" type: $ref: "#/components/schemas/FormElementType" - comments: - $ref: "#/components/schemas/PagedCommentDto" CreateFormElementDto: type: object @@ -716,6 +748,7 @@ components: required: - id - message + - applicationFormId - formElementId - createdAt - modifiedAt @@ -726,6 +759,9 @@ components: format: uuid message: type: string + applicationFormId: + type: string + format: uuid formElementId: type: string format: uuid @@ -742,9 +778,12 @@ components: type: object required: - message + - createdBy properties: message: type: string + createdBy: + $ref: "#/components/schemas/UserDto" PagedCommentDto: type: object diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/Comment.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/Comment.kt index 4e967a2..ba036fc 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/Comment.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/Comment.kt @@ -1,5 +1,6 @@ package com.betriebsratkanzlei.legalconsenthub.comment; +import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm import com.betriebsratkanzlei.legalconsenthub.form_element.FormElement import com.betriebsratkanzlei.legalconsenthub.user.User import jakarta.persistence.AttributeOverride @@ -41,6 +42,10 @@ class Comment( @Column(nullable = false) var modifiedAt: LocalDateTime? = null, + @ManyToOne + @JoinColumn(name = "application_form_id", nullable = false) + var applicationForm: ApplicationForm? = null, + @ManyToOne @JoinColumn(name = "form_element_id", nullable = false) var formElement: FormElement? = null, diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentController.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentController.kt new file mode 100644 index 0000000..659c158 --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentController.kt @@ -0,0 +1,47 @@ +package com.betriebsratkanzlei.legalconsenthub.comment + +import com.betriebsratkanzlei.legalconsenthub_api.api.CommentApi +import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto +import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto +import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.RestController +import java.util.UUID + +@RestController +class CommentController( + val commentService: CommentService, val commentMapper: CommentMapper, val pagedCommentMapper: PagedCommentMapper +) : CommentApi { + override fun createComment( + applicationFormId: UUID, + formElementId: UUID, + createCommentDto: CreateCommentDto + ): ResponseEntity { + return ResponseEntity.ok( + commentMapper.toCommentDto( + commentService.createComment(applicationFormId, formElementId, createCommentDto) + ) + ) + } + + override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity { + return ResponseEntity.ok( + pagedCommentMapper.toPagedCommentDto( + commentService.getComments(applicationFormId) + ) + ) + } + + override fun updateComment(id: UUID, commentDto: CommentDto): ResponseEntity { + return ResponseEntity.ok( + commentMapper.toCommentDto( + commentService.updateComment(commentDto) + ) + ) + } + + override fun deleteComment(id: UUID): ResponseEntity { + commentService.deleteCommentByID(id) + return ResponseEntity.noContent().build() + } +} diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentMapper.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentMapper.kt index 681291a..894c612 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentMapper.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentMapper.kt @@ -1,14 +1,22 @@ package com.betriebsratkanzlei.legalconsenthub.comment +import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormRepository +import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException import com.betriebsratkanzlei.legalconsenthub.error.FormElementNotFoundException import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementRepository import com.betriebsratkanzlei.legalconsenthub.user.UserMapper import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto +import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto import org.springframework.stereotype.Component import java.time.LocalDateTime +import java.util.UUID @Component -class CommentMapper(private val userMapper: UserMapper, private val formElementRepository: FormElementRepository) { +class CommentMapper( + private val userMapper: UserMapper, + private val applicationFormRepository: ApplicationFormRepository, + private val formElementRepository: FormElementRepository +) { fun toCommentDto(comment: Comment): CommentDto { return CommentDto( id = comment.id ?: throw IllegalStateException("Comment ID must not be null!"), @@ -16,12 +24,17 @@ class CommentMapper(private val userMapper: UserMapper, private val formElementR createdAt = comment.createdAt ?: LocalDateTime.now(), modifiedAt = comment.modifiedAt ?: LocalDateTime.now(), createdBy = userMapper.toUserDto(comment.createdBy), + applicationFormId = comment.applicationForm?.id + ?: throw IllegalStateException("ApplicationForm ID must not be null!"), formElementId = comment.formElement?.id ?: throw IllegalStateException("FormElement ID must not be null!"), ) } fun toComment(commentDto: CommentDto): Comment { - val formElement = formElementRepository.findById(commentDto.formElementId).orElseThrow { FormElementNotFoundException(commentDto.formElementId) } + val applicationForm = applicationFormRepository.findById(commentDto.applicationFormId) + .orElseThrow { ApplicationFormNotFoundException(commentDto.applicationFormId) } + val formElement = formElementRepository.findById(commentDto.formElementId) + .orElseThrow { FormElementNotFoundException(commentDto.formElementId) } return Comment( id = commentDto.id, @@ -29,6 +42,21 @@ class CommentMapper(private val userMapper: UserMapper, private val formElementR createdAt = commentDto.createdAt, modifiedAt = commentDto.modifiedAt, createdBy = userMapper.toUser(commentDto.createdBy), + applicationForm = applicationForm, + formElement = formElement + ) + } + + fun toComment(applicationFormId: UUID, formElementId: UUID, commentDto: CreateCommentDto): Comment { + val applicationForm = applicationFormRepository.findById(applicationFormId) + .orElseThrow { FormElementNotFoundException(applicationFormId) } + val formElement = formElementRepository.findById(formElementId) + .orElseThrow { FormElementNotFoundException(formElementId) } + + return Comment( + message = commentDto.message, + createdBy = userMapper.toUser(commentDto.createdBy), + applicationForm = applicationForm, formElement = formElement ) } diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentRepository.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentRepository.kt index d16f313..84b6d28 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentRepository.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentRepository.kt @@ -1,8 +1,13 @@ package com.betriebsratkanzlei.legalconsenthub.comment +import com.betriebsratkanzlei.legalconsenthub.form_element.FormElement +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository import java.util.UUID @Repository -interface CommentRepository : JpaRepository +interface CommentRepository : JpaRepository { + fun findAllByFormElement(formElement: FormElement, pageable: Pageable): Page +} diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentService.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentService.kt new file mode 100644 index 0000000..cce172c --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/comment/CommentService.kt @@ -0,0 +1,67 @@ +package com.betriebsratkanzlei.legalconsenthub.comment + +import com.betriebsratkanzlei.legalconsenthub.error.CommentNotCreatedException +import com.betriebsratkanzlei.legalconsenthub.error.CommentNotDeletedException +import com.betriebsratkanzlei.legalconsenthub.error.CommentNotFoundException +import com.betriebsratkanzlei.legalconsenthub.error.CommentNotUpdatedException +import com.betriebsratkanzlei.legalconsenthub.error.FormElementNotFoundException +import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementRepository +import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto +import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageRequest +import org.springframework.stereotype.Service +import java.util.UUID + +@Service +class CommentService( + private val commentRepository: CommentRepository, + private val formElementRepository: FormElementRepository, + private val commentMapper: CommentMapper +) { + + fun createComment(applicationFormId: UUID, formElementId: UUID, createCommentDto: CreateCommentDto): Comment { + val comment = commentMapper.toComment(applicationFormId, formElementId, createCommentDto) + val savedComment: Comment + try { + savedComment = commentRepository.save(comment) + } catch (e: Exception) { + throw CommentNotCreatedException(e) + } + + return savedComment + } + + fun getCommentById(id: UUID): Comment { + return commentRepository.findById(id).orElseThrow { CommentNotFoundException(id) } + } + + fun getComments(formElementId: UUID): Page { + val formElement = + formElementRepository.findById(formElementId).orElseThrow { FormElementNotFoundException(formElementId) } + val pageable = PageRequest.of(0, 10) + return commentRepository.findAllByFormElement(formElement, pageable) + } + + fun updateComment(commentDto: CommentDto): Comment { + // TODO find statt mappen? + val comment = commentMapper.toComment(commentDto) + val updatedComment: Comment + + try { + updatedComment = commentRepository.save(comment) + } catch (e: Exception) { + throw CommentNotUpdatedException(e, commentDto.id) + } + + return updatedComment + } + + fun deleteCommentByID(id: UUID) { + try { + commentRepository.deleteById(id) + } catch (e: Exception) { + throw CommentNotDeletedException(e) + } + } +} diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotCreatedException.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotCreatedException.kt new file mode 100644 index 0000000..a330ce5 --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotCreatedException.kt @@ -0,0 +1,3 @@ +package com.betriebsratkanzlei.legalconsenthub.error + +class CommentNotCreatedException(e: Exception): RuntimeException("Couldn't create comment", e) diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotDeletedException.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotDeletedException.kt new file mode 100644 index 0000000..d221865 --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotDeletedException.kt @@ -0,0 +1,3 @@ +package com.betriebsratkanzlei.legalconsenthub.error + +class CommentNotDeletedException(e: Exception): RuntimeException("Couldn't delete comment", e) diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotFoundException.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotFoundException.kt new file mode 100644 index 0000000..2e7d64c --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotFoundException.kt @@ -0,0 +1,5 @@ +package com.betriebsratkanzlei.legalconsenthub.error + +import java.util.UUID + +class CommentNotFoundException(id: UUID): RuntimeException("Couldn't find comment with ID: $id") diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotUpdatedException.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotUpdatedException.kt new file mode 100644 index 0000000..c9ebe54 --- /dev/null +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/error/CommentNotUpdatedException.kt @@ -0,0 +1,5 @@ +package com.betriebsratkanzlei.legalconsenthub.error + +import java.util.UUID + +class CommentNotUpdatedException(e: Exception, id: UUID): RuntimeException("Couldn't update comment with ID: $id", e) diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElement.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElement.kt index 29381ef..b57f329 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElement.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElement.kt @@ -31,8 +31,5 @@ class FormElement ( var options: MutableList = mutableListOf(), @Column(nullable = false) - var type: FormElementType, - - @OneToMany(mappedBy = "formElement", cascade = [CascadeType.ALL], orphanRemoval = true) - var comments: MutableList = mutableListOf(), + var type: FormElementType ) diff --git a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElementMapper.kt b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElementMapper.kt index d75dac7..4a8c466 100644 --- a/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElementMapper.kt +++ b/legalconsenthub-backend/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub/form_element/FormElementMapper.kt @@ -2,20 +2,14 @@ package com.betriebsratkanzlei.legalconsenthub.form_element import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormRepository -import com.betriebsratkanzlei.legalconsenthub.comment.CommentMapper -import com.betriebsratkanzlei.legalconsenthub.comment.PagedCommentMapper import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException import com.betriebsratkanzlei.legalconsenthub_api.model.CreateFormElementDto import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementDto -import org.springframework.data.domain.PageImpl -import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Component @Component class FormElementMapper( private val formOptionMapper: FormOptionMapper, - private val commentMapper: CommentMapper, - private val pagedCommentMapper: PagedCommentMapper, private val applicationFormRepository: ApplicationFormRepository ) { fun toFormElementDto(formElement: FormElement): FormElementDto { @@ -24,14 +18,7 @@ class FormElementMapper( options = formElement.options.map { formOptionMapper.toFormOptionDto(it) }, type = formElement.type, applicationFormId = formElement.applicationForm?.id - ?: throw IllegalStateException("ApplicationForm ID must not be null!"), - comments = if (formElement.comments.size > 0) pagedCommentMapper.toPagedCommentDto( - PageImpl( - formElement.comments.toList(), - PageRequest.of(0, formElement.comments.size), - formElement.comments.size.toLong() - ) - ) else null + ?: throw IllegalStateException("ApplicationForm ID must not be null!") ) } @@ -43,8 +30,7 @@ class FormElementMapper( id = formElement.id, options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(), type = formElement.type, - applicationForm = applicationForm, - comments = formElement.comments?.content?.map { commentMapper.toComment(it) }?.toMutableList() ?: mutableListOf() + applicationForm = applicationForm ) } @@ -53,7 +39,7 @@ class FormElementMapper( id = null, options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(), type = formElement.type, - applicationForm = applicationForm, + applicationForm = applicationForm ) } }