UI rework: modal dialogs, inline lab editing, manual creation, content management
- Dashboard: real stats (groups, students, labs, average grade), labs/groups summary lists, no placeholder tile - Lab page: view + edit combined — metadata form in modal, condition rendered as markdown, per-level variant tables with add/edit/delete dialogs, level rename/delete, student level/variant selectors with group filter - Labs list: create-lab dialog with manual level entry (code; title lines) - Groups: create-group dialog, add-student dialog (auto password, toast card) - Content: public /learn reader is the single place; admin buttons (new article with chapter/section create-or-select, rename/delete chapters and sections, move articles between sections, import zip) appear for admins; removed separate 'Контент' admin section - Buttons use btn classes instead of nav-link - Favicon: generated SVG book icon - Security: CSRF synchronizer token interceptor (replaced spring-security in web which broke logback under nested jars), session regenerated on login, hardened session cookie, gateway actuator limited to health,info - Jackson 3: nullable-safe request DTOs for labs (FAIL_ON_NULL_FOR_PRIMITIVES) - academic: POST /labs (manual create with levels), level add/rename/delete, content chapters/sections CRUD, article create/move/delete endpoints
This commit is contained in:
@@ -29,6 +29,12 @@ class GroupController(private val groupService: GroupService) {
|
||||
@PostMapping
|
||||
fun create(@Valid @RequestBody body: CreateGroupRequest): GroupSummary = groupService.create(body)
|
||||
|
||||
@PostMapping("/{id}/students")
|
||||
fun createStudent(
|
||||
@PathVariable id: UUID,
|
||||
@Valid @RequestBody body: CreateStudentRequest,
|
||||
): Credential = groupService.createStudent(id, body)
|
||||
|
||||
@PostMapping("/import")
|
||||
fun import(
|
||||
@RequestParam("file") file: MultipartFile,
|
||||
|
||||
@@ -31,6 +31,44 @@ class GroupService(
|
||||
@Transactional(readOnly = true)
|
||||
fun list(): List<GroupSummary> = groups.findAllByOrderByNameAsc().map { summary(it) }
|
||||
|
||||
@Transactional
|
||||
fun createStudent(groupId: UUID, request: CreateStudentRequest): Credential {
|
||||
val group = groups.findById(groupId).orElseThrow { NotFoundException("Группа не найдена") }
|
||||
val studentNo = request.studentNo.trim()
|
||||
if (studentNo.isBlank()) throw BadRequestException("Студенческий номер не может быть пустым")
|
||||
if (students.existsByStudentNo(studentNo)) {
|
||||
throw ConflictException("Студент с номером $studentNo уже существует")
|
||||
}
|
||||
val password = Passwords.generate()
|
||||
val account = accounts.save(
|
||||
Account(
|
||||
login = studentNo,
|
||||
passwordHash = passwordEncoder.encode(password) ?: "",
|
||||
role = LmsRole.STUDENT,
|
||||
mustChangePassword = true,
|
||||
tempPassword = password,
|
||||
),
|
||||
)
|
||||
val student = students.save(
|
||||
Student(
|
||||
studentNo = studentNo,
|
||||
lastName = request.lastName.trim(),
|
||||
firstName = request.firstName.trim(),
|
||||
middleName = request.middleName.trim(),
|
||||
basis = request.basis.trim(),
|
||||
note = request.note.trim(),
|
||||
),
|
||||
)
|
||||
student.account = account
|
||||
enrollments.save(Enrollment(group = group, student = student))
|
||||
return Credential(
|
||||
id = account.id.toString(),
|
||||
studentNo = studentNo,
|
||||
fullName = student.fullName,
|
||||
password = password,
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun create(request: CreateGroupRequest): GroupSummary {
|
||||
val name = request.name.trim()
|
||||
|
||||
@@ -14,6 +14,17 @@ data class CreateGroupRequest(
|
||||
val name: String,
|
||||
)
|
||||
|
||||
data class CreateStudentRequest(
|
||||
@field:NotBlank(message = "Укажите студенческий номер")
|
||||
val studentNo: String,
|
||||
@field:NotBlank(message = "Укажите фамилию")
|
||||
val lastName: String,
|
||||
val firstName: String = "",
|
||||
val middleName: String = "",
|
||||
val basis: String = "",
|
||||
val note: String = "",
|
||||
)
|
||||
|
||||
data class StudentRow(
|
||||
val id: String,
|
||||
val studentNo: String,
|
||||
|
||||
Reference in New Issue
Block a user