Admin group: fix script loading (extra div), total submissions counter, label cleanup
This commit is contained in:
@@ -56,6 +56,13 @@ class SubmissionController(
|
|||||||
@RequestParam labId: UUID,
|
@RequestParam labId: UUID,
|
||||||
): List<SubmissionDto> = submissions.latestPerStudent(labId)
|
): List<SubmissionDto> = submissions.latestPerStudent(labId)
|
||||||
|
|
||||||
|
/** Общее число решений (всех попыток) по лабораторной. */
|
||||||
|
@GetMapping("/submissions/count")
|
||||||
|
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
||||||
|
fun submissionCount(
|
||||||
|
@RequestParam labId: UUID,
|
||||||
|
): Map<String, Long> = mapOf("count" to submissions.countForLab(labId))
|
||||||
|
|
||||||
@GetMapping("/submissions/{id}/download")
|
@GetMapping("/submissions/{id}/download")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
||||||
fun downloadForAdmin(
|
fun downloadForAdmin(
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ class SubmissionService(
|
|||||||
return zip to name
|
return zip to name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Общее число решений (всех попыток) по лабораторной. */
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun countForLab(labId: UUID): Long = submissions.countByLabId(labId)
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun latestPerStudent(labId: UUID): List<SubmissionDto> {
|
fun latestPerStudent(labId: UUID): List<SubmissionDto> {
|
||||||
val perStudent = mutableMapOf<UUID, Submission>()
|
val perStudent = mutableMapOf<UUID, Submission>()
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ interface SubmissionRepository : JpaRepository<Submission, UUID> {
|
|||||||
|
|
||||||
fun findByLabIdOrderByCreatedAtDesc(labId: UUID): List<Submission>
|
fun findByLabIdOrderByCreatedAtDesc(labId: UUID): List<Submission>
|
||||||
|
|
||||||
|
fun countByLabId(labId: UUID): Long
|
||||||
|
|
||||||
fun findFirstByStudentIdAndLabIdOrderBySeqDesc(
|
fun findFirstByStudentIdAndLabIdOrderBySeqDesc(
|
||||||
studentId: UUID,
|
studentId: UUID,
|
||||||
labId: UUID,
|
labId: UUID,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import ru.ysu.lms.web.api.GradeSetPayload
|
|||||||
import ru.ysu.lms.web.api.GroupDetailDto
|
import ru.ysu.lms.web.api.GroupDetailDto
|
||||||
import ru.ysu.lms.web.api.LabSummaryDto
|
import ru.ysu.lms.web.api.LabSummaryDto
|
||||||
import ru.ysu.lms.web.api.StudentCandidateDto
|
import ru.ysu.lms.web.api.StudentCandidateDto
|
||||||
import ru.ysu.lms.web.api.SubmissionDto
|
|
||||||
import ru.ysu.lms.web.api.createGroup
|
import ru.ysu.lms.web.api.createGroup
|
||||||
import ru.ysu.lms.web.api.downloadSubmissionAsAdmin
|
import ru.ysu.lms.web.api.downloadSubmissionAsAdmin
|
||||||
import ru.ysu.lms.web.api.getLabAssignments
|
import ru.ysu.lms.web.api.getLabAssignments
|
||||||
@@ -38,6 +37,7 @@ import ru.ysu.lms.web.api.listGroups
|
|||||||
import ru.ysu.lms.web.api.listLabs
|
import ru.ysu.lms.web.api.listLabs
|
||||||
import ru.ysu.lms.web.api.publishGrades
|
import ru.ysu.lms.web.api.publishGrades
|
||||||
import ru.ysu.lms.web.api.setGrade
|
import ru.ysu.lms.web.api.setGrade
|
||||||
|
import ru.ysu.lms.web.api.submissionCount
|
||||||
import ru.ysu.lms.web.api.suggestComments
|
import ru.ysu.lms.web.api.suggestComments
|
||||||
import tools.jackson.databind.ObjectMapper
|
import tools.jackson.databind.ObjectMapper
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
@@ -192,7 +192,7 @@ class AdminGroupController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fillGroupModel(model, groupViewModel(t, id, GroupRenderData(group, labs, rows, publishedLabs, submissionsBy)))
|
fillGroupModel(model, groupViewModel(t, id, GroupRenderData(group, labs, rows, publishedLabs)))
|
||||||
return "admin/group"
|
return "admin/group"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +206,6 @@ class AdminGroupController(
|
|||||||
val labs: List<LabSummaryDto>,
|
val labs: List<LabSummaryDto>,
|
||||||
val rows: List<GroupStudentRow>,
|
val rows: List<GroupStudentRow>,
|
||||||
val publishedLabs: Set<String>,
|
val publishedLabs: Set<String>,
|
||||||
val submissionsBy: Map<LabSummaryDto, Map<String, SubmissionDto>>,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun groupViewModel(
|
private fun groupViewModel(
|
||||||
@@ -214,7 +213,7 @@ class AdminGroupController(
|
|||||||
id: String,
|
id: String,
|
||||||
data: GroupRenderData,
|
data: GroupRenderData,
|
||||||
): GroupViewModel {
|
): GroupViewModel {
|
||||||
val submissionCounts = data.labs.associate { it.id to (data.submissionsBy[it]?.size ?: 0) }
|
val submissionCounts = data.labs.associate { it.id to api.submissionCount(token, it.id) }
|
||||||
val candidates = runCatching { api.groupCandidates(token, id) }.getOrDefault(emptyList())
|
val candidates = runCatching { api.groupCandidates(token, id) }.getOrDefault(emptyList())
|
||||||
return GroupViewModel(data.group, data.labs, candidates, data.rows, data.publishedLabs, submissionCounts)
|
return GroupViewModel(data.group, data.labs, candidates, data.rows, data.publishedLabs, submissionCounts)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,23 @@ import org.springframework.http.HttpHeaders
|
|||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.util.LinkedMultiValueMap
|
import org.springframework.util.LinkedMultiValueMap
|
||||||
|
|
||||||
|
fun ApiClient.submissionCount(
|
||||||
|
token: String,
|
||||||
|
labId: String,
|
||||||
|
): Int {
|
||||||
|
val type = object : ParameterizedTypeReference<Map<String, Long>>() {}
|
||||||
|
val result =
|
||||||
|
call {
|
||||||
|
client
|
||||||
|
.get()
|
||||||
|
.uri("/api/v1/submissions/count?labId={id}", labId)
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, bearer(token))
|
||||||
|
.retrieve()
|
||||||
|
.body(type)
|
||||||
|
}
|
||||||
|
return (result["count"] ?: 0L).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
fun ApiClient.distribute(
|
fun ApiClient.distribute(
|
||||||
token: String,
|
token: String,
|
||||||
payload: DistributeRequestPayload,
|
payload: DistributeRequestPayload,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<button class="btn btn-primary" type="button" onclick="openModal('modal-add-student')">+ Студент</button>
|
<button class="btn btn-primary" type="button" onclick="openModal('modal-add-student')">+ Студент</button>
|
||||||
<a class="btn btn-secondary" th:href="@{/admin/groups/{id}/credentials(id=${group.id}, format='xlsx')}">Скачать пароли</a>
|
<a class="btn btn-secondary" th:href="@{/admin/groups/{id}/credentials(id=${group.id}, format='xlsx')}">Скачать пароли</a>
|
||||||
<button class="btn btn-secondary" type="button" onclick="openModal('modal-defense-import')">Импорт заданий (CSV)</button>
|
<button class="btn btn-secondary" type="button" onclick="openModal('modal-defense-import')">Импорт заданий</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -225,7 +225,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
@@ -234,7 +233,7 @@
|
|||||||
<!-- Диалог импорта CSV -->
|
<!-- Диалог импорта CSV -->
|
||||||
<dialog id="modal-defense-import" class="modal">
|
<dialog id="modal-defense-import" class="modal">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h2 class="modal-title">Импорт заданий (CSV)</h2>
|
<h2 class="modal-title">Импорт заданий</h2>
|
||||||
<button class="modal-close" type="button" onclick="closeModal('modal-defense-import')">✕</button>
|
<button class="modal-close" type="button" onclick="closeModal('modal-defense-import')">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|||||||
Reference in New Issue
Block a user