mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Start implementation of game requests
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package org.gameyfin.app.core.plugins.dto
|
||||
|
||||
class ExternalProviderIdDto(
|
||||
val pluginId: String,
|
||||
val externalProviderId: String,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "$pluginId:$externalProviderId"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
package org.gameyfin.app.core.security
|
||||
|
||||
import org.gameyfin.app.core.Role
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
|
||||
fun getCurrentAuth(): Authentication {
|
||||
return SecurityContextHolder.getContext().authentication
|
||||
}
|
||||
|
||||
fun isCurrentUserAdmin(): Boolean {
|
||||
return SecurityContextHolder.getContext().authentication?.authorities?.any { it.authority == Role.Names.ADMIN || it.authority == Role.Names.SUPERADMIN }
|
||||
return getCurrentAuth().authorities?.any { it.authority == Role.Names.ADMIN || it.authority == Role.Names.SUPERADMIN }
|
||||
?: false
|
||||
}
|
||||
@@ -5,8 +5,12 @@ import com.vaadin.hilla.Endpoint
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
import org.gameyfin.app.core.Role
|
||||
import org.gameyfin.app.core.annotations.DynamicPublicAccess
|
||||
import org.gameyfin.app.core.plugins.dto.ExternalProviderIdDto
|
||||
import org.gameyfin.app.core.security.isCurrentUserAdmin
|
||||
import org.gameyfin.app.games.dto.*
|
||||
import org.gameyfin.app.games.dto.GameDto
|
||||
import org.gameyfin.app.games.dto.GameEvent
|
||||
import org.gameyfin.app.games.dto.GameSearchResultDto
|
||||
import org.gameyfin.app.games.dto.GameUpdateDto
|
||||
import org.gameyfin.app.libraries.LibraryCoreService
|
||||
import org.gameyfin.app.libraries.LibraryService
|
||||
import reactor.core.publisher.Flux
|
||||
@@ -45,7 +49,12 @@ class GameEndpoint(
|
||||
}
|
||||
|
||||
@RolesAllowed(Role.Names.ADMIN)
|
||||
fun matchManually(originalIds: Map<String, OriginalIdDto>, path: String, libraryId: Long, replaceGameId: Long?) {
|
||||
fun matchManually(
|
||||
originalIds: Map<String, ExternalProviderIdDto>,
|
||||
path: String,
|
||||
libraryId: Long,
|
||||
replaceGameId: Long?
|
||||
) {
|
||||
val library = libraryService.getById(libraryId)
|
||||
val game = gameService.matchManually(originalIds, Path.of(path), library, replaceGameId)
|
||||
if (game != null) {
|
||||
|
||||
@@ -12,10 +12,12 @@ import org.gameyfin.app.core.alphaNumeric
|
||||
import org.gameyfin.app.core.filesystem.FilesystemService
|
||||
import org.gameyfin.app.core.filterValuesNotNull
|
||||
import org.gameyfin.app.core.plugins.PluginService
|
||||
import org.gameyfin.app.core.plugins.dto.ExternalProviderIdDto
|
||||
import org.gameyfin.app.core.plugins.management.GameyfinPluginDescriptor
|
||||
import org.gameyfin.app.core.plugins.management.GameyfinPluginManager
|
||||
import org.gameyfin.app.core.plugins.management.PluginManagementEntry
|
||||
import org.gameyfin.app.core.replaceRomanNumerals
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.games.dto.*
|
||||
import org.gameyfin.app.games.entities.*
|
||||
import org.gameyfin.app.games.extensions.toDtos
|
||||
@@ -25,7 +27,6 @@ import org.gameyfin.app.media.ImageService
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.gameyfin.pluginapi.gamemetadata.*
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -149,8 +150,7 @@ class GameService(
|
||||
val existingGame = gameRepository.findByIdOrNull(gameUpdateDto.id)
|
||||
?: throw IllegalArgumentException("Game with ID $gameUpdateDto.id not found")
|
||||
|
||||
val userDetails = SecurityContextHolder.getContext().authentication.principal
|
||||
val user = when (userDetails) {
|
||||
val user = when (val userDetails = getCurrentAuth().principal) {
|
||||
is UserDetails -> userService.getByUsernameNonNull(userDetails.username)
|
||||
is OidcUser -> userService.getByUsernameNonNull(userDetails.preferredUsername)
|
||||
else -> throw IllegalStateException("Unkown user type: ${userDetails::class.java.name}")
|
||||
@@ -260,12 +260,12 @@ class GameService(
|
||||
|
||||
val game = getById(game.id!!)
|
||||
|
||||
val originalIds: Map<String, OriginalIdDto> = game.metadata.originalIds
|
||||
val originalIds: Map<String, ExternalProviderIdDto> = game.metadata.originalIds
|
||||
.map { (provider, originalId) ->
|
||||
val providerId = pluginManager.getExtensions(provider.pluginId).first()?.javaClass?.name ?: return null
|
||||
val pluginId = provider.pluginId
|
||||
val originalId = originalId
|
||||
providerId to OriginalIdDto(pluginId, originalId)
|
||||
providerId to ExternalProviderIdDto(pluginId, originalId)
|
||||
}
|
||||
.toMap()
|
||||
|
||||
@@ -504,12 +504,12 @@ class GameService(
|
||||
sorted.mapNotNull { selector(it.second) }.firstOrNull { it.isNotEmpty() }
|
||||
|
||||
// Collect originalIds for this group
|
||||
val originalIds: Map<String, OriginalIdDto> = group
|
||||
val originalIds: Map<String, ExternalProviderIdDto> = group
|
||||
.mapNotNull { (provider, metadata) ->
|
||||
val providerId = provider.javaClass.name
|
||||
val pluginId = providerToManagementEntry[provider]?.pluginId ?: return@mapNotNull null
|
||||
val originalId = metadata.originalId
|
||||
if (providerId != null) providerId to OriginalIdDto(pluginId, originalId) else null
|
||||
if (providerId != null) providerId to ExternalProviderIdDto(pluginId, originalId) else null
|
||||
}
|
||||
.toMap()
|
||||
|
||||
@@ -567,7 +567,7 @@ class GameService(
|
||||
}
|
||||
|
||||
fun matchManually(
|
||||
originalIds: Map<String, OriginalIdDto>,
|
||||
originalIds: Map<String, ExternalProviderIdDto>,
|
||||
path: Path,
|
||||
library: Library,
|
||||
replaceGameId: Long? = null,
|
||||
@@ -578,7 +578,7 @@ class GameService(
|
||||
coroutineScope {
|
||||
metadataPlugins.associateWith { plugin ->
|
||||
async {
|
||||
val originalId = originalIds[plugin.javaClass.name]?.originalId ?: return@async null
|
||||
val originalId = originalIds[plugin.javaClass.name]?.externalProviderId ?: return@async null
|
||||
try {
|
||||
return@async plugin.fetchById(originalId)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.gameyfin.app.games.dto
|
||||
|
||||
import org.gameyfin.app.core.plugins.dto.ExternalProviderIdDto
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
||||
@@ -11,18 +12,9 @@ class GameSearchResultDto(
|
||||
val release: Instant?,
|
||||
val publishers: Collection<String>?,
|
||||
val developers: Collection<String>?,
|
||||
val originalIds: Map<String, OriginalIdDto>
|
||||
val originalIds: Map<String, ExternalProviderIdDto>
|
||||
)
|
||||
|
||||
class OriginalIdDto(
|
||||
val pluginId: String,
|
||||
val originalId: String,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "$pluginId:$originalId"
|
||||
}
|
||||
}
|
||||
|
||||
class UrlWithSourceDto(
|
||||
val url: String,
|
||||
val pluginId: String
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.gameyfin.app.core.Role
|
||||
import org.gameyfin.app.core.Utils
|
||||
import org.gameyfin.app.core.annotations.DynamicPublicAccess
|
||||
import org.gameyfin.app.core.plugins.PluginService
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.games.entities.Image
|
||||
import org.gameyfin.app.games.entities.ImageType
|
||||
import org.gameyfin.app.users.UserService
|
||||
@@ -15,8 +16,6 @@ import org.springframework.core.io.InputStreamResource
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
|
||||
@@ -61,7 +60,7 @@ class ImageEndpoint(
|
||||
@PermitAll
|
||||
@PostMapping("/avatar/upload")
|
||||
fun uploadAvatar(@RequestParam("file") file: MultipartFile) {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
|
||||
val image: Image = if (!userService.hasAvatar(auth.name)) {
|
||||
imageService.createFile(ImageType.AVATAR, file.inputStream, file.contentType!!)
|
||||
@@ -76,7 +75,7 @@ class ImageEndpoint(
|
||||
@PermitAll
|
||||
@PostMapping("/avatar/delete")
|
||||
fun deleteAvatar() {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
userService.deleteAvatar(auth.name)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.gameyfin.app.messages
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.gameyfin.app.core.events.*
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.messages.providers.AbstractMessageProvider
|
||||
import org.gameyfin.app.messages.templates.MessageTemplateService
|
||||
import org.gameyfin.app.messages.templates.MessageTemplates
|
||||
@@ -10,8 +11,6 @@ import org.gameyfin.app.users.UserService
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.event.EventListener
|
||||
import org.springframework.scheduling.annotation.Async
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.*
|
||||
|
||||
@@ -61,7 +60,7 @@ class MessageService(
|
||||
}
|
||||
|
||||
try {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
val user = userService.getByUsername(auth.name) ?: throw IllegalStateException("User not found")
|
||||
val template = templateService.getMessageTemplate(templateKey)
|
||||
sendNotification(user.email, "[Gameyfin] Test Notification", template, placeholders)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.gameyfin.app.requests
|
||||
|
||||
import jakarta.persistence.*
|
||||
import org.gameyfin.app.requests.status.GameRequestStatus
|
||||
import org.gameyfin.app.users.entities.User
|
||||
import org.hibernate.annotations.CreationTimestamp
|
||||
import org.hibernate.annotations.UpdateTimestamp
|
||||
import java.time.Instant
|
||||
|
||||
typealias ExternalProviderIds = Map<String, String>
|
||||
|
||||
@Entity
|
||||
class GameRequest(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(nullable = false, updatable = false)
|
||||
var createdAt: Instant? = null,
|
||||
|
||||
@UpdateTimestamp
|
||||
@Column(nullable = false)
|
||||
var updatedAt: Instant? = null,
|
||||
|
||||
@Column(nullable = false)
|
||||
val title: String,
|
||||
|
||||
@Column(nullable = false)
|
||||
val release: Instant,
|
||||
|
||||
@Column(nullable = false)
|
||||
var status: GameRequestStatus,
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
var requester: User? = null,
|
||||
|
||||
var voters: MutableList<User> = mutableListOf(),
|
||||
|
||||
@ElementCollection
|
||||
val externalProviderIds: ExternalProviderIds
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.gameyfin.app.requests
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface GameRequestRepository : JpaRepository<GameRequest, Long>
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.gameyfin.app.requests
|
||||
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.games.dto.GameUserEvent
|
||||
import org.gameyfin.app.requests.dto.GameRequestCreationDto
|
||||
import org.gameyfin.app.requests.status.GameRequestStatus
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Sinks
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
@Service
|
||||
class GameRequestService(
|
||||
private val gameRequestRepository: GameRequestRepository,
|
||||
private val userService: UserService
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
/* Websockets */
|
||||
private val gameRequestEvents = Sinks.many().multicast().onBackpressureBuffer<GameUserEvent>(1024, false)
|
||||
|
||||
fun subscribe(): Flux<List<GameUserEvent>> {
|
||||
log.debug { "New user subscription for gameRequestEvents" }
|
||||
return gameRequestEvents.asFlux()
|
||||
.buffer(100.milliseconds.toJavaDuration())
|
||||
.doOnSubscribe {
|
||||
log.debug { "Subscriber added to gameRequestEvents [${gameRequestEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
.doFinally {
|
||||
log.debug { "Subscriber removed from gameRequestEvents with signal type $it [${gameRequestEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
}
|
||||
|
||||
fun emit(event: GameUserEvent) {
|
||||
gameRequestEvents.tryEmitNext(event)
|
||||
}
|
||||
}
|
||||
|
||||
fun createRequest(gameRequest: GameRequestCreationDto) {
|
||||
val currentUser = userService.getByUsername(getCurrentAuth().name)
|
||||
|
||||
val gameRequest = GameRequest(
|
||||
title = gameRequest.title,
|
||||
release = gameRequest.release,
|
||||
status = GameRequestStatus.PENDING,
|
||||
externalProviderIds = gameRequest.externalProviderIds,
|
||||
requester = currentUser
|
||||
)
|
||||
|
||||
gameRequestRepository.save(gameRequest)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.gameyfin.app.requests.dto
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
class GameRequestCreationDto(
|
||||
val title: String,
|
||||
val release: Instant,
|
||||
val externalProviderIds: Map<String, String>
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.gameyfin.app.requests.dto
|
||||
|
||||
import org.gameyfin.app.requests.status.GameRequestStatus
|
||||
import org.gameyfin.app.users.dto.UserInfoAdminDto
|
||||
import java.time.Instant
|
||||
|
||||
class GameRequestDto(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
val release: Instant,
|
||||
val status: GameRequestStatus,
|
||||
val requester: UserInfoAdminDto
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.gameyfin.app.requests.dto
|
||||
|
||||
sealed class GameRequestEvent {
|
||||
abstract val type: String
|
||||
|
||||
data class Created(val game: GameRequestDto, override val type: String = "created") : GameRequestEvent()
|
||||
data class Updated(val game: GameRequestDto, override val type: String = "updated") : GameRequestEvent()
|
||||
data class Deleted(val gameRequestId: Long, override val type: String = "deleted") : GameRequestEvent()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.gameyfin.app.requests.extensions
|
||||
|
||||
import org.gameyfin.app.requests.GameRequest
|
||||
import org.gameyfin.app.requests.dto.GameRequestDto
|
||||
|
||||
fun GameRequest.toDto(): GameRequestDto {
|
||||
return GameRequestDto(
|
||||
id = this.id!!,
|
||||
title = this.title,
|
||||
release = this.release,
|
||||
externalProviderIds = this.externalProviderIds,
|
||||
status = this.status,
|
||||
requester = this.requester.toDto()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.gameyfin.app.requests.status
|
||||
|
||||
enum class GameRequestStatus {
|
||||
PENDING,
|
||||
APPROVED,
|
||||
FULFILLED,
|
||||
REJECTED
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package org.gameyfin.app.setup
|
||||
import com.vaadin.flow.server.auth.AnonymousAllowed
|
||||
import com.vaadin.hilla.Endpoint
|
||||
import com.vaadin.hilla.exception.EndpointException
|
||||
import org.gameyfin.app.users.dto.UserInfoDto
|
||||
import org.gameyfin.app.users.dto.UserInfoAdminDto
|
||||
import org.gameyfin.app.users.dto.UserRegistrationDto
|
||||
|
||||
@Endpoint
|
||||
@@ -16,7 +16,7 @@ class SetupEndpoint(
|
||||
}
|
||||
|
||||
@AnonymousAllowed
|
||||
fun registerSuperAdmin(superAdminRegistration: UserRegistrationDto): UserInfoDto {
|
||||
fun registerSuperAdmin(superAdminRegistration: UserRegistrationDto): UserInfoAdminDto {
|
||||
if (setupService.isSetupCompleted()) throw EndpointException("Setup already completed")
|
||||
return setupService.createInitialAdminUser(superAdminRegistration)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.gameyfin.app.setup
|
||||
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.gameyfin.app.core.Role
|
||||
import org.gameyfin.app.users.RoleService
|
||||
import org.gameyfin.app.users.dto.UserInfoDto
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.gameyfin.app.users.dto.UserInfoAdminDto
|
||||
import org.gameyfin.app.users.dto.UserRegistrationDto
|
||||
import org.gameyfin.app.users.entities.User
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -26,7 +26,7 @@ class SetupService(
|
||||
/**
|
||||
* Creates the initial user with Super-Admin permissions
|
||||
*/
|
||||
fun createInitialAdminUser(registration: UserRegistrationDto): UserInfoDto {
|
||||
fun createInitialAdminUser(registration: UserRegistrationDto): UserInfoAdminDto {
|
||||
val superAdmin = User(
|
||||
username = registration.username,
|
||||
password = registration.password,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.gameyfin.app.users
|
||||
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.users.entities.User
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.core.session.SessionInformation
|
||||
import org.springframework.security.core.session.SessionRegistry
|
||||
@@ -11,14 +11,12 @@ import org.springframework.stereotype.Service
|
||||
class SessionService(private val sessionRegistry: SessionRegistry) {
|
||||
|
||||
fun logoutAllSessions() {
|
||||
val auth: Authentication? = SecurityContextHolder.getContext().authentication
|
||||
if (auth != null) {
|
||||
val sessions: List<SessionInformation> = sessionRegistry.getAllSessions(auth.principal, false)
|
||||
for (sessionInfo in sessions) {
|
||||
sessionInfo.expireNow()
|
||||
}
|
||||
SecurityContextHolder.clearContext()
|
||||
val auth = getCurrentAuth()
|
||||
val sessions: List<SessionInformation> = sessionRegistry.getAllSessions(auth.principal, false)
|
||||
for (sessionInfo in sessions) {
|
||||
sessionInfo.expireNow()
|
||||
}
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
fun logoutAllSessions(user: User) {
|
||||
|
||||
@@ -5,11 +5,11 @@ import com.vaadin.hilla.Endpoint
|
||||
import jakarta.annotation.security.PermitAll
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
import org.gameyfin.app.core.Role
|
||||
import org.gameyfin.app.users.dto.UserInfoDto
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.users.dto.UserInfoAdminDto
|
||||
import org.gameyfin.app.users.dto.UserUpdateDto
|
||||
import org.gameyfin.app.users.enums.RoleAssignmentResult
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
|
||||
|
||||
@Endpoint
|
||||
@@ -18,15 +18,15 @@ class UserEndpoint(
|
||||
private val roleService: RoleService
|
||||
) {
|
||||
@AnonymousAllowed
|
||||
fun getUserInfo(): UserInfoDto? {
|
||||
val auth = SecurityContextHolder.getContext().authentication
|
||||
fun getUserInfo(): UserInfoAdminDto? {
|
||||
val auth = getCurrentAuth()
|
||||
if (!auth.isAuthenticated || auth.principal == "anonymousUser") return null
|
||||
return userService.getUserInfo()
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
fun updateUser(updates: UserUpdateDto) {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth: Authentication = getCurrentAuth()
|
||||
userService.updateUser(auth.name, updates)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class UserEndpoint(
|
||||
}
|
||||
|
||||
@RolesAllowed(Role.Names.ADMIN)
|
||||
fun getAllUsers(): List<UserInfoDto> {
|
||||
fun getAllUsers(): List<UserInfoAdminDto> {
|
||||
return userService.getAllUsers()
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class UserEndpoint(
|
||||
|
||||
@PermitAll
|
||||
fun deleteUser() {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth: Authentication = getCurrentAuth()
|
||||
userService.deleteUser(auth.name)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class UserEndpoint(
|
||||
|
||||
@RolesAllowed(Role.Names.ADMIN)
|
||||
fun getRolesBelow(): List<String> {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth: Authentication = getCurrentAuth()
|
||||
return roleService.getRolesBelowAuth(auth).map { it.roleName }
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@ import org.gameyfin.app.config.ConfigService
|
||||
import org.gameyfin.app.core.Role
|
||||
import org.gameyfin.app.core.Utils
|
||||
import org.gameyfin.app.core.events.*
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.games.entities.Image
|
||||
import org.gameyfin.app.media.ImageService
|
||||
import org.gameyfin.app.users.dto.UserInfoDto
|
||||
import org.gameyfin.app.users.dto.UserInfoAdminDto
|
||||
import org.gameyfin.app.users.dto.UserRegistrationDto
|
||||
import org.gameyfin.app.users.dto.UserUpdateDto
|
||||
import org.gameyfin.app.users.emailconfirmation.EmailConfirmationService
|
||||
@@ -17,7 +18,6 @@ import org.gameyfin.app.users.persistence.UserRepository
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
@@ -77,7 +77,7 @@ class UserService(
|
||||
fun findByOidcProviderId(oidcProviderId: String): org.gameyfin.app.users.entities.User? =
|
||||
userRepository.findByOidcProviderId(oidcProviderId)
|
||||
|
||||
fun getAllUsers(): List<UserInfoDto> {
|
||||
fun getAllUsers(): List<UserInfoAdminDto> {
|
||||
return userRepository.findAll().map { u -> toUserInfo(u) }
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ class UserService(
|
||||
return userRepository.findByUsername(username) ?: throw UsernameNotFoundException("Unknown user '$username'")
|
||||
}
|
||||
|
||||
fun getUserInfo(): UserInfoDto {
|
||||
val auth = SecurityContextHolder.getContext().authentication
|
||||
fun getUserInfo(): UserInfoAdminDto {
|
||||
val auth = getCurrentAuth()
|
||||
val principal = auth.principal
|
||||
|
||||
if (principal is OidcUser) {
|
||||
@@ -238,7 +238,7 @@ class UserService(
|
||||
return RoleAssignmentResult.NO_ROLES_PROVIDED
|
||||
}
|
||||
|
||||
val currentUser = SecurityContextHolder.getContext().authentication
|
||||
val currentUser = getCurrentAuth()
|
||||
val targetUser = getByUsernameNonNull(username)
|
||||
|
||||
if (!canManage(targetUser)) {
|
||||
@@ -266,7 +266,7 @@ class UserService(
|
||||
}
|
||||
|
||||
fun canManage(targetUser: org.gameyfin.app.users.entities.User): Boolean {
|
||||
val currentUser = SecurityContextHolder.getContext().authentication
|
||||
val currentUser = getCurrentAuth()
|
||||
val currentUserLevel = roleService.getHighestRoleFromAuthorities(currentUser.authorities).powerLevel
|
||||
val targetUserLevel = roleService.getHighestRole(targetUser.roles).powerLevel
|
||||
return currentUserLevel > targetUserLevel
|
||||
@@ -285,8 +285,8 @@ class UserService(
|
||||
eventPublisher.publishEvent(AccountDeletedEvent(this, user, Utils.Companion.getBaseUrl()))
|
||||
}
|
||||
|
||||
fun toUserInfo(user: org.gameyfin.app.users.entities.User): UserInfoDto {
|
||||
return UserInfoDto(
|
||||
fun toUserInfo(user: org.gameyfin.app.users.entities.User): UserInfoAdminDto {
|
||||
return UserInfoAdminDto(
|
||||
username = user.username,
|
||||
email = user.email,
|
||||
emailConfirmed = user.emailConfirmed,
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package org.gameyfin.app.users.dto
|
||||
|
||||
import org.gameyfin.app.core.Role
|
||||
|
||||
data class UserInfoDto(
|
||||
data class UserInfoAdminDto(
|
||||
val username: String,
|
||||
val managedBySso: Boolean,
|
||||
val email: String,
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.gameyfin.app.users.dto
|
||||
|
||||
data class UserInfoUserDto(
|
||||
val username: String,
|
||||
val hasAvatar: Boolean,
|
||||
val avatarId: Long? = null,
|
||||
)
|
||||
+3
-4
@@ -1,11 +1,10 @@
|
||||
package org.gameyfin.app.users.emailconfirmation
|
||||
|
||||
import com.vaadin.hilla.Endpoint
|
||||
import org.gameyfin.app.users.UserService
|
||||
import jakarta.annotation.security.PermitAll
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.shared.token.TokenValidationResult
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.gameyfin.app.users.UserService
|
||||
|
||||
@Endpoint
|
||||
class EmailConfirmationEndpoint(
|
||||
@@ -20,7 +19,7 @@ class EmailConfirmationEndpoint(
|
||||
|
||||
@PermitAll
|
||||
fun resendEmailConfirmation() {
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
userService.getByUsername(auth.name)?.let {
|
||||
emailConfirmationService.resendEmailConfirmation(it)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.gameyfin.app.users.preferences
|
||||
|
||||
import org.gameyfin.app.users.UserService
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.io.Serializable
|
||||
|
||||
@@ -135,7 +135,7 @@ class UserPreferencesService(
|
||||
}
|
||||
|
||||
private fun id(key: String): UserPreferenceKey {
|
||||
val auth = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
val user = userService.getByUsernameNonNull(auth.name)
|
||||
return UserPreferenceKey(key, user.id!!)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package org.gameyfin.app.users.registration
|
||||
|
||||
import org.gameyfin.app.core.Utils
|
||||
import org.gameyfin.app.core.events.AccountStatusChangedEvent
|
||||
import org.gameyfin.app.core.events.UserInvitationEvent
|
||||
import org.gameyfin.app.core.security.getCurrentAuth
|
||||
import org.gameyfin.app.shared.token.TokenDto
|
||||
import org.gameyfin.app.shared.token.TokenRepository
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.gameyfin.app.core.Utils
|
||||
import org.gameyfin.app.shared.token.TokenService
|
||||
import org.gameyfin.app.shared.token.TokenType
|
||||
import org.gameyfin.app.users.UserService
|
||||
import org.gameyfin.app.users.dto.UserRegistrationDto
|
||||
import org.gameyfin.app.users.enums.UserInvitationAcceptanceResult
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
@@ -30,7 +29,7 @@ class InvitationService(
|
||||
if (userService.existsByEmail(email))
|
||||
throw IllegalStateException("User with email ${Utils.Companion.maskEmail(email)} is already registered")
|
||||
|
||||
val auth: Authentication = SecurityContextHolder.getContext().authentication
|
||||
val auth = getCurrentAuth()
|
||||
val user = userService.getByUsername(auth.name) ?: throw IllegalStateException("User not found")
|
||||
val payload = mapOf(EMAIL_KEY to email)
|
||||
val token = super.generateWithPayload(user, payload)
|
||||
@@ -45,7 +44,8 @@ class InvitationService(
|
||||
}
|
||||
|
||||
fun acceptInvitation(secret: String, registration: UserRegistrationDto): UserInvitationAcceptanceResult {
|
||||
val invitationToken = super.get(secret, TokenType.Invitation) ?: return UserInvitationAcceptanceResult.TOKEN_INVALID
|
||||
val invitationToken =
|
||||
super.get(secret, TokenType.Invitation) ?: return UserInvitationAcceptanceResult.TOKEN_INVALID
|
||||
val email = invitationToken.payload[EMAIL_KEY] ?: return UserInvitationAcceptanceResult.TOKEN_INVALID
|
||||
if (invitationToken.expired) return UserInvitationAcceptanceResult.TOKEN_EXPIRED
|
||||
|
||||
|
||||
Reference in New Issue
Block a user