feat(academic): преподаватель может вести лабораторные
This commit is contained in:
@@ -61,96 +61,154 @@ class LabController(
|
|||||||
return labService.detail(id)
|
return labService.detail(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Копирование: нужен доступ и к исходной лабораторной, и к целевому курсу. */
|
||||||
@PostMapping("/{id}/copy")
|
@PostMapping("/{id}/copy")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun copy(
|
fun copy(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@Valid @RequestBody body: LabCopyRequest,
|
@Valid @RequestBody body: LabCopyRequest,
|
||||||
): LabDetail = labService.copy(id, body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
accessService.requireCourseAccess(body.courseId, jwt)
|
||||||
|
return labService.copy(id, body)
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/import")
|
@PostMapping("/import")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun importLab(
|
fun importLab(
|
||||||
@RequestParam("file") file: MultipartFile,
|
@RequestParam("file") file: MultipartFile,
|
||||||
@RequestParam(required = false) courseId: UUID?,
|
@RequestParam(required = false) courseId: UUID?,
|
||||||
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
): LabImportResult {
|
): LabImportResult {
|
||||||
if (file.isEmpty) throw BadRequestException("Выберите файл")
|
if (file.isEmpty) throw BadRequestException("Выберите файл")
|
||||||
return labService.importFromFile(file.originalFilename ?: "lab.zip", file.bytes, courseId)
|
val targetCourseId = requireWritableCourse(courseId, jwt)
|
||||||
|
return labService.importFromFile(file.originalFilename ?: "lab.zip", file.bytes, targetCourseId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun delete(
|
fun delete(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
) {
|
) {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
labService.delete(id)
|
labService.delete(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun update(
|
fun update(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@Valid @RequestBody body: LabUpdateRequest,
|
@Valid @RequestBody body: LabUpdateRequest,
|
||||||
): LabDetail = labService.update(id, body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.update(id, body)
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/variants")
|
@PostMapping("/{id}/variants")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun addVariant(
|
fun addVariant(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@Valid @RequestBody body: VariantSaveRequest,
|
@Valid @RequestBody body: VariantSaveRequest,
|
||||||
): LabDetail = labService.addVariant(id, body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.addVariant(id, body)
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}/variants/{variantId}")
|
@PutMapping("/{id}/variants/{variantId}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun updateVariant(
|
fun updateVariant(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@PathVariable variantId: UUID,
|
@PathVariable variantId: UUID,
|
||||||
@Valid @RequestBody body: VariantSaveRequest,
|
@Valid @RequestBody body: VariantSaveRequest,
|
||||||
): LabDetail = labService.updateVariant(id, variantId, body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.updateVariant(id, variantId, body)
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}/variants/{variantId}")
|
@DeleteMapping("/{id}/variants/{variantId}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun deleteVariant(
|
fun deleteVariant(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@PathVariable variantId: UUID,
|
@PathVariable variantId: UUID,
|
||||||
): LabDetail = labService.deleteVariant(id, variantId)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.deleteVariant(id, variantId)
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/toggle-status")
|
@PostMapping("/{id}/toggle-status")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun toggleStatus(
|
fun toggleStatus(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
) {
|
) {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
labService.toggleStatus(id)
|
labService.toggleStatus(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun create(
|
fun create(
|
||||||
@Valid @RequestBody body: LabCreateRequest,
|
@Valid @RequestBody body: LabCreateRequest,
|
||||||
): LabDetail = labService.create(body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
requireWritableCourse(body.courseId, jwt)
|
||||||
|
return labService.create(body)
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/levels")
|
@PostMapping("/{id}/levels")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun addLevel(
|
fun addLevel(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@Valid @RequestBody body: LevelSaveRequest,
|
@Valid @RequestBody body: LevelSaveRequest,
|
||||||
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
): LabDetail {
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
labService.addLevel(id, body)
|
labService.addLevel(id, body)
|
||||||
return labService.detail(id)
|
return labService.detail(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}/levels/{levelId}")
|
@PutMapping("/{id}/levels/{levelId}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun renameLevel(
|
fun renameLevel(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@PathVariable levelId: UUID,
|
@PathVariable levelId: UUID,
|
||||||
@Valid @RequestBody body: LevelRenameRequest,
|
@Valid @RequestBody body: LevelRenameRequest,
|
||||||
): LabDetail = labService.renameLevel(id, levelId, body)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.renameLevel(id, levelId, body)
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}/levels/{levelId}")
|
@DeleteMapping("/{id}/levels/{levelId}")
|
||||||
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
|
@PreAuthorize("hasAnyRole('ADMIN','TEACHER')")
|
||||||
fun deleteLevel(
|
fun deleteLevel(
|
||||||
@PathVariable id: UUID,
|
@PathVariable id: UUID,
|
||||||
@PathVariable levelId: UUID,
|
@PathVariable levelId: UUID,
|
||||||
): LabDetail = labService.deleteLevel(id, levelId)
|
@AuthenticationPrincipal jwt: Jwt,
|
||||||
|
): LabDetail {
|
||||||
|
accessService.requireLabAccess(id, jwt)
|
||||||
|
return labService.deleteLevel(id, levelId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Для записи не-администратор обязан явно указать курс: legacy-выбор единственного курса
|
||||||
|
* остаётся только для администратора. Возвращает проверенный курс (или null для admin).
|
||||||
|
*/
|
||||||
|
private fun requireWritableCourse(
|
||||||
|
courseId: UUID?,
|
||||||
|
jwt: Jwt,
|
||||||
|
): UUID? {
|
||||||
|
if (courseId != null) {
|
||||||
|
accessService.requireCourseAccess(courseId, jwt)
|
||||||
|
return courseId
|
||||||
|
}
|
||||||
|
if (!accessService.isAdmin(jwt)) throw BadRequestException("Укажите курс")
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ class CourseAccessService(
|
|||||||
return courseService.list().filter { it.id in allowedIds }
|
return courseService.list().filter { it.id in allowedIds }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isAdmin(jwt: Jwt): Boolean = role(jwt) == ROLE_ADMIN
|
||||||
|
|
||||||
private fun activeCourseIds(courseIds: Collection<UUID>): Set<UUID> {
|
private fun activeCourseIds(courseIds: Collection<UUID>): Set<UUID> {
|
||||||
if (courseIds.isEmpty()) return emptySet()
|
if (courseIds.isEmpty()) return emptySet()
|
||||||
return courses.findAllById(courseIds).filter { it.status == Course.STATUS_ACTIVE }.mapTo(HashSet()) { it.id }
|
return courses.findAllById(courseIds).filter { it.status == Course.STATUS_ACTIVE }.mapTo(HashSet()) { it.id }
|
||||||
|
|||||||
@@ -0,0 +1,260 @@
|
|||||||
|
package ru.ysu.lms.academic.lab
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt
|
||||||
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||||
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.context.WebApplicationContext
|
||||||
|
import org.testcontainers.junit.jupiter.Container
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers
|
||||||
|
import org.testcontainers.postgresql.PostgreSQLContainer
|
||||||
|
import ru.ysu.lms.academic.course.CourseCreateRequest
|
||||||
|
import ru.ysu.lms.academic.course.CourseService
|
||||||
|
import ru.ysu.lms.academic.course.CourseTeacherRequest
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Запись в лабораторные: преподаватель управляет только лабораторными своих курсов,
|
||||||
|
* студент не может писать вовсе, администратор не ограничен.
|
||||||
|
*/
|
||||||
|
@Testcontainers
|
||||||
|
@SpringBootTest
|
||||||
|
@Transactional
|
||||||
|
class LabTeacherAccessIntegrationTest {
|
||||||
|
companion object {
|
||||||
|
@Container
|
||||||
|
@ServiceConnection
|
||||||
|
@JvmStatic
|
||||||
|
val postgres = PostgreSQLContainer("postgres:18")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var context: WebApplicationContext
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var courseService: CourseService
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var labService: LabService
|
||||||
|
|
||||||
|
private val mockMvc: MockMvc by lazy {
|
||||||
|
MockMvcBuilders
|
||||||
|
.webAppContextSetup(context)
|
||||||
|
.apply<DefaultMockMvcBuilder>(springSecurity())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher can update lab of own course`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
val teacherId = UUID.randomUUID()
|
||||||
|
assignTeacher(courseId, teacherId)
|
||||||
|
val labId = newLab(courseId)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
put("/api/v1/labs/{id}", labId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"title":"Обновлено преподавателем"}""")
|
||||||
|
.with(jwtFor(teacherId, "TEACHER")),
|
||||||
|
).andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.title").value("Обновлено преподавателем"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher cannot update lab of foreign course`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
val labId = newLab(courseId)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
put("/api/v1/labs/{id}", labId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"title":"Чужая лабораторная"}""")
|
||||||
|
.with(jwtFor(UUID.randomUUID(), "TEACHER")),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher can create lab in own course`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
val teacherId = UUID.randomUUID()
|
||||||
|
assignTeacher(courseId, teacherId)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"number":1,"title":"Новая лабораторная","courseId":"$courseId","levels":[]}""")
|
||||||
|
.with(jwtFor(teacherId, "TEACHER")),
|
||||||
|
).andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.courseId").value(courseId.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher cannot create lab in foreign course`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"number":1,"title":"Чужая лабораторная","courseId":"$courseId","levels":[]}""")
|
||||||
|
.with(jwtFor(UUID.randomUUID(), "TEACHER")),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher create without course is bad request`() {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"number":1,"title":"Без курса","levels":[]}""")
|
||||||
|
.with(jwtFor(UUID.randomUUID(), "TEACHER")),
|
||||||
|
).andExpect(status().isBadRequest)
|
||||||
|
.andExpect(jsonPath("$.detail").value("Укажите курс"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `admin can update and create labs in any course`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
val labId = newLab(courseId)
|
||||||
|
val admin = jwtFor(UUID.randomUUID(), "ADMIN")
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
put("/api/v1/labs/{id}", labId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"title":"Обновлено администратором"}""")
|
||||||
|
.with(admin),
|
||||||
|
).andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.title").value("Обновлено администратором"))
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"number":2,"title":"Создано администратором","courseId":"$courseId","levels":[]}""")
|
||||||
|
.with(admin),
|
||||||
|
).andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.courseId").value(courseId.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `student cannot update or create labs`() {
|
||||||
|
val courseId = newCourse()
|
||||||
|
val labId = newLab(courseId)
|
||||||
|
val student = jwtFor(UUID.randomUUID(), "STUDENT")
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
put("/api/v1/labs/{id}", labId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"title":"Студент не должен менять"}""")
|
||||||
|
.with(student),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"number":2,"title":"Студент не должен создавать","courseId":"$courseId","levels":[]}""")
|
||||||
|
.with(student),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher can copy own lab into own course`() {
|
||||||
|
val sourceCourseId = newCourse()
|
||||||
|
val targetCourseId = newCourse()
|
||||||
|
val teacherId = UUID.randomUUID()
|
||||||
|
assignTeacher(sourceCourseId, teacherId)
|
||||||
|
assignTeacher(targetCourseId, teacherId)
|
||||||
|
val sourceLabId = newLab(sourceCourseId)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs/{id}/copy", sourceLabId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"courseId":"$targetCourseId","number":2}""")
|
||||||
|
.with(jwtFor(teacherId, "TEACHER")),
|
||||||
|
).andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.courseId").value(targetCourseId.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `teacher cannot copy foreign lab or into foreign course`() {
|
||||||
|
val ownCourseId = newCourse()
|
||||||
|
val foreignCourseId = newCourse()
|
||||||
|
val teacherId = UUID.randomUUID()
|
||||||
|
assignTeacher(ownCourseId, teacherId)
|
||||||
|
val ownLabId = newLab(ownCourseId)
|
||||||
|
val foreignLabId = newLab(foreignCourseId)
|
||||||
|
val teacher = jwtFor(teacherId, "TEACHER")
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs/{id}/copy", foreignLabId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"courseId":"$ownCourseId","number":2}""")
|
||||||
|
.with(teacher),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
post("/api/v1/labs/{id}/copy", ownLabId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("""{"courseId":"$foreignCourseId","number":2}""")
|
||||||
|
.with(teacher),
|
||||||
|
).andExpect(status().isForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newCourse(): UUID =
|
||||||
|
UUID.fromString(
|
||||||
|
courseService
|
||||||
|
.create(CourseCreateRequest("Курс ${UUID.randomUUID()}"), UUID.randomUUID())
|
||||||
|
.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun assignTeacher(
|
||||||
|
courseId: UUID,
|
||||||
|
teacherId: UUID,
|
||||||
|
) {
|
||||||
|
courseService.assignTeacher(courseId, CourseTeacherRequest(teacherId.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newLab(
|
||||||
|
courseId: UUID,
|
||||||
|
number: Int = 1,
|
||||||
|
): UUID =
|
||||||
|
UUID.fromString(
|
||||||
|
labService
|
||||||
|
.create(
|
||||||
|
LabCreateRequest(
|
||||||
|
number = number,
|
||||||
|
title = "Лабораторная ${UUID.randomUUID()}",
|
||||||
|
courseId = courseId,
|
||||||
|
),
|
||||||
|
).id,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun jwtFor(
|
||||||
|
subject: UUID,
|
||||||
|
role: String,
|
||||||
|
) = jwt()
|
||||||
|
.authorities(SimpleGrantedAuthority("ROLE_$role"))
|
||||||
|
.jwt { it.subject(subject.toString()).claim("role", role) }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user