mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Move AvatarController to ImageController
This commit is contained in:
@@ -5,7 +5,7 @@ export async function uploadAvatar(avatar: any) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", avatar);
|
||||
|
||||
const response = await fetchWithAuth("avatar/upload", formData);
|
||||
const response = await fetchWithAuth("images/avatar/upload", formData);
|
||||
|
||||
const result = await response.text();
|
||||
|
||||
@@ -17,7 +17,7 @@ export async function uploadAvatar(avatar: any) {
|
||||
}
|
||||
|
||||
export async function removeAvatar() {
|
||||
const response = await fetchWithAuth("avatar/delete")
|
||||
const response = await fetchWithAuth("images/avatar/delete")
|
||||
|
||||
const result = await response.text();
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function removeAvatar() {
|
||||
}
|
||||
|
||||
export async function removeAvatarByName(name: string) {
|
||||
const response = await fetchWithAuth("avatar/deleteByName?" + new URLSearchParams({name: name}))
|
||||
const response = await fetchWithAuth("images/avatar/deleteByName?" + new URLSearchParams({name: name}))
|
||||
|
||||
const result = await response.text();
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import {Button, Input} from "@nextui-org/react";
|
||||
import {toast} from "sonner";
|
||||
import {LibraryEndpoint, SystemEndpoint} from "Frontend/generated/endpoints";
|
||||
import {useState} from "react";
|
||||
import Game from "Frontend/generated/de/grimsi/gameyfin/games/Game";
|
||||
import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto";
|
||||
|
||||
export default function TestView() {
|
||||
const [gameTitle, setGameTitle] = useState("");
|
||||
const [game, setGame] = useState<Game>();
|
||||
const [game, setGame] = useState<GameDto>();
|
||||
|
||||
function getGame() {
|
||||
LibraryEndpoint.test(gameTitle).then(game => {
|
||||
|
||||
@@ -16,7 +16,7 @@ class Image(
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
|
||||
val originalUrl: URL,
|
||||
val originalUrl: URL? = null,
|
||||
|
||||
val type: ImageType,
|
||||
|
||||
@@ -35,5 +35,6 @@ class Image(
|
||||
|
||||
enum class ImageType {
|
||||
COVER,
|
||||
SCREENSHOT
|
||||
SCREENSHOT,
|
||||
AVATAR
|
||||
}
|
||||
+9
-12
@@ -1,26 +1,24 @@
|
||||
package de.grimsi.gameyfin.users.avatar
|
||||
package de.grimsi.gameyfin.media
|
||||
|
||||
import de.grimsi.gameyfin.core.Role
|
||||
import de.grimsi.gameyfin.users.UserService
|
||||
import jakarta.annotation.security.PermitAll
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
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.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
|
||||
|
||||
@RestController
|
||||
class AvatarController(
|
||||
private val userService: UserService
|
||||
@RequestMapping("/images")
|
||||
class ImageController(
|
||||
private val userService: UserService,
|
||||
private val imageService: ImageService
|
||||
) {
|
||||
|
||||
@PostMapping("/avatar/upload")
|
||||
@@ -42,14 +40,13 @@ class AvatarController(
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@GetMapping("/images/avatar")
|
||||
@GetMapping("/avatar")
|
||||
fun getAvatar(
|
||||
@RequestParam("username") username: String,
|
||||
response: HttpServletResponse
|
||||
@RequestParam("username") username: String
|
||||
): ResponseEntity<InputStreamResource>? {
|
||||
val avatar = userService.getAvatar(username) ?: return ResponseEntity.notFound().build()
|
||||
|
||||
val file = avatar.let { userService.getAvatarFile(it) }
|
||||
val file = avatar.let { imageService.getFileContent(it) }
|
||||
|
||||
val inputStreamResource = InputStreamResource(file)
|
||||
val headers = HttpHeaders()
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.grimsi.gameyfin.media
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Image
|
||||
import de.grimsi.gameyfin.games.entities.ImageType
|
||||
import de.grimsi.gameyfin.games.repositories.ImageContentStore
|
||||
import de.grimsi.gameyfin.games.repositories.ImageRepository
|
||||
import org.springframework.stereotype.Service
|
||||
import java.io.InputStream
|
||||
|
||||
@Service
|
||||
class ImageService(
|
||||
private val imageRepository: ImageRepository,
|
||||
private val imageContentStore: ImageContentStore
|
||||
) {
|
||||
|
||||
fun createFile(type: ImageType, content: InputStream, mimeType: String): Image {
|
||||
val image = Image(type = type, mimeType = mimeType)
|
||||
imageRepository.save(image)
|
||||
return imageContentStore.setContent(image, content)
|
||||
}
|
||||
|
||||
fun getFileContent(image: Image): InputStream {
|
||||
return imageContentStore.getContent(image)
|
||||
}
|
||||
|
||||
fun deleteFile(image: Image) {
|
||||
imageContentStore.unsetContent(image)
|
||||
imageRepository.delete(image)
|
||||
}
|
||||
|
||||
fun updateFileContent(image: Image, content: InputStream, mimeType: String? = null): Image {
|
||||
mimeType?.let { image.mimeType = it }
|
||||
imageRepository.save(image)
|
||||
return imageContentStore.setContent(image, content)
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,15 @@ import de.grimsi.gameyfin.config.ConfigService
|
||||
import de.grimsi.gameyfin.core.Role
|
||||
import de.grimsi.gameyfin.core.Utils
|
||||
import de.grimsi.gameyfin.core.events.*
|
||||
import de.grimsi.gameyfin.games.entities.Image
|
||||
import de.grimsi.gameyfin.games.entities.ImageType
|
||||
import de.grimsi.gameyfin.media.ImageService
|
||||
import de.grimsi.gameyfin.users.dto.UserInfoDto
|
||||
import de.grimsi.gameyfin.users.dto.UserRegistrationDto
|
||||
import de.grimsi.gameyfin.users.dto.UserUpdateDto
|
||||
import de.grimsi.gameyfin.users.emailconfirmation.EmailConfirmationService
|
||||
import de.grimsi.gameyfin.users.entities.Avatar
|
||||
import de.grimsi.gameyfin.users.entities.User
|
||||
import de.grimsi.gameyfin.users.enums.RoleAssignmentResult
|
||||
import de.grimsi.gameyfin.users.persistence.AvatarContentStore
|
||||
import de.grimsi.gameyfin.users.persistence.UserRepository
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import jakarta.transaction.Transactional
|
||||
@@ -28,14 +29,13 @@ import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
class UserService(
|
||||
private val userRepository: UserRepository,
|
||||
private val avatarStore: AvatarContentStore,
|
||||
private val imageService: ImageService,
|
||||
private val passwordEncoder: PasswordEncoder,
|
||||
private val roleService: RoleService,
|
||||
private val sessionService: SessionService,
|
||||
@@ -100,23 +100,20 @@ class UserService(
|
||||
return toUserInfo(user)
|
||||
}
|
||||
|
||||
fun getAvatar(username: String): Avatar? {
|
||||
fun getAvatar(username: String): Image? {
|
||||
val user = getByUsernameNonNull(username)
|
||||
return user.avatar
|
||||
}
|
||||
|
||||
fun getAvatarFile(avatar: Avatar): InputStream {
|
||||
return avatarStore.getContent(avatar)
|
||||
}
|
||||
|
||||
fun setAvatar(username: String, file: MultipartFile) {
|
||||
val user = getByUsernameNonNull(username)
|
||||
|
||||
if (user.avatar == null) {
|
||||
user.avatar = Avatar(mimeType = file.contentType)
|
||||
user.avatar = imageService.createFile(ImageType.AVATAR, file.inputStream, file.contentType!!)
|
||||
} else {
|
||||
user.avatar = imageService.updateFileContent(user.avatar!!, file.inputStream, file.contentType!!)
|
||||
}
|
||||
|
||||
avatarStore.setContent(user.avatar, file.inputStream)
|
||||
userRepository.save(user)
|
||||
}
|
||||
|
||||
@@ -124,8 +121,7 @@ class UserService(
|
||||
val user = getByUsernameNonNull(username)
|
||||
|
||||
if (user.avatar == null) return
|
||||
|
||||
avatarStore.unsetContent(user.avatar)
|
||||
imageService.deleteFile(user.avatar!!)
|
||||
user.avatar = null
|
||||
|
||||
userRepository.save(user)
|
||||
@@ -275,6 +271,7 @@ class UserService(
|
||||
emailConfirmed = user.emailConfirmed,
|
||||
isEnabled = user.enabled,
|
||||
hasAvatar = user.avatar != null,
|
||||
avatarId = user.avatar?.contentId,
|
||||
managedBySso = user.oidcProviderId != null,
|
||||
roles = user.roles
|
||||
)
|
||||
|
||||
@@ -9,5 +9,6 @@ data class UserInfoDto(
|
||||
val emailConfirmed: Boolean,
|
||||
val isEnabled: Boolean,
|
||||
val hasAvatar: Boolean,
|
||||
val avatarId: String? = null,
|
||||
var roles: Set<Role>
|
||||
)
|
||||
@@ -1,23 +0,0 @@
|
||||
package de.grimsi.gameyfin.users.entities
|
||||
|
||||
import jakarta.annotation.Nullable
|
||||
import jakarta.persistence.Embeddable
|
||||
import org.springframework.content.commons.annotations.ContentId
|
||||
import org.springframework.content.commons.annotations.ContentLength
|
||||
import org.springframework.content.commons.annotations.MimeType
|
||||
|
||||
|
||||
@Embeddable
|
||||
class Avatar(
|
||||
@ContentId
|
||||
@Nullable
|
||||
var contentId: String? = null,
|
||||
|
||||
@ContentLength
|
||||
@Nullable
|
||||
var contentLength: Long? = null,
|
||||
|
||||
@MimeType
|
||||
@Nullable
|
||||
var mimeType: String? = null
|
||||
)
|
||||
@@ -2,6 +2,7 @@ package de.grimsi.gameyfin.users.entities
|
||||
|
||||
import de.grimsi.gameyfin.core.Role
|
||||
import de.grimsi.gameyfin.core.security.EncryptionConverter
|
||||
import de.grimsi.gameyfin.games.entities.Image
|
||||
import jakarta.annotation.Nullable
|
||||
import jakarta.persistence.*
|
||||
import jakarta.validation.constraints.NotNull
|
||||
@@ -32,9 +33,8 @@ class User(
|
||||
|
||||
var enabled: Boolean = false,
|
||||
|
||||
@Embedded
|
||||
@Nullable
|
||||
var avatar: Avatar? = null,
|
||||
@OneToOne(cascade = [CascadeType.ALL])
|
||||
var avatar: Image? = null,
|
||||
|
||||
@ElementCollection(targetClass = Role::class, fetch = FetchType.EAGER)
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package de.grimsi.gameyfin.users.persistence
|
||||
|
||||
import de.grimsi.gameyfin.users.entities.Avatar
|
||||
import org.springframework.content.commons.store.ContentStore
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface AvatarContentStore : ContentStore<Avatar, String>
|
||||
Reference in New Issue
Block a user