fix: prevent user self-deletion

closes #100
This commit is contained in:
Gauthier Roebroeck 2020-03-02 22:34:06 +08:00
parent 0791e52592
commit 3d9b78d364
2 changed files with 57 additions and 49 deletions

View file

@ -40,7 +40,9 @@
</v-list-item-action>
<v-list-item-action>
<v-btn icon @click="promptDeleteUser(u)">
<v-btn icon @click="promptDeleteUser(u)"
:disabled="u.id === me.id"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-action>
@ -90,6 +92,9 @@ export default Vue.extend({
computed: {
users (): UserWithSharedLibrariesDto[] {
return this.$store.state.komgaUsers.users
},
me (): UserDto {
return this.$store.state.komgaUsers.me
}
},
async mounted () {

View file

@ -33,20 +33,20 @@ private val logger = KotlinLogging.logger {}
@RestController
@RequestMapping("api/v1/users", produces = [MediaType.APPLICATION_JSON_VALUE])
class UserController(
private val userDetailsLifecycle: KomgaUserDetailsLifecycle,
private val userRepository: KomgaUserRepository,
private val libraryRepository: LibraryRepository
private val userDetailsLifecycle: KomgaUserDetailsLifecycle,
private val userRepository: KomgaUserRepository,
private val libraryRepository: LibraryRepository
) {
@GetMapping("me")
fun getMe(@AuthenticationPrincipal principal: KomgaPrincipal): UserDto =
principal.user.toDto()
principal.user.toDto()
@PatchMapping("me/password")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun updatePassword(
@AuthenticationPrincipal principal: KomgaPrincipal,
@Valid @RequestBody newPasswordDto: PasswordUpdateDto
@AuthenticationPrincipal principal: KomgaPrincipal,
@Valid @RequestBody newPasswordDto: PasswordUpdateDto
) {
userDetailsLifecycle.updatePassword(principal, newPasswordDto.password, false)
}
@ -54,22 +54,25 @@ class UserController(
@GetMapping
@PreAuthorize("hasRole('ADMIN')")
fun getAll(): List<UserWithSharedLibrariesDto> =
userRepository.findAll().map { it.toWithSharedLibrariesDto() }
userRepository.findAll().map { it.toWithSharedLibrariesDto() }
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
@PreAuthorize("hasRole('ADMIN')")
fun addOne(@Valid @RequestBody newUser: UserCreationDto): UserDto =
try {
(userDetailsLifecycle.createUser(newUser.toUserDetails()) as KomgaPrincipal).toDto()
} catch (e: UserEmailAlreadyExistsException) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "A user with this email already exists")
}
try {
(userDetailsLifecycle.createUser(newUser.toUserDetails()) as KomgaPrincipal).toDto()
} catch (e: UserEmailAlreadyExistsException) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "A user with this email already exists")
}
@DeleteMapping("{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
@PreAuthorize("hasRole('ADMIN')")
fun delete(@PathVariable id: Long) {
@PreAuthorize("hasRole('ADMIN') and #principal.user.id != #id")
fun delete(
@PathVariable id: Long,
@AuthenticationPrincipal principal: KomgaPrincipal
) {
userRepository.findByIdOrNull(id)?.let {
userDetailsLifecycle.deleteUser(it)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
@ -79,8 +82,8 @@ class UserController(
@ResponseStatus(HttpStatus.NO_CONTENT)
@PreAuthorize("hasRole('ADMIN')")
fun updateSharesLibraries(
@PathVariable id: Long,
@Valid @RequestBody sharedLibrariesUpdateDto: SharedLibrariesUpdateDto
@PathVariable id: Long,
@Valid @RequestBody sharedLibrariesUpdateDto: SharedLibrariesUpdateDto
) {
userRepository.findByIdOrNull(id)?.let { user ->
if (sharedLibrariesUpdateDto.all) {
@ -96,59 +99,59 @@ class UserController(
}
data class UserDto(
val id: Long,
val email: String,
val roles: List<String>
val id: Long,
val email: String,
val roles: List<String>
)
fun KomgaUser.toDto() =
UserDto(
id = id,
email = email,
roles = roles.map { it.name }
)
UserDto(
id = id,
email = email,
roles = roles.map { it.name }
)
data class UserWithSharedLibrariesDto(
val id: Long,
val email: String,
val roles: List<String>,
val sharedAllLibraries: Boolean,
val sharedLibraries: List<SharedLibraryDto>
val id: Long,
val email: String,
val roles: List<String>,
val sharedAllLibraries: Boolean,
val sharedLibraries: List<SharedLibraryDto>
)
data class SharedLibraryDto(
val id: Long,
val name: String
val id: Long,
val name: String
)
fun KomgaUser.toWithSharedLibrariesDto() =
UserWithSharedLibrariesDto(
id = id,
email = email,
roles = roles.map { it.name },
sharedAllLibraries = sharedAllLibraries,
sharedLibraries = sharedLibraries.map { SharedLibraryDto(it.id, it.name) }
)
UserWithSharedLibrariesDto(
id = id,
email = email,
roles = roles.map { it.name },
sharedAllLibraries = sharedAllLibraries,
sharedLibraries = sharedLibraries.map { SharedLibraryDto(it.id, it.name) }
)
fun KomgaPrincipal.toDto() = user.toDto()
data class UserCreationDto(
@get:Email val email: String,
@get:NotBlank val password: String,
val roles: List<String> = emptyList()
@get:Email val email: String,
@get:NotBlank val password: String,
val roles: List<String> = emptyList()
) {
fun toUserDetails(): UserDetails =
User.withUsername(email)
.password(password)
.roles(*roles.toTypedArray())
.build()
User.withUsername(email)
.password(password)
.roles(*roles.toTypedArray())
.build()
}
data class PasswordUpdateDto(
@get:NotBlank val password: String
@get:NotBlank val password: String
)
data class SharedLibrariesUpdateDto(
val all: Boolean,
val libraryIds: Set<Long>
val all: Boolean,
val libraryIds: Set<Long>
)