fix(admin-series): 시리즈 수정 API 추가

This commit is contained in:
2025-11-12 14:58:48 +09:00
parent 3ed306ae8c
commit 4f52ec0663
5 changed files with 186 additions and 1 deletions

View File

@@ -4,6 +4,8 @@ import kr.co.vividnext.sodalive.common.ApiResponse
import org.springframework.data.domain.Pageable
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@@ -19,4 +21,9 @@ class AdminContentSeriesController(private val service: AdminContentSeriesServic
fun searchSeriesList(
@RequestParam(value = "search_word") searchWord: String
) = ApiResponse.ok(service.searchSeriesList(searchWord))
@PutMapping
fun modifySeries(
@RequestBody request: AdminModifySeriesRequest
) = ApiResponse.ok(service.modifySeries(request), "시리즈가 수정되었습니다.")
}

View File

@@ -1,10 +1,17 @@
package kr.co.vividnext.sodalive.admin.content.series
import kr.co.vividnext.sodalive.admin.content.series.genre.AdminContentSeriesGenreRepository
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
class AdminContentSeriesService(private val repository: AdminContentSeriesRepository) {
class AdminContentSeriesService(
private val repository: AdminContentSeriesRepository,
private val genreRepository: AdminContentSeriesGenreRepository
) {
fun getSeriesList(pageable: Pageable): GetAdminSeriesListResponse {
val totalCount = repository.getSeriesTotalCount()
val items = repository.getSeriesList(
@@ -18,4 +25,33 @@ class AdminContentSeriesService(private val repository: AdminContentSeriesReposi
fun searchSeriesList(searchWord: String): List<GetAdminSearchSeriesListItem> {
return repository.searchSeriesList(searchWord)
}
@Transactional
fun modifySeries(request: AdminModifySeriesRequest) {
val series = repository.findByIdAndActiveTrue(request.seriesId)
?: throw SodaException("잘못된 요청입니다.")
if (request.publishedDaysOfWeek != null) {
val days = request.publishedDaysOfWeek
if (days.contains(SeriesPublishedDaysOfWeek.RANDOM) && days.size > 1) {
throw SodaException("랜덤과 연재요일 동시에 선택할 수 없습니다.")
}
series.publishedDaysOfWeek.clear()
series.publishedDaysOfWeek.addAll(days)
}
if (request.genreId != null) {
val genre = genreRepository.findActiveSeriesGenreById(request.genreId)
?: throw SodaException("잘못된 요청입니다.")
series.genre = genre
}
if (request.isOriginal != null) {
series.isOriginal = request.isOriginal
}
if (request.isAdult != null) {
series.isAdult = request.isAdult
}
}
}

View File

@@ -0,0 +1,11 @@
package kr.co.vividnext.sodalive.admin.content.series
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
data class AdminModifySeriesRequest(
val seriesId: Long,
val publishedDaysOfWeek: Set<SeriesPublishedDaysOfWeek>?,
val genreId: Long?,
val isOriginal: Boolean?,
val isAdult: Boolean?
)

View File

@@ -8,6 +8,7 @@ interface AdminContentSeriesGenreRepository : JpaRepository<SeriesGenre, Long>,
interface AdminContentSeriesGenreQueryRepository {
fun getSeriesGenreList(): List<GetSeriesGenreListResponse>
fun findActiveSeriesGenreById(id: Long): SeriesGenre?
}
class AdminContentSeriesGenreQueryRepositoryImpl(
@@ -21,4 +22,14 @@ class AdminContentSeriesGenreQueryRepositoryImpl(
.orderBy(seriesGenre.orders.asc())
.fetch()
}
override fun findActiveSeriesGenreById(id: Long): SeriesGenre? {
return queryFactory
.selectFrom(seriesGenre)
.where(
seriesGenre.id.eq(id)
.and(seriesGenre.isActive.isTrue)
)
.fetchFirst()
}
}

View File

@@ -0,0 +1,120 @@
package kr.co.vividnext.sodalive.admin.content.series
import kr.co.vividnext.sodalive.admin.content.series.genre.AdminContentSeriesGenreRepository
import kr.co.vividnext.sodalive.admin.content.series.genre.SeriesGenre
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesState
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.Mockito
class AdminContentSeriesServiceTest {
private lateinit var seriesRepository: AdminContentSeriesRepository
private lateinit var genreRepository: AdminContentSeriesGenreRepository
private lateinit var service: AdminContentSeriesService
@BeforeEach
fun setup() {
seriesRepository = Mockito.mock(AdminContentSeriesRepository::class.java)
genreRepository = Mockito.mock(AdminContentSeriesGenreRepository::class.java)
service = AdminContentSeriesService(seriesRepository, genreRepository)
}
@Test
fun shouldModifySeriesFieldsByAdmin() {
// given
val series = Series(
title = "title",
introduction = "intro",
state = SeriesState.PROCEEDING
)
series.id = 1L
series.genre = SeriesGenre(genre = "Old", isAdult = false)
series.publishedDaysOfWeek.add(SeriesPublishedDaysOfWeek.MON)
series.isAdult = false
series.isOriginal = false
Mockito.`when`(seriesRepository.findByIdAndActiveTrue(1L)).thenReturn(series)
val newGenre = SeriesGenre(genre = "New", isAdult = false)
newGenre.id = 10L
Mockito.`when`(genreRepository.findActiveSeriesGenreById(10L)).thenReturn(newGenre)
val request = AdminModifySeriesRequest(
seriesId = 1L,
publishedDaysOfWeek = setOf(SeriesPublishedDaysOfWeek.WED),
genreId = 10L,
isOriginal = true,
isAdult = true
)
// when
service.modifySeries(request)
// then
assertEquals(setOf(SeriesPublishedDaysOfWeek.WED), series.publishedDaysOfWeek)
assertEquals(newGenre, series.genre)
assertEquals(true, series.isOriginal)
assertEquals(true, series.isAdult)
}
@Test
fun shouldThrowWhenRandomAndOtherDaysSelectedTogether() {
// given
val series = Series(
title = "title",
introduction = "intro",
state = SeriesState.PROCEEDING
)
series.id = 2L
series.genre = SeriesGenre(genre = "Old", isAdult = false)
Mockito.`when`(seriesRepository.findByIdAndActiveTrue(2L)).thenReturn(series)
val request = AdminModifySeriesRequest(
seriesId = 2L,
publishedDaysOfWeek = setOf(SeriesPublishedDaysOfWeek.RANDOM, SeriesPublishedDaysOfWeek.MON),
genreId = null,
isOriginal = null,
isAdult = null
)
// expect
assertThrows(SodaException::class.java) {
service.modifySeries(request)
}
}
@Test
fun shouldThrowWhenGenreNotFound() {
// given
val series = Series(
title = "title",
introduction = "intro",
state = SeriesState.PROCEEDING
)
series.id = 3L
series.genre = SeriesGenre(genre = "Old", isAdult = false)
Mockito.`when`(seriesRepository.findByIdAndActiveTrue(3L)).thenReturn(series)
// genre not found
Mockito.`when`(genreRepository.findActiveSeriesGenreById(999L)).thenReturn(null)
val request = AdminModifySeriesRequest(
seriesId = 3L,
publishedDaysOfWeek = null,
genreId = 999L,
isOriginal = null,
isAdult = null
)
// expect
assertThrows(SodaException::class.java) {
service.modifySeries(request)
}
}
}