From 4f52ec06631710114a5e95b292a6d21019790236 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 12 Nov 2025 14:58:48 +0900 Subject: [PATCH] =?UTF-8?q?fix(admin-series):=20=EC=8B=9C=EB=A6=AC?= =?UTF-8?q?=EC=A6=88=20=EC=88=98=EC=A0=95=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../series/AdminContentSeriesController.kt | 7 + .../series/AdminContentSeriesService.kt | 38 +++++- .../series/AdminModifySeriesRequest.kt | 11 ++ .../AdminContentSeriesGenreRepository.kt | 11 ++ .../series/AdminContentSeriesServiceTest.kt | 120 ++++++++++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminModifySeriesRequest.kt create mode 100644 src/test/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesServiceTest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesController.kt index bc2867c..77f9add 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesController.kt @@ -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), "시리즈가 수정되었습니다.") } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesService.kt index 1a949d2..6b757ec 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesService.kt @@ -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 { 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 + } + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminModifySeriesRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminModifySeriesRequest.kt new file mode 100644 index 0000000..065cc6e --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminModifySeriesRequest.kt @@ -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?, + val genreId: Long?, + val isOriginal: Boolean?, + val isAdult: Boolean? +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/genre/AdminContentSeriesGenreRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/genre/AdminContentSeriesGenreRepository.kt index 3587baa..42140d1 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/genre/AdminContentSeriesGenreRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/series/genre/AdminContentSeriesGenreRepository.kt @@ -8,6 +8,7 @@ interface AdminContentSeriesGenreRepository : JpaRepository, interface AdminContentSeriesGenreQueryRepository { fun getSeriesGenreList(): List + 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() + } } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesServiceTest.kt new file mode 100644 index 0000000..ddf0b09 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/content/series/AdminContentSeriesServiceTest.kt @@ -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) + } + } +}