Grade comments: show live usage count and allow deleting unused templates
This commit is contained in:
@@ -146,6 +146,13 @@ data class CommentOut(
|
||||
val tone: String,
|
||||
)
|
||||
|
||||
/** Подсказка комментария: текст, тон и текущее число использований. */
|
||||
data class CommentSuggestion(
|
||||
val text: String,
|
||||
val tone: String,
|
||||
val count: Long,
|
||||
)
|
||||
|
||||
data class GradeResponse(
|
||||
val studentId: String,
|
||||
val labId: String,
|
||||
|
||||
@@ -74,11 +74,38 @@ class GradeService(
|
||||
lid: UUID,
|
||||
): List<GradeComment> = gradeComments.findByStudentIdAndLabId(sid, lid)
|
||||
|
||||
/**
|
||||
* Подсказки комментариев: поиск по подстроке, выше — чаще используемые сейчас.
|
||||
* Число использований считается по актуальным оценкам, а не по накопительному [CommentTemplate.useCount].
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
fun suggestComments(query: String): List<CommentOut> =
|
||||
templates
|
||||
.findTop30ByTextContainingIgnoreCaseOrderByUseCountDesc(query.trim())
|
||||
.map { CommentOut(it.text, it.tone) }
|
||||
fun suggestComments(query: String): List<CommentSuggestion> {
|
||||
val found = templates.findByTextContainingIgnoreCase(query.trim())
|
||||
val counts = liveCounts(found.map { it.text })
|
||||
return found
|
||||
.map { it to (counts[it.text] ?: 0L) }
|
||||
.sortedWith(compareByDescending<Pair<CommentTemplate, Long>> { it.second }.thenByDescending { it.first.useCount })
|
||||
.take(SUGGEST_LIMIT)
|
||||
.map { CommentSuggestion(it.first.text, it.first.tone, it.second) }
|
||||
}
|
||||
|
||||
/** Удаляет шаблон комментария, только если он нигде не проставлен. */
|
||||
@Transactional
|
||||
fun deleteCommentTemplate(text: String) {
|
||||
val trimmed = text.trim()
|
||||
val inUse = gradeComments.countByText(trimmed)
|
||||
if (inUse > 0) throw BadRequestException("Комментарий используется $inUse раз(а) — удалить нельзя")
|
||||
templates.deleteByText(trimmed)
|
||||
}
|
||||
|
||||
private fun liveCounts(texts: List<String>): Map<String, Long> {
|
||||
if (texts.isEmpty()) return emptyMap()
|
||||
return gradeComments
|
||||
.findByTextIn(texts)
|
||||
.groupingBy { it.text }
|
||||
.eachCount()
|
||||
.mapValues { it.value.toLong() }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun myComments(studentId: UUID): List<GradeComment> = gradeComments.findByStudentId(studentId)
|
||||
@@ -98,4 +125,8 @@ class GradeService(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SUGGEST_LIMIT = 30
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import jakarta.validation.Valid
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
@@ -121,5 +122,13 @@ class ProgressController(
|
||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
||||
fun suggestComments(
|
||||
@RequestParam q: String,
|
||||
): List<CommentOut> = grades.suggestComments(q)
|
||||
): List<CommentSuggestion> = grades.suggestComments(q)
|
||||
|
||||
@DeleteMapping("/comment-templates")
|
||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
||||
fun deleteCommentTemplate(
|
||||
@RequestParam text: String,
|
||||
) {
|
||||
grades.deleteCommentTemplate(text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import java.util.UUID
|
||||
interface CommentTemplateRepository : JpaRepository<CommentTemplate, UUID> {
|
||||
fun findByText(text: String): CommentTemplate?
|
||||
|
||||
fun findTop30ByTextContainingIgnoreCaseOrderByUseCountDesc(text: String): List<CommentTemplate>
|
||||
fun findByTextContainingIgnoreCase(text: String): List<CommentTemplate>
|
||||
|
||||
fun deleteByText(text: String)
|
||||
}
|
||||
|
||||
interface GradeCommentRepository : JpaRepository<GradeComment, UUID> {
|
||||
@@ -23,4 +25,8 @@ interface GradeCommentRepository : JpaRepository<GradeComment, UUID> {
|
||||
)
|
||||
|
||||
fun findByStudentId(studentId: UUID): List<GradeComment>
|
||||
|
||||
fun findByTextIn(texts: Collection<String>): List<GradeComment>
|
||||
|
||||
fun countByText(text: String): Long
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user