From 9a2a4023b52c9050df033c340ba2ca6abe9ca836 Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Sun, 27 Sep 2026 22:02:56 +0300 Subject: [PATCH] Refactor: split loop/throws helpers; drop deprecated JSON accessors --- .../ru/ysu/lms/progress/DefenseService.kt | 20 ++++-- .../ru/ysu/lms/web/admin/AdminController.kt | 66 ++++++++++++------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/DefenseService.kt b/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/DefenseService.kt index 02890a3..8e76868 100644 --- a/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/DefenseService.kt +++ b/services/progress-service/src/main/kotlin/ru/ysu/lms/progress/DefenseService.kt @@ -124,10 +124,22 @@ class DefenseService( studentId: UUID, code: String, ): DefenseSession { - val s = sessions.findByCode(code.trim()) ?: throw BadRequestException("Код не найден") - if (s.studentId != studentId) throw ForbiddenException("Этот код выдан другому студенту") - if (s.status != DefenseStatus.waiting.name) throw BadRequestException("Защита по этому коду уже начата") - return s + val session = findSessionByCode(code) + requireOwnerAndWaiting(session, studentId) + return session + } + + private fun findSessionByCode(code: String): DefenseSession = + sessions.findByCode(code.trim()) ?: throw BadRequestException("Код не найден") + + private fun requireOwnerAndWaiting( + session: DefenseSession, + studentId: UUID, + ) { + if (session.studentId != studentId) throw ForbiddenException("Этот код выдан другому студенту") + if (session.status != DefenseStatus.waiting.name) { + throw BadRequestException("Защита по этому коду уже начата") + } } @Transactional diff --git a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminController.kt b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminController.kt index c1b6b53..cf2903e 100644 --- a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminController.kt +++ b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminController.kt @@ -20,6 +20,7 @@ import ru.ysu.lms.web.api.CreateStudentRequestDto import ru.ysu.lms.web.api.DistributeRequestPayload import ru.ysu.lms.web.api.GradeSetPayload import ru.ysu.lms.web.api.LabCreatePayload +import ru.ysu.lms.web.api.LabSummaryDto import ru.ysu.lms.web.api.LabUpdatePayload import ru.ysu.lms.web.api.LevelAssignPayload import ru.ysu.lms.web.api.LevelPayload @@ -479,29 +480,13 @@ class AdminController( var count = 0 var skipped = 0 for ((idx, rawCols) in rows.withIndex()) { - val cells = rawCols.map { it.trim() } - if (cells.all { it.isBlank() }) continue - if (idx == 0 && looksLikeHeader(cells)) continue - var sid: String? = null - var lid: String? = labId?.takeIf { it.isNotBlank() } - var md: String? = null - when { - cells.size >= 3 -> { - sid = studentByNo[cells[0]] - lid = labByNumber[cells[1]]?.id ?: lid - md = cells.drop(2).joinToString("; ") - } - cells.size == 2 -> { - sid = studentByNo[cells[0]] - md = cells[1] - } - } - if (sid == null || lid.isNullOrBlank() || md.isNullOrBlank()) { + val row = resolveDefenseRow(rawCols, idx, labId, studentByNo, labByNumber) + if (row == null) { skipped++ - continue + } else { + api.assignDefense(t, row.studentId, row.labId, row.assignmentMd.replace("\\n", "\n")) + count++ } - api.assignDefense(t, sid, lid, md.replace("\\n", "\n")) - count++ } val tail = if (skipped > 0) ", пропущено: $skipped" else "" redirect.addFlashAttribute("notice", "Импортировано заданий: $count$tail") @@ -511,6 +496,41 @@ class AdminController( redirectToGroup(groupId, labId) } + private data class DefenseRow( + val studentId: String, + val labId: String, + val assignmentMd: String, + ) + + /** Разбирает строку CSV с заданием на защиту; null — строку нужно пропустить. */ + private fun resolveDefenseRow( + rawCols: List, + index: Int, + defaultLabId: String?, + studentByNo: Map, + labByNumber: Map, + ): DefenseRow? { + val cells = rawCols.map { it.trim() } + if (cells.all { it.isBlank() }) return null + if (index == 0 && looksLikeHeader(cells)) return null + var sid: String? = null + var lid: String? = defaultLabId?.takeIf { it.isNotBlank() } + var md: String? = null + when { + cells.size >= 3 -> { + sid = studentByNo[cells[0]] + lid = labByNumber[cells[1]]?.id ?: lid + md = cells.drop(2).joinToString("; ") + } + cells.size == 2 -> { + sid = studentByNo[cells[0]] + md = cells[1] + } + } + if (sid == null || lid.isNullOrBlank() || md.isNullOrBlank()) return null + return DefenseRow(sid, lid, md) + } + private fun looksLikeHeader(cells: List): Boolean { val joined = cells.joinToString(" ").lowercase() return joined.contains("студент") || @@ -1250,11 +1270,11 @@ class AdminController( val node = mapper.readTree(json) buildList { node.forEach { el -> - val text = el.path("text").asText("").trim() + val text = el.path("text").asString("").trim() if (text.isNotEmpty()) { add( ru.ysu.lms.web.api - .CommentPayload(text, el.path("tone").asText("neutral")), + .CommentPayload(text, el.path("tone").asString("neutral")), ) } }