test #341
|
@ -2,11 +2,14 @@ package kr.co.vividnext.sodalive.admin.chat.original
|
||||||
|
|
||||||
import com.amazonaws.services.s3.model.ObjectMetadata
|
import com.amazonaws.services.s3.model.ObjectMetadata
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterSearchListPageResponse
|
||||||
|
import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterSearchResponse
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkAssignCharactersRequest
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkAssignCharactersRequest
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkPageResponse
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkPageResponse
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkRegisterRequest
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkRegisterRequest
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkResponse
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkResponse
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkUpdateRequest
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkUpdateRequest
|
||||||
|
import kr.co.vividnext.sodalive.admin.chat.original.service.AdminOriginalWorkService
|
||||||
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
@ -34,7 +37,7 @@ import org.springframework.web.multipart.MultipartFile
|
||||||
@RequestMapping("/admin/chat/original")
|
@RequestMapping("/admin/chat/original")
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
class AdminOriginalWorkController(
|
class AdminOriginalWorkController(
|
||||||
private val originalWorkService: kr.co.vividnext.sodalive.admin.chat.original.service.AdminOriginalWorkService,
|
private val originalWorkService: AdminOriginalWorkService,
|
||||||
private val s3Uploader: S3Uploader,
|
private val s3Uploader: S3Uploader,
|
||||||
@Value("\${cloud.aws.s3.bucket}")
|
@Value("\${cloud.aws.s3.bucket}")
|
||||||
private val s3Bucket: String,
|
private val s3Bucket: String,
|
||||||
|
@ -157,6 +160,27 @@ class AdminOriginalWorkController(
|
||||||
ApiResponse.ok(null)
|
ApiResponse.ok(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 관리자용: 지정 원작에 속한 캐릭터 목록 페이징 조회
|
||||||
|
* - 활성 캐릭터만 포함
|
||||||
|
* - 응답 항목: 캐릭터 이미지(URL), 이름
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}/characters")
|
||||||
|
fun listCharactersOfOriginal(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@RequestParam(defaultValue = "0") page: Int,
|
||||||
|
@RequestParam(defaultValue = "20") size: Int
|
||||||
|
) = run {
|
||||||
|
val pageRes = originalWorkService.getCharactersOfOriginalWorkPage(id, page, size)
|
||||||
|
val content = pageRes.content.map { ChatCharacterSearchResponse.from(it, imageHost) }
|
||||||
|
ApiResponse.ok(
|
||||||
|
ChatCharacterSearchListPageResponse(
|
||||||
|
totalCount = pageRes.totalElements,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/** 이미지 업로드 공통 처리 */
|
/** 이미지 업로드 공통 처리 */
|
||||||
private fun uploadImage(originalWorkId: Long, image: MultipartFile): String {
|
private fun uploadImage(originalWorkId: Long, image: MultipartFile): String {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.admin.chat.original.service
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkRegisterRequest
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkRegisterRequest
|
||||||
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkUpdateRequest
|
import kr.co.vividnext.sodalive.admin.chat.original.dto.OriginalWorkUpdateRequest
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.ChatCharacter
|
||||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
||||||
import kr.co.vividnext.sodalive.chat.original.OriginalWork
|
import kr.co.vividnext.sodalive.chat.original.OriginalWork
|
||||||
import kr.co.vividnext.sodalive.chat.original.OriginalWorkRepository
|
import kr.co.vividnext.sodalive.chat.original.OriginalWorkRepository
|
||||||
|
@ -85,10 +86,33 @@ class AdminOriginalWorkService(
|
||||||
/** 원작 페이징 조회 */
|
/** 원작 페이징 조회 */
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun getOriginalWorkPage(page: Int, size: Int): Page<OriginalWork> {
|
fun getOriginalWorkPage(page: Int, size: Int): Page<OriginalWork> {
|
||||||
val pageable = PageRequest.of(page, size, Sort.by("createdAt").descending())
|
val safePage = if (page < 0) 0 else page
|
||||||
|
val safeSize = when {
|
||||||
|
size <= 0 -> 20
|
||||||
|
size > 100 -> 100
|
||||||
|
else -> size
|
||||||
|
}
|
||||||
|
val pageable = PageRequest.of(safePage, safeSize, Sort.by("createdAt").descending())
|
||||||
return originalWorkRepository.findByIsDeletedFalse(pageable)
|
return originalWorkRepository.findByIsDeletedFalse(pageable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 지정 원작에 속한 활성 캐릭터 페이징 조회 (최신순) */
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun getCharactersOfOriginalWorkPage(originalWorkId: Long, page: Int, size: Int): Page<ChatCharacter> {
|
||||||
|
// 원작 존재 및 소프트 삭제 여부 확인
|
||||||
|
originalWorkRepository.findByIdAndIsDeletedFalse(originalWorkId)
|
||||||
|
.orElseThrow { SodaException("해당 원작을 찾을 수 없습니다") }
|
||||||
|
|
||||||
|
val safePage = if (page < 0) 0 else page
|
||||||
|
val safeSize = when {
|
||||||
|
size <= 0 -> 20
|
||||||
|
size > 100 -> 100
|
||||||
|
else -> size
|
||||||
|
}
|
||||||
|
val pageable = PageRequest.of(safePage, safeSize, Sort.by("createdAt").descending())
|
||||||
|
return chatCharacterRepository.findByOriginalWorkIdAndIsActiveTrue(originalWorkId, pageable)
|
||||||
|
}
|
||||||
|
|
||||||
/** 원작 검색 (제목/콘텐츠타입/카테고리, 소프트 삭제 제외) - 무페이징 */
|
/** 원작 검색 (제목/콘텐츠타입/카테고리, 소프트 삭제 제외) - 무페이징 */
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun searchOriginalWorksAll(searchTerm: String): List<OriginalWork> {
|
fun searchOriginalWorksAll(searchTerm: String): List<OriginalWork> {
|
||||||
|
|
|
@ -13,6 +13,7 @@ interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> {
|
||||||
fun findByName(name: String): ChatCharacter?
|
fun findByName(name: String): ChatCharacter?
|
||||||
fun findByIsActiveTrue(pageable: Pageable): Page<ChatCharacter>
|
fun findByIsActiveTrue(pageable: Pageable): Page<ChatCharacter>
|
||||||
fun findByOriginalWorkIdAndIsActiveTrueOrderByCreatedAtDesc(originalWorkId: Long): List<ChatCharacter>
|
fun findByOriginalWorkIdAndIsActiveTrueOrderByCreatedAtDesc(originalWorkId: Long): List<ChatCharacter>
|
||||||
|
fun findByOriginalWorkIdAndIsActiveTrue(originalWorkId: Long, pageable: Pageable): Page<ChatCharacter>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2주 이내(파라미터 since 이상) 활성 캐릭터 페이징 조회
|
* 2주 이내(파라미터 since 이상) 활성 캐릭터 페이징 조회
|
||||||
|
|
Loading…
Reference in New Issue