test #341

Merged
klaus merged 6 commits from test into main 2025-09-14 20:33:51 +00:00
6 changed files with 93 additions and 7 deletions
Showing only changes of commit b6c96af8a2 - Show all commits

View File

@ -70,6 +70,19 @@ class AdminChatCharacterController(
ApiResponse.ok(response) ApiResponse.ok(response)
} }
/**
* 캐릭터 검색(관리자)
* - 이름/설명/MBTI/태그 기준 부분 검색, 활성 캐릭터만 대상
* - 페이징 제거: 전체 목록 반환
*/
@GetMapping("/search")
fun searchCharacters(
@RequestParam("searchTerm") searchTerm: String
) = run {
val list = adminService.searchCharactersAll(searchTerm, imageHost)
ApiResponse.ok(list)
}
/** /**
* 캐릭터 상세 정보 조회 API * 캐릭터 상세 정보 조회 API
* *

View File

@ -65,12 +65,7 @@ class AdminChatCharacterService(
} }
/** /**
* 캐릭터 검색 (이름, 설명, MBTI, 태그 기반) * 캐릭터 검색 (이름, 설명, MBTI, 태그 기반) - 페이징 (기존 사용처 호환용)
*
* @param searchTerm 검색어
* @param pageable 페이징 정보
* @param imageHost 이미지 호스트 URL
* @return 검색된 캐릭터 목록 (페이징)
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
fun searchCharacters( fun searchCharacters(
@ -81,4 +76,20 @@ class AdminChatCharacterService(
val characters = chatCharacterRepository.searchCharacters(searchTerm, pageable) val characters = chatCharacterRepository.searchCharacters(searchTerm, pageable)
return characters.map { ChatCharacterSearchResponse.from(it, imageHost) } return characters.map { ChatCharacterSearchResponse.from(it, imageHost) }
} }
/**
* 캐릭터 검색 (이름, 설명, MBTI, 태그 기반) - 무페이징
*
* @param searchTerm 검색어
* @param imageHost 이미지 호스트 URL
* @return 검색된 캐릭터 목록 (전체)
*/
@Transactional(readOnly = true)
fun searchCharactersAll(
searchTerm: String,
imageHost: String = ""
): List<ChatCharacterSearchResponse> {
val characters = chatCharacterRepository.searchCharactersNoPaging(searchTerm)
return characters.map { ChatCharacterSearchResponse.from(it, imageHost) }
}
} }

View File

@ -109,6 +109,20 @@ class AdminOriginalWorkController(
ApiResponse.ok(OriginalWorkPageResponse(totalCount = pageRes.totalElements, content = content)) ApiResponse.ok(OriginalWorkPageResponse(totalCount = pageRes.totalElements, content = content))
} }
/**
* 원작 검색(관리자)
* - 제목/콘텐츠타입/카테고리 기준 부분 검색, 소프트 삭제 제외
* - 페이징 제거: 전체 목록 반환
*/
@GetMapping("/search")
fun search(
@RequestParam("searchTerm") searchTerm: String
) = run {
val list = originalWorkService.searchOriginalWorksAll(searchTerm)
val content = list.map { OriginalWorkResponse.from(it, imageHost) }
ApiResponse.ok(content)
}
/** /**
* 원작 상세 * 원작 상세
*/ */

View File

@ -89,6 +89,12 @@ class AdminOriginalWorkService(
return originalWorkRepository.findByIsDeletedFalse(pageable) return originalWorkRepository.findByIsDeletedFalse(pageable)
} }
/** 원작 검색 (제목/콘텐츠타입/카테고리, 소프트 삭제 제외) - 무페이징 */
@Transactional(readOnly = true)
fun searchOriginalWorksAll(searchTerm: String): List<OriginalWork> {
return originalWorkRepository.searchNoPaging(searchTerm)
}
/** 원작에 기존 캐릭터들을 배정 */ /** 원작에 기존 캐릭터들을 배정 */
@Transactional @Transactional
fun assignCharacters(originalWorkId: Long, characterIds: List<Long>) { fun assignCharacters(originalWorkId: Long, characterIds: List<Long>) {

View File

@ -31,7 +31,7 @@ interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> {
fun countByIsActiveTrueAndCreatedAtGreaterThanEqual(since: java.time.LocalDateTime): Long fun countByIsActiveTrueAndCreatedAtGreaterThanEqual(since: java.time.LocalDateTime): Long
/** /**
* 이름, 설명, MBTI, 태그로 캐릭터 검색 * 이름, 설명, MBTI, 태그로 캐릭터 검색 - 페이징
*/ */
@Query( @Query(
""" """
@ -52,6 +52,28 @@ interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> {
pageable: Pageable pageable: Pageable
): Page<ChatCharacter> ): Page<ChatCharacter>
/**
* 이름, 설명, MBTI, 태그로 캐릭터 검색 - 무페이징 전체 목록
*/
@Query(
"""
SELECT DISTINCT c FROM ChatCharacter c
LEFT JOIN c.tagMappings tm
LEFT JOIN tm.tag t
WHERE c.isActive = true AND
(
LOWER(c.name) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
LOWER(c.description) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
(c.mbti IS NOT NULL AND LOWER(c.mbti) LIKE LOWER(CONCAT('%', :searchTerm, '%'))) OR
(t.tag IS NOT NULL AND LOWER(t.tag) LIKE LOWER(CONCAT('%', :searchTerm, '%')))
)
ORDER BY c.createdAt DESC
"""
)
fun searchCharactersNoPaging(
@Param("searchTerm") searchTerm: String
): List<ChatCharacter>
/** /**
* 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외)
*/ */

View File

@ -3,6 +3,8 @@ package kr.co.vividnext.sodalive.chat.original
import org.springframework.data.domain.Page import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import java.util.Optional import java.util.Optional
@ -11,4 +13,22 @@ interface OriginalWorkRepository : JpaRepository<OriginalWork, Long> {
fun findByTitleAndIsDeletedFalse(title: String): OriginalWork? fun findByTitleAndIsDeletedFalse(title: String): OriginalWork?
fun findByIdAndIsDeletedFalse(id: Long): Optional<OriginalWork> fun findByIdAndIsDeletedFalse(id: Long): Optional<OriginalWork>
fun findByIsDeletedFalse(pageable: Pageable): Page<OriginalWork> fun findByIsDeletedFalse(pageable: Pageable): Page<OriginalWork>
/**
* 제목/콘텐츠타입/카테고리 기준 부분 검색 (소프트 삭제 제외) - 무페이징 전체 목록
*/
@Query(
"""
SELECT ow FROM OriginalWork ow
WHERE ow.isDeleted = false AND (
LOWER(ow.title) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
LOWER(ow.contentType) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR
LOWER(ow.category) LIKE LOWER(CONCAT('%', :searchTerm, '%'))
)
ORDER BY ow.createdAt DESC
"""
)
fun searchNoPaging(
@Param("searchTerm") searchTerm: String
): List<OriginalWork>
} }