feat(#21): Replaced chat comment component with proper cursor-based commenting
This commit is contained in:
@@ -90,8 +90,8 @@ task generate_legalconsenthub_server(type: org.openapitools.generator.gradle.plu
|
||||
enumPropertyNaming: 'original',
|
||||
interfaceOnly : 'true',
|
||||
useSpringBoot3 : 'true']
|
||||
typeMappings = [DateTime: "LocalDateTime"]
|
||||
importMappings = [LocalDateTime: "java.time.LocalDateTime"]
|
||||
typeMappings = [DateTime: "Instant"]
|
||||
importMappings = [Instant: "java.time.Instant"]
|
||||
}
|
||||
|
||||
compileKotlin.dependsOn(tasks.generate_legalconsenthub_server)
|
||||
|
||||
@@ -18,7 +18,7 @@ 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.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@@ -47,8 +47,8 @@ class ApplicationForm(
|
||||
var lastModifiedBy: User,
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
var createdAt: LocalDateTime? = null,
|
||||
var createdAt: Instant? = null,
|
||||
@LastModifiedDate
|
||||
@Column(nullable = false)
|
||||
var modifiedAt: LocalDateTime? = null,
|
||||
var modifiedAt: Instant? = null,
|
||||
)
|
||||
|
||||
@@ -33,9 +33,12 @@ class ApplicationFormController(
|
||||
)
|
||||
override fun getAllApplicationForms(organizationId: String?): ResponseEntity<PagedApplicationFormDto> =
|
||||
ResponseEntity.ok(
|
||||
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
||||
applicationFormService.getApplicationForms(organizationId),
|
||||
),
|
||||
applicationFormService.getApplicationFormsWithCommentCounts(organizationId).let { result ->
|
||||
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
||||
result.page,
|
||||
result.commentCountByApplicationFormId,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@PreAuthorize(
|
||||
|
||||
@@ -19,8 +19,9 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSubSectionSna
|
||||
import org.springframework.stereotype.Service
|
||||
import org.thymeleaf.TemplateEngine
|
||||
import org.thymeleaf.context.Context
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.UUID
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionOperator as VisibilityConditionOperatorDto
|
||||
@@ -39,7 +40,7 @@ class ApplicationFormFormatService(
|
||||
|
||||
fun generatePdf(
|
||||
snapshot: ApplicationFormSnapshotDto,
|
||||
createdAt: LocalDateTime?,
|
||||
createdAt: Instant?,
|
||||
): ByteArray {
|
||||
val latexContent = generateLatex(snapshot, createdAt)
|
||||
return pdfRenderer.render(latexContent)
|
||||
@@ -58,7 +59,7 @@ class ApplicationFormFormatService(
|
||||
|
||||
fun generateLatex(
|
||||
snapshot: ApplicationFormSnapshotDto,
|
||||
createdAt: LocalDateTime?,
|
||||
createdAt: Instant?,
|
||||
): String {
|
||||
val filteredSnapshot = filterVisibleElements(snapshot)
|
||||
val exportModel = buildLatexExportModel(filteredSnapshot, createdAt)
|
||||
@@ -88,7 +89,7 @@ class ApplicationFormFormatService(
|
||||
organizationId = LatexEscaper.escape(applicationForm.organizationId),
|
||||
employer = LatexEscaper.escape("Arbeitgeber der Organisation ${applicationForm.organizationId}"),
|
||||
worksCouncil = LatexEscaper.escape("Betriebsrat der Organisation ${applicationForm.organizationId}"),
|
||||
createdAt = applicationForm.createdAt?.format(dateFormatter) ?: "",
|
||||
createdAt = applicationForm.createdAt?.atZone(ZoneId.of("Europe/Berlin"))?.format(dateFormatter) ?: "",
|
||||
sections =
|
||||
applicationForm.formElementSections.map { section ->
|
||||
LatexSection(
|
||||
@@ -116,7 +117,7 @@ class ApplicationFormFormatService(
|
||||
|
||||
private fun buildLatexExportModel(
|
||||
snapshot: ApplicationFormSnapshotDto,
|
||||
createdAt: LocalDateTime?,
|
||||
createdAt: Instant?,
|
||||
): LatexExportModel {
|
||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
|
||||
|
||||
@@ -126,7 +127,7 @@ class ApplicationFormFormatService(
|
||||
organizationId = LatexEscaper.escape(snapshot.organizationId),
|
||||
employer = LatexEscaper.escape("Arbeitgeber der Organisation ${snapshot.organizationId}"),
|
||||
worksCouncil = LatexEscaper.escape("Betriebsrat der Organisation ${snapshot.organizationId}"),
|
||||
createdAt = createdAt?.format(dateFormatter) ?: "",
|
||||
createdAt = createdAt?.atZone(ZoneId.of("Europe/Berlin"))?.format(dateFormatter) ?: "",
|
||||
sections =
|
||||
snapshot.sections.map { section ->
|
||||
LatexSection(
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.betriebsratkanzlei.legalconsenthub.user.UserMapper
|
||||
import com.betriebsratkanzlei.legalconsenthub.user.UserService
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Component
|
||||
@@ -16,6 +16,12 @@ class ApplicationFormMapper(
|
||||
private val userService: UserService,
|
||||
) {
|
||||
fun toApplicationFormDto(applicationForm: ApplicationForm): ApplicationFormDto =
|
||||
toApplicationFormDto(applicationForm, null)
|
||||
|
||||
fun toApplicationFormDto(
|
||||
applicationForm: ApplicationForm,
|
||||
commentCount: Long?,
|
||||
): ApplicationFormDto =
|
||||
ApplicationFormDto(
|
||||
id = applicationForm.id,
|
||||
name = applicationForm.name,
|
||||
@@ -30,9 +36,10 @@ class ApplicationFormMapper(
|
||||
organizationId = applicationForm.organizationId,
|
||||
createdBy = userMapper.toUserDto(applicationForm.createdBy),
|
||||
lastModifiedBy = userMapper.toUserDto(applicationForm.lastModifiedBy),
|
||||
createdAt = applicationForm.createdAt ?: LocalDateTime.now(),
|
||||
modifiedAt = applicationForm.modifiedAt ?: LocalDateTime.now(),
|
||||
createdAt = applicationForm.createdAt ?: Instant.now(),
|
||||
modifiedAt = applicationForm.modifiedAt ?: Instant.now(),
|
||||
status = applicationForm.status,
|
||||
commentCount = commentCount,
|
||||
)
|
||||
|
||||
fun toNewApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.application_form
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub.application_form_version.ApplicationFormVersionService
|
||||
import com.betriebsratkanzlei.legalconsenthub.comment.CommentRepository
|
||||
import com.betriebsratkanzlei.legalconsenthub.email.ApplicationFormCreatedEvent
|
||||
import com.betriebsratkanzlei.legalconsenthub.email.ApplicationFormSubmittedEvent
|
||||
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormInvalidStateException
|
||||
@@ -22,6 +23,11 @@ import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.UUID
|
||||
|
||||
data class ApplicationFormPageWithCommentCounts(
|
||||
val page: Page<ApplicationForm>,
|
||||
val commentCountByApplicationFormId: Map<UUID, Long>,
|
||||
)
|
||||
|
||||
@Service
|
||||
class ApplicationFormService(
|
||||
private val applicationFormRepository: ApplicationFormRepository,
|
||||
@@ -31,6 +37,7 @@ class ApplicationFormService(
|
||||
private val versionService: ApplicationFormVersionService,
|
||||
private val userService: UserService,
|
||||
private val eventPublisher: ApplicationEventPublisher,
|
||||
private val commentRepository: CommentRepository,
|
||||
) {
|
||||
fun createApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {
|
||||
val applicationForm = applicationFormMapper.toNewApplicationForm(applicationFormDto)
|
||||
@@ -62,10 +69,26 @@ class ApplicationFormService(
|
||||
}
|
||||
|
||||
fun getApplicationForms(organizationId: String?): Page<ApplicationForm> {
|
||||
val pageable = PageRequest.of(0, 10)
|
||||
val pageable = PageRequest.of(0, 100)
|
||||
return applicationFormRepository.findAllByIsTemplateFalseAndOrganizationId(organizationId, pageable)
|
||||
}
|
||||
|
||||
fun getApplicationFormsWithCommentCounts(organizationId: String?): ApplicationFormPageWithCommentCounts {
|
||||
val page = getApplicationForms(organizationId)
|
||||
val applicationFormIds = page.content.mapNotNull { it.id }
|
||||
|
||||
if (applicationFormIds.isEmpty()) {
|
||||
return ApplicationFormPageWithCommentCounts(page, emptyMap())
|
||||
}
|
||||
|
||||
val counts =
|
||||
commentRepository.countByApplicationFormIds(applicationFormIds).associate { projection ->
|
||||
projection.applicationFormId to projection.commentCount
|
||||
}
|
||||
|
||||
return ApplicationFormPageWithCommentCounts(page, counts)
|
||||
}
|
||||
|
||||
fun updateApplicationForm(
|
||||
id: UUID,
|
||||
applicationFormDto: ApplicationFormDto,
|
||||
|
||||
@@ -3,14 +3,25 @@ package com.betriebsratkanzlei.legalconsenthub.application_form
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.UUID
|
||||
|
||||
@Component
|
||||
class PagedApplicationFormMapper(
|
||||
private val applicationFormMapper: ApplicationFormMapper,
|
||||
) {
|
||||
fun toPagedApplicationFormDto(pagedApplicationForm: Page<ApplicationForm>): PagedApplicationFormDto =
|
||||
toPagedApplicationFormDto(pagedApplicationForm, emptyMap())
|
||||
|
||||
fun toPagedApplicationFormDto(
|
||||
pagedApplicationForm: Page<ApplicationForm>,
|
||||
commentCountByApplicationFormId: Map<UUID, Long>,
|
||||
): PagedApplicationFormDto =
|
||||
PagedApplicationFormDto(
|
||||
content = pagedApplicationForm.content.map { applicationFormMapper.toApplicationFormDto(it) },
|
||||
content =
|
||||
pagedApplicationForm.content.map { applicationForm ->
|
||||
val count = applicationForm.id?.let { commentCountByApplicationFormId[it] } ?: 0L
|
||||
applicationFormMapper.toApplicationFormDto(applicationForm, count)
|
||||
},
|
||||
number = pagedApplicationForm.number,
|
||||
propertySize = pagedApplicationForm.size,
|
||||
numberOfElements = pagedApplicationForm.numberOfElements,
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.hibernate.annotations.OnDelete
|
||||
import org.hibernate.annotations.OnDeleteAction
|
||||
import org.springframework.data.annotation.CreatedDate
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@@ -45,5 +45,5 @@ class ApplicationFormVersion(
|
||||
var createdBy: User,
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
var createdAt: LocalDateTime? = null,
|
||||
var createdAt: Instant? = null,
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ import jakarta.persistence.ManyToOne
|
||||
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.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@@ -22,17 +22,17 @@ class Comment(
|
||||
@Id
|
||||
@GeneratedValue
|
||||
var id: UUID? = null,
|
||||
@Column(nullable = false)
|
||||
@Column(nullable = false, columnDefinition = "TEXT")
|
||||
var message: String = "",
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "created_by_id", nullable = false)
|
||||
var createdBy: User,
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
var createdAt: LocalDateTime? = null,
|
||||
var createdAt: Instant? = null,
|
||||
@LastModifiedDate
|
||||
@Column(nullable = false)
|
||||
var modifiedAt: LocalDateTime? = null,
|
||||
var modifiedAt: Instant? = null,
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "application_form_id", nullable = false)
|
||||
var applicationForm: ApplicationForm? = null,
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.comment
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.api.CommentApi
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormCommentCountsDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CursorPagedCommentDto
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@RestController
|
||||
class CommentController(
|
||||
val commentService: CommentService,
|
||||
val commentMapper: CommentMapper,
|
||||
val pagedCommentMapper: PagedCommentMapper,
|
||||
) : CommentApi {
|
||||
@PreAuthorize(
|
||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
|
||||
@@ -32,12 +33,36 @@ class CommentController(
|
||||
@PreAuthorize(
|
||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
|
||||
)
|
||||
override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity<PagedCommentDto> =
|
||||
ResponseEntity.ok(
|
||||
pagedCommentMapper.toPagedCommentDto(
|
||||
commentService.getComments(applicationFormId),
|
||||
override fun getGroupedCommentCountByApplicationFromId(
|
||||
applicationFormId: UUID,
|
||||
): ResponseEntity<ApplicationFormCommentCountsDto> {
|
||||
val counts = commentService.getGroupedCommentCountByApplicationFromId(applicationFormId)
|
||||
return ResponseEntity.ok(
|
||||
ApplicationFormCommentCountsDto(
|
||||
counts = counts.mapKeys { it.key.toString() },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@PreAuthorize(
|
||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
|
||||
)
|
||||
override fun getCommentsByApplicationFormId(
|
||||
applicationFormId: UUID,
|
||||
formElementId: UUID?,
|
||||
cursorCreatedAt: Instant?,
|
||||
limit: Int,
|
||||
): ResponseEntity<CursorPagedCommentDto> {
|
||||
val page = commentService.getComments(applicationFormId, formElementId, cursorCreatedAt, limit)
|
||||
|
||||
return ResponseEntity.ok(
|
||||
CursorPagedCommentDto(
|
||||
content = page.comments.map { commentMapper.toCommentDto(it) },
|
||||
nextCursorCreatedAt = page.nextCursorCreatedAt,
|
||||
hasMore = page.hasMore,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@PreAuthorize(
|
||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
|
||||
@@ -48,7 +73,7 @@ class CommentController(
|
||||
): ResponseEntity<CommentDto> =
|
||||
ResponseEntity.ok(
|
||||
commentMapper.toCommentDto(
|
||||
commentService.updateComment(commentDto),
|
||||
commentService.updateComment(id, commentDto),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.betriebsratkanzlei.legalconsenthub.user.UserService
|
||||
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.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Component
|
||||
@@ -23,8 +23,8 @@ class CommentMapper(
|
||||
CommentDto(
|
||||
id = comment.id ?: throw IllegalStateException("Comment ID must not be null!"),
|
||||
message = comment.message,
|
||||
createdAt = comment.createdAt ?: LocalDateTime.now(),
|
||||
modifiedAt = comment.modifiedAt ?: LocalDateTime.now(),
|
||||
createdAt = comment.createdAt ?: Instant.now(),
|
||||
modifiedAt = comment.modifiedAt ?: Instant.now(),
|
||||
createdBy = userMapper.toUserDto(comment.createdBy),
|
||||
applicationFormId =
|
||||
comment.applicationForm?.id
|
||||
@@ -56,6 +56,14 @@ class CommentMapper(
|
||||
)
|
||||
}
|
||||
|
||||
fun applyUpdate(
|
||||
existing: Comment,
|
||||
commentDto: CommentDto,
|
||||
): Comment {
|
||||
existing.message = commentDto.message
|
||||
return existing
|
||||
}
|
||||
|
||||
fun toComment(
|
||||
applicationFormId: UUID,
|
||||
formElementId: UUID,
|
||||
|
||||
@@ -4,13 +4,68 @@ import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import org.springframework.data.repository.query.Param
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
interface ApplicationFormCommentCountProjection {
|
||||
val applicationFormId: UUID
|
||||
val commentCount: Long
|
||||
}
|
||||
|
||||
interface FormElementCommentCountProjection {
|
||||
val formElementId: UUID
|
||||
val commentCount: Long
|
||||
}
|
||||
|
||||
@Repository
|
||||
interface CommentRepository : JpaRepository<Comment, UUID> {
|
||||
fun findAllByApplicationForm(
|
||||
applicationForm: ApplicationForm,
|
||||
pageable: Pageable,
|
||||
): Page<Comment>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
select c.applicationForm.id as applicationFormId, count(c.id) as commentCount
|
||||
from Comment c
|
||||
where c.applicationForm.id in :applicationFormIds
|
||||
group by c.applicationForm.id
|
||||
""",
|
||||
)
|
||||
fun countByApplicationFormIds(
|
||||
@Param("applicationFormIds") applicationFormIds: Collection<UUID>,
|
||||
): List<ApplicationFormCommentCountProjection>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
select c.*
|
||||
from comment c
|
||||
where c.application_form_id = :applicationFormId
|
||||
and (cast(:formElementId as uuid) is null or c.form_element_id = :formElementId)
|
||||
and (cast(:cursorCreatedAt as timestamp) is null or c.created_at < :cursorCreatedAt)
|
||||
order by c.created_at desc, c.id desc
|
||||
""",
|
||||
nativeQuery = true,
|
||||
)
|
||||
fun findNextByApplicationFormId(
|
||||
@Param("applicationFormId") applicationFormId: UUID,
|
||||
@Param("formElementId") formElementId: UUID?,
|
||||
@Param("cursorCreatedAt") cursorCreatedAt: Instant?,
|
||||
pageable: Pageable,
|
||||
): List<Comment>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
select c.formElement.id as formElementId, count(c.id) as commentCount
|
||||
from Comment c
|
||||
where c.applicationForm.id = :applicationFormId
|
||||
group by c.formElement.id
|
||||
""",
|
||||
)
|
||||
fun countByApplicationFormIdGroupByFormElementId(
|
||||
@Param("applicationFormId") applicationFormId: UUID,
|
||||
): List<FormElementCommentCountProjection>
|
||||
}
|
||||
|
||||
@@ -7,11 +7,17 @@ import com.betriebsratkanzlei.legalconsenthub.error.CommentNotFoundException
|
||||
import com.betriebsratkanzlei.legalconsenthub.error.CommentNotUpdatedException
|
||||
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.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
data class CursorCommentPage(
|
||||
val comments: List<Comment>,
|
||||
val nextCursorCreatedAt: Instant?,
|
||||
val hasMore: Boolean,
|
||||
)
|
||||
|
||||
@Service
|
||||
class CommentService(
|
||||
private val commentRepository: CommentRepository,
|
||||
@@ -36,25 +42,55 @@ class CommentService(
|
||||
|
||||
fun getCommentById(id: UUID): Comment = commentRepository.findById(id).orElseThrow { CommentNotFoundException(id) }
|
||||
|
||||
fun getComments(applicationFormId: UUID): Page<Comment> {
|
||||
val applicationForm =
|
||||
applicationFormRepository.findById(applicationFormId).orElse(null)
|
||||
val pageable = PageRequest.of(0, 10)
|
||||
return commentRepository.findAllByApplicationForm(applicationForm, pageable)
|
||||
fun getComments(
|
||||
applicationFormId: UUID,
|
||||
formElementId: UUID?,
|
||||
cursorCreatedAt: Instant?,
|
||||
limit: Int,
|
||||
): CursorCommentPage {
|
||||
applicationFormRepository.findById(applicationFormId).orElse(null)
|
||||
|
||||
val pageSize = limit.coerceIn(1, 50)
|
||||
val fetchSize = pageSize + 1
|
||||
|
||||
val comments =
|
||||
commentRepository.findNextByApplicationFormId(
|
||||
applicationFormId = applicationFormId,
|
||||
formElementId = formElementId,
|
||||
cursorCreatedAt = cursorCreatedAt,
|
||||
pageable = PageRequest.of(0, fetchSize),
|
||||
)
|
||||
val hasMore = comments.size > pageSize
|
||||
val pageItems = if (hasMore) comments.take(pageSize) else comments
|
||||
val nextCursor = if (hasMore) pageItems.lastOrNull()?.createdAt else null
|
||||
|
||||
return CursorCommentPage(
|
||||
comments = pageItems,
|
||||
nextCursorCreatedAt = nextCursor,
|
||||
hasMore = hasMore,
|
||||
)
|
||||
}
|
||||
|
||||
fun updateComment(commentDto: CommentDto): Comment {
|
||||
// TODO find statt mappen?
|
||||
val comment = commentMapper.toComment(commentDto)
|
||||
val updatedComment: Comment
|
||||
fun getGroupedCommentCountByApplicationFromId(applicationFormId: UUID): Map<UUID, Long> {
|
||||
applicationFormRepository.findById(applicationFormId).orElse(null)
|
||||
|
||||
try {
|
||||
updatedComment = commentRepository.save(comment)
|
||||
return commentRepository
|
||||
.countByApplicationFormIdGroupByFormElementId(applicationFormId)
|
||||
.associate { it.formElementId to it.commentCount }
|
||||
}
|
||||
|
||||
fun updateComment(
|
||||
id: UUID,
|
||||
commentDto: CommentDto,
|
||||
): Comment {
|
||||
val existing = getCommentById(id)
|
||||
val updated = commentMapper.applyUpdate(existing, commentDto)
|
||||
|
||||
return try {
|
||||
commentRepository.save(updated)
|
||||
} catch (e: Exception) {
|
||||
throw CommentNotUpdatedException(e, commentDto.id)
|
||||
throw CommentNotUpdatedException(e, id)
|
||||
}
|
||||
|
||||
return updatedComment
|
||||
}
|
||||
|
||||
fun deleteCommentByID(id: UUID) {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.comment
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PagedCommentMapper(
|
||||
private val commentMapper: CommentMapper,
|
||||
) {
|
||||
fun toPagedCommentDto(pagedComment: Page<Comment>): PagedCommentDto =
|
||||
PagedCommentDto(
|
||||
content = pagedComment.content.map { commentMapper.toCommentDto(it) },
|
||||
number = pagedComment.number,
|
||||
propertySize = pagedComment.size,
|
||||
numberOfElements = pagedComment.numberOfElements,
|
||||
last = pagedComment.isLast,
|
||||
totalPages = pagedComment.totalPages,
|
||||
totalElements = pagedComment.totalElements,
|
||||
empty = pagedComment.isEmpty,
|
||||
first = pagedComment.isFirst,
|
||||
)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import jakarta.persistence.JoinColumn
|
||||
import jakarta.persistence.ManyToOne
|
||||
import org.springframework.data.annotation.CreatedDate
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@@ -42,5 +42,5 @@ class Notification(
|
||||
var organizationId: String = "",
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
var createdAt: LocalDateTime? = null,
|
||||
var createdAt: Instant? = null,
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import jakarta.persistence.Table
|
||||
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.Instant
|
||||
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener::class)
|
||||
@@ -29,8 +29,8 @@ class User(
|
||||
var emailOnFormSubmitted: Boolean = true,
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
var createdAt: LocalDateTime? = null,
|
||||
var createdAt: Instant? = null,
|
||||
@LastModifiedDate
|
||||
@Column(nullable = false)
|
||||
var modifiedAt: LocalDateTime? = null,
|
||||
var modifiedAt: Instant? = null,
|
||||
)
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
create table app_user
|
||||
(
|
||||
email_on_form_created boolean not null,
|
||||
email_on_form_submitted boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
modified_at timestamp(6) not null,
|
||||
email_on_form_created boolean not null,
|
||||
email_on_form_submitted boolean not null,
|
||||
created_at timestamp(6) with time zone not null,
|
||||
modified_at timestamp(6) with time zone not null,
|
||||
email varchar(255),
|
||||
keycloak_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
keycloak_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
organization_id varchar(255),
|
||||
primary key (keycloak_id)
|
||||
);
|
||||
|
||||
create table application_form
|
||||
(
|
||||
is_template boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
modified_at timestamp(6) not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
last_modified_by_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
is_template boolean not null,
|
||||
created_at timestamp(6) with time zone not null,
|
||||
modified_at timestamp(6) with time zone not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
last_modified_by_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
organization_id varchar(255),
|
||||
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
|
||||
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table application_form_version
|
||||
(
|
||||
version_number integer not null,
|
||||
created_at timestamp(6) not null,
|
||||
application_form_id uuid not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
organization_id varchar(255) not null,
|
||||
snapshot_data TEXT not null,
|
||||
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
|
||||
version_number integer not null,
|
||||
created_at timestamp(6) with time zone not null,
|
||||
application_form_id uuid not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
organization_id varchar(255) not null,
|
||||
snapshot_data TEXT not null,
|
||||
status varchar(255) not null check (status in ('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED', 'SIGNED')),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table comment
|
||||
(
|
||||
created_at timestamp(6) not null,
|
||||
modified_at timestamp(6) not null,
|
||||
application_form_id uuid not null,
|
||||
form_element_id uuid not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
message varchar(255) not null,
|
||||
created_at timestamp(6) with time zone not null,
|
||||
modified_at timestamp(6) with time zone not null,
|
||||
application_form_id uuid not null,
|
||||
form_element_id uuid not null,
|
||||
id uuid not null,
|
||||
created_by_id varchar(255) not null,
|
||||
message TEXT not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
@@ -109,16 +109,16 @@ create table form_element_sub_section
|
||||
|
||||
create table notification
|
||||
(
|
||||
is_read boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
id uuid not null,
|
||||
click_target varchar(255) not null,
|
||||
message TEXT not null,
|
||||
organization_id varchar(255) not null,
|
||||
is_read boolean not null,
|
||||
created_at timestamp(6) with time zone not null,
|
||||
id uuid not null,
|
||||
click_target varchar(255) not null,
|
||||
message TEXT not null,
|
||||
organization_id varchar(255) not null,
|
||||
recipient_id varchar(255),
|
||||
target_roles TEXT,
|
||||
title varchar(255) not null,
|
||||
type varchar(255) not null check (type in ('INFO', 'WARNING', 'ERROR')),
|
||||
title varchar(255) not null,
|
||||
type varchar(255) not null check (type in ('INFO', 'WARNING', 'ERROR')),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
@@ -136,9 +136,7 @@ alter table if exists application_form_version
|
||||
add constraint FKpfri4lhy9wqfsp8esabedkq6c
|
||||
foreign key (application_form_id)
|
||||
references application_form
|
||||
on
|
||||
delete
|
||||
cascade;
|
||||
on delete cascade;
|
||||
|
||||
alter table if exists application_form_version
|
||||
add constraint FKl6fbcrvh439gbwgcvvfyxaggi
|
||||
|
||||
Reference in New Issue
Block a user