feat(identity): аккаунты преподавателей
This commit is contained in:
@@ -13,4 +13,6 @@ interface AccountRepository : JpaRepository<Account, UUID> {
|
||||
fun existsByRole(role: LmsRole): Boolean
|
||||
|
||||
fun countByRole(role: LmsRole): Long
|
||||
|
||||
fun findAllByRoleOrderByLoginAsc(role: LmsRole): List<Account>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package ru.ysu.lms.identity.roster
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.util.UUID
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/teachers")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
class TeacherController(
|
||||
private val teacherService: TeacherService,
|
||||
) {
|
||||
@GetMapping
|
||||
fun list(): List<TeacherDto> = teacherService.list()
|
||||
|
||||
@PostMapping
|
||||
fun create(
|
||||
@RequestBody body: TeacherCreateRequest,
|
||||
): TeacherCredential = teacherService.create(body)
|
||||
|
||||
@PostMapping("/{id}/reset-password")
|
||||
fun resetPassword(
|
||||
@PathVariable id: UUID,
|
||||
): ResetPasswordResponse = teacherService.resetPassword(id)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ru.ysu.lms.identity.roster
|
||||
|
||||
/** Преподаватель в списке управления: аккаунт роли TEACHER. */
|
||||
data class TeacherDto(
|
||||
val id: String,
|
||||
val login: String,
|
||||
val name: String,
|
||||
val status: String,
|
||||
val mustChangePassword: Boolean,
|
||||
)
|
||||
|
||||
data class TeacherCreateRequest(
|
||||
val login: String,
|
||||
val password: String? = null,
|
||||
)
|
||||
|
||||
/** Выданные преподавателю учётные данные (пароль показывается один раз). */
|
||||
data class TeacherCredential(
|
||||
val id: String,
|
||||
val login: String,
|
||||
val password: String,
|
||||
)
|
||||
@@ -0,0 +1,81 @@
|
||||
package ru.ysu.lms.identity.roster
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import ru.ysu.lms.common.BadRequestException
|
||||
import ru.ysu.lms.common.ConflictException
|
||||
import ru.ysu.lms.common.NotFoundException
|
||||
import ru.ysu.lms.identity.auth.Passwords
|
||||
import ru.ysu.lms.identity.domain.Account
|
||||
import ru.ysu.lms.identity.domain.AccountStatus
|
||||
import ru.ysu.lms.identity.repo.AccountRepository
|
||||
import ru.ysu.lms.security.LmsRole
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
@Service
|
||||
class TeacherService(
|
||||
private val accounts: AccountRepository,
|
||||
private val passwordEncoder: PasswordEncoder,
|
||||
) {
|
||||
@Transactional(readOnly = true)
|
||||
fun list(): List<TeacherDto> =
|
||||
accounts
|
||||
.findAllByRoleOrderByLoginAsc(LmsRole.TEACHER)
|
||||
.map { account ->
|
||||
TeacherDto(
|
||||
id = account.id.toString(),
|
||||
login = account.login,
|
||||
name = account.login,
|
||||
status = account.status.name,
|
||||
mustChangePassword = account.mustChangePassword,
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun create(request: TeacherCreateRequest): TeacherCredential {
|
||||
val login = request.login.trim()
|
||||
if (login.length < 3) {
|
||||
throw BadRequestException("Логин: минимум 3 символа")
|
||||
}
|
||||
if (accounts.existsByLogin(login)) {
|
||||
throw ConflictException("Логин $login уже занят другим аккаунтом")
|
||||
}
|
||||
val password = request.password?.takeIf { it.isNotBlank() } ?: Passwords.generate()
|
||||
val account =
|
||||
accounts.save(
|
||||
Account(
|
||||
login = login,
|
||||
passwordHash = passwordEncoder.encode(password) ?: "",
|
||||
role = LmsRole.TEACHER,
|
||||
mustChangePassword = true,
|
||||
tempPassword = password,
|
||||
status = AccountStatus.ACTIVE,
|
||||
),
|
||||
)
|
||||
return TeacherCredential(
|
||||
id = account.id.toString(),
|
||||
login = account.login,
|
||||
password = password,
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun resetPassword(teacherId: UUID): ResetPasswordResponse {
|
||||
val account =
|
||||
accounts
|
||||
.findById(teacherId)
|
||||
.orElseThrow { NotFoundException("Преподаватель не найден") }
|
||||
if (account.role != LmsRole.TEACHER) {
|
||||
throw BadRequestException("Сбросить пароль можно только преподавателю")
|
||||
}
|
||||
val password = Passwords.generate()
|
||||
account.passwordHash = passwordEncoder.encode(password) ?: account.passwordHash
|
||||
account.mustChangePassword = true
|
||||
account.tempPassword = password
|
||||
account.updatedAt = Instant.now()
|
||||
accounts.save(account)
|
||||
return ResetPasswordResponse(password)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user