feat(backend,api): Rework whole comment

This commit is contained in:
2025-05-10 17:18:31 +02:00
parent 6a751285dc
commit d4ea9cd3d9
12 changed files with 268 additions and 78 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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<CommentDto> {
return ResponseEntity.ok(
commentMapper.toCommentDto(
commentService.createComment(applicationFormId, formElementId, createCommentDto)
)
)
}
override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity<PagedCommentDto> {
return ResponseEntity.ok(
pagedCommentMapper.toPagedCommentDto(
commentService.getComments(applicationFormId)
)
)
}
override fun updateComment(id: UUID, commentDto: CommentDto): ResponseEntity<CommentDto> {
return ResponseEntity.ok(
commentMapper.toCommentDto(
commentService.updateComment(commentDto)
)
)
}
override fun deleteComment(id: UUID): ResponseEntity<Unit> {
commentService.deleteCommentByID(id)
return ResponseEntity.noContent().build()
}
}

View File

@@ -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
)
}

View File

@@ -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<Comment, UUID>
interface CommentRepository : JpaRepository<Comment, UUID> {
fun findAllByFormElement(formElement: FormElement, pageable: Pageable): Page<Comment>
}

View File

@@ -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<Comment> {
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)
}
}
}

View File

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

View File

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

View File

@@ -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")

View File

@@ -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)

View File

@@ -31,8 +31,5 @@ class FormElement (
var options: MutableList<FormOption> = mutableListOf(),
@Column(nullable = false)
var type: FormElementType,
@OneToMany(mappedBy = "formElement", cascade = [CascadeType.ALL], orphanRemoval = true)
var comments: MutableList<Comment> = mutableListOf(),
var type: FormElementType
)

View File

@@ -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
)
}
}