diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt index d6edb2219..5707c5b87 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt @@ -3,6 +3,7 @@ package com.few.api.repo.dao.article import com.few.api.repo.config.LocalCacheConfig.Companion.LOCAL_CM import com.few.api.repo.config.LocalCacheConfig.Companion.SELECT_ARTICLE_RECORD_CACHE import com.few.api.repo.dao.article.command.InsertFullArticleRecordCommand +import com.few.api.repo.dao.article.query.SelectArticleIdByWorkbookIdAndDayQuery import com.few.api.repo.dao.article.query.SelectArticleRecordQuery import com.few.api.repo.dao.article.query.SelectWorkBookArticleRecordQuery import com.few.api.repo.dao.article.query.SelectWorkbookMappedArticleRecordsQuery @@ -100,6 +101,13 @@ class ArticleDao( return mstId.getValue(ArticleMst.ARTICLE_MST.ID) } + fun insertArticleMstCommand(command: InsertFullArticleRecordCommand) = + dslContext.insertInto(ArticleMst.ARTICLE_MST) + .set(ArticleMst.ARTICLE_MST.MEMBER_ID, command.writerId) + .set(ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL, command.mainImageURL.toString()) + .set(ArticleMst.ARTICLE_MST.TITLE, command.title) + .set(ArticleMst.ARTICLE_MST.CATEGORY_CD, command.category) + fun insertArticleIfoCommand( mstId: Long, command: InsertFullArticleRecordCommand, @@ -107,12 +115,18 @@ class ArticleDao( .set(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID, mstId) .set(ArticleIfo.ARTICLE_IFO.CONTENT, command.content) - fun insertArticleMstCommand(command: InsertFullArticleRecordCommand) = - dslContext.insertInto(ArticleMst.ARTICLE_MST) - .set(ArticleMst.ARTICLE_MST.MEMBER_ID, command.writerId) - .set(ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL, command.mainImageURL.toString()) - .set(ArticleMst.ARTICLE_MST.TITLE, command.title) - .set(ArticleMst.ARTICLE_MST.CATEGORY_CD, command.category) + fun selectArticleIdByWorkbookIdAndDay(query: SelectArticleIdByWorkbookIdAndDayQuery): Long? { + return selectArticleIdByWorkbookIdAndDayQuery(query) + .fetchOneInto(Long::class.java) + } + + fun selectArticleIdByWorkbookIdAndDayQuery(query: SelectArticleIdByWorkbookIdAndDayQuery) = + dslContext.select( + MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID + ).from(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .where(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(query.workbookId)) + .and(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.DAY_COL.eq(query.day)) + .query fun selectArticleContents(articleIds: Set): List = selectArticleContentsQuery(articleIds) diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/query/SelectArticleIdByWorkbookIdAndDayQuery.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/query/SelectArticleIdByWorkbookIdAndDayQuery.kt new file mode 100644 index 000000000..c98869346 --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/query/SelectArticleIdByWorkbookIdAndDayQuery.kt @@ -0,0 +1,6 @@ +package com.few.api.repo.dao.article.query + +data class SelectArticleIdByWorkbookIdAndDayQuery( + val workbookId: Long, + val day: Int, +) \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt index b8e6eaebc..636dea158 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt @@ -3,13 +3,18 @@ package com.few.api.repo.dao.subscription import com.few.api.repo.dao.subscription.command.InsertWorkbookSubscriptionCommand import com.few.api.repo.dao.subscription.command.UpdateDeletedAtInAllSubscriptionCommand import com.few.api.repo.dao.subscription.command.UpdateDeletedAtInWorkbookSubscriptionCommand +import com.few.api.repo.dao.subscription.query.CountAllWorkbooksSubscription import com.few.api.repo.dao.subscription.query.SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery import com.few.api.repo.dao.subscription.record.WorkbookSubscriptionStatus import com.few.api.repo.dao.subscription.query.CountWorkbookMappedArticlesQuery +import com.few.api.repo.dao.subscription.query.SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery import com.few.api.repo.dao.subscription.record.CountAllSubscriptionStatusRecord +import com.few.api.repo.dao.subscription.record.MemberWorkbookSubscriptionStatusRecord import jooq.jooq_dsl.Tables.MAPPING_WORKBOOK_ARTICLE import jooq.jooq_dsl.Tables.SUBSCRIPTION +import jooq.jooq_dsl.tables.MappingWorkbookArticle import org.jooq.DSLContext +import org.jooq.impl.DSL import org.springframework.stereotype.Repository import java.time.LocalDateTime @@ -64,6 +69,26 @@ class SubscriptionDao( .orderBy(SUBSCRIPTION.CREATED_AT.desc()) .limit(1) + fun selectAllWorkbookSubscriptionStatus(query: SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery): List { + return selectAllWorkbookSubscriptionStatusQuery(query) + .fetchInto(MemberWorkbookSubscriptionStatusRecord::class.java) + } + + fun selectAllWorkbookSubscriptionStatusQuery(query: SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery) = + dslContext.select( + SUBSCRIPTION.TARGET_WORKBOOK_ID.`as`(MemberWorkbookSubscriptionStatusRecord::workbookId.name), + SUBSCRIPTION.DELETED_AT.isNull.`as`(MemberWorkbookSubscriptionStatusRecord::isActiveSub.name), + DSL.max(SUBSCRIPTION.PROGRESS).add(1).`as`(MemberWorkbookSubscriptionStatusRecord::currentDay.name), + DSL.max(MAPPING_WORKBOOK_ARTICLE.DAY_COL).`as`(MemberWorkbookSubscriptionStatusRecord::totalDay.name) + ) + .from(SUBSCRIPTION) + .leftJoin(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .on(SUBSCRIPTION.TARGET_WORKBOOK_ID.eq(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID)) + .where(SUBSCRIPTION.MEMBER_ID.eq(query.memberId)) + .and(SUBSCRIPTION.TARGET_MEMBER_ID.isNull) + .groupBy(SUBSCRIPTION.TARGET_WORKBOOK_ID, SUBSCRIPTION.DELETED_AT) + .query + fun updateDeletedAtInAllSubscription(command: UpdateDeletedAtInAllSubscriptionCommand) { updateDeletedAtInAllSubscriptionCommand(command) .execute() @@ -95,4 +120,22 @@ class SubscriptionDao( .fetchOne(0, Int::class.java)!! return CountAllSubscriptionStatusRecord(total.toLong(), active.toLong()) } + + /** + * key: workbookId + * value: workbook 구독 전체 기록 수 + */ + fun countAllWorkbookSubscription(query: CountAllWorkbooksSubscription): Map { + return countAllWorkbookSubscriptionQuery() + .fetch() + .intoMap(SUBSCRIPTION.TARGET_WORKBOOK_ID, DSL.count(SUBSCRIPTION.TARGET_WORKBOOK_ID)) + } + + fun countAllWorkbookSubscriptionQuery() = dslContext.select( + SUBSCRIPTION.TARGET_WORKBOOK_ID, + DSL.count(SUBSCRIPTION.TARGET_WORKBOOK_ID) + ) + .from(SUBSCRIPTION) + .groupBy(SUBSCRIPTION.TARGET_WORKBOOK_ID) + .query } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/CountAllWorkbooksSubscription.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/CountAllWorkbooksSubscription.kt new file mode 100644 index 000000000..1dcfa7751 --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/CountAllWorkbooksSubscription.kt @@ -0,0 +1,5 @@ +package com.few.api.repo.dao.subscription.query + +data class CountAllWorkbooksSubscription( + val workbookIds: List, +) \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery.kt new file mode 100644 index 000000000..063f23d69 --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/query/SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery.kt @@ -0,0 +1,8 @@ +package com.few.api.repo.dao.subscription.query + +/** + * DeleteAt을 고려하지 않고 멤버의 모든 워크북 구독 상태를 조회하는 쿼리 + */ +data class SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery( + val memberId: Long, +) \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/record/MemberWorkbookSubscriptionStatusRecord.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/record/MemberWorkbookSubscriptionStatusRecord.kt new file mode 100644 index 000000000..0bddbd397 --- /dev/null +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/record/MemberWorkbookSubscriptionStatusRecord.kt @@ -0,0 +1,8 @@ +package com.few.api.repo.dao.subscription.record + +data class MemberWorkbookSubscriptionStatusRecord( + val workbookId: Long, + val isActiveSub: Boolean, + val currentDay: Int, + val totalDay: Int, +) \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt index b1818b3d7..6b52e402e 100644 --- a/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt @@ -2,6 +2,7 @@ package com.few.api.repo.explain.article import com.few.api.repo.dao.article.ArticleDao import com.few.api.repo.dao.article.command.InsertFullArticleRecordCommand +import com.few.api.repo.dao.article.query.SelectArticleIdByWorkbookIdAndDayQuery import com.few.api.repo.dao.article.query.SelectArticleRecordQuery import com.few.api.repo.dao.article.query.SelectWorkBookArticleRecordQuery import com.few.api.repo.dao.article.query.SelectWorkbookMappedArticleRecordsQuery @@ -122,4 +123,15 @@ class ArticleDaoExplainGenerateTest : JooqTestSpec() { ResultGenerator.execute(command, explain, "insertArticleIfoCommandExplain") } + + @Test + fun selectArticleIdByWorkbookIdAndDayQueryExplain() { + val query = SelectArticleIdByWorkbookIdAndDayQuery(1L, 1).let { + articleDao.selectArticleIdByWorkbookIdAndDayQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectArticleIdByWorkbookIdAndDayQueryExplain") + } } \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt index 8ddd24902..76dd2a8df 100644 --- a/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt @@ -5,6 +5,7 @@ import com.few.api.repo.dao.subscription.command.InsertWorkbookSubscriptionComma import com.few.api.repo.dao.subscription.command.UpdateDeletedAtInAllSubscriptionCommand import com.few.api.repo.dao.subscription.query.CountWorkbookMappedArticlesQuery import com.few.api.repo.dao.subscription.query.SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery +import com.few.api.repo.dao.subscription.query.SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery import com.few.api.repo.explain.InsertUpdateExplainGenerator import com.few.api.repo.explain.ResultGenerator import com.few.api.repo.jooq.JooqTestSpec @@ -59,6 +60,17 @@ class SubscriptionDaoExplainGenerateTest : JooqTestSpec() { ResultGenerator.execute(query, explain, "selectTopWorkbookSubscriptionStatusQueryExplain") } + @Test + fun selectAllTopWorkbookSubscriptionStatusQueryExplain() { + val query = SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery(memberId = 1L).let { + subscriptionDao.selectAllWorkbookSubscriptionStatusQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectAllTopWorkbookSubscriptionStatusQueryExplain") + } + @Test fun countWorkbookMappedArticlesQueryExplain() { val query = CountWorkbookMappedArticlesQuery( @@ -99,4 +111,13 @@ class SubscriptionDaoExplainGenerateTest : JooqTestSpec() { ResultGenerator.execute(command, explain, "updateDeletedAtInAllSubscriptionCommandExplain") } + + @Test + fun countAllWorkbookSubscriptionQueryExplain() { + val query = subscriptionDao.countAllWorkbookSubscriptionQuery() + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "countAllWorkbookSubscriptionQueryExplain") + } } \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/domain/subscription/service/SubscriptionArticleService.kt b/api/src/main/kotlin/com/few/api/domain/subscription/service/SubscriptionArticleService.kt new file mode 100644 index 000000000..ba1111c44 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/domain/subscription/service/SubscriptionArticleService.kt @@ -0,0 +1,17 @@ +package com.few.api.domain.subscription.service + +import com.few.api.domain.subscription.service.dto.ReadArticleIdByWorkbookIdAndDayDto +import com.few.api.repo.dao.article.ArticleDao +import com.few.api.repo.dao.article.query.SelectArticleIdByWorkbookIdAndDayQuery +import org.springframework.stereotype.Service + +@Service +class SubscriptionArticleService( + private val articleDao: ArticleDao, +) { + fun readArticleIdByWorkbookIdAndDay(dto: ReadArticleIdByWorkbookIdAndDayDto): Long? { + SelectArticleIdByWorkbookIdAndDayQuery(dto.workbookId, dto.day).let { query -> + return articleDao.selectArticleIdByWorkbookIdAndDay(query) + } + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/domain/subscription/service/dto/ReadArticleIdByWorkbookIdAndDayDto.kt b/api/src/main/kotlin/com/few/api/domain/subscription/service/dto/ReadArticleIdByWorkbookIdAndDayDto.kt new file mode 100644 index 000000000..587516064 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/domain/subscription/service/dto/ReadArticleIdByWorkbookIdAndDayDto.kt @@ -0,0 +1,6 @@ +package com.few.api.domain.subscription.service.dto + +data class ReadArticleIdByWorkbookIdAndDayDto( + val workbookId: Long, + val day: Int, +) \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCase.kt b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCase.kt new file mode 100644 index 000000000..a9c203433 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCase.kt @@ -0,0 +1,73 @@ +package com.few.api.domain.subscription.usecase + +import com.fasterxml.jackson.databind.ObjectMapper +import com.few.api.domain.subscription.service.SubscriptionArticleService +import com.few.api.domain.subscription.service.dto.ReadArticleIdByWorkbookIdAndDayDto +import com.few.api.domain.subscription.usecase.dto.BrowseSubscribeWorkbooksUseCaseIn +import com.few.api.domain.subscription.usecase.dto.BrowseSubscribeWorkbooksUseCaseOut +import com.few.api.domain.subscription.usecase.dto.SubscribeWorkbookDetail +import com.few.api.repo.dao.subscription.SubscriptionDao +import com.few.api.repo.dao.subscription.query.CountAllWorkbooksSubscription +import com.few.api.repo.dao.subscription.query.SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery +import com.few.api.web.support.WorkBookStatus +import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional + +@Component +class BrowseSubscribeWorkbooksUseCase( + private val subscriptionDao: SubscriptionDao, + private val subscriptionArticleService: SubscriptionArticleService, + private val objectMapper: ObjectMapper, +) { + @Transactional + fun execute(useCaseIn: BrowseSubscribeWorkbooksUseCaseIn): BrowseSubscribeWorkbooksUseCaseOut { + val subscriptionRecords = + SelectAllMemberWorkbookSubscriptionStatusNotConsiderDeletedAtQuery(useCaseIn.memberId).let { + subscriptionDao.selectAllWorkbookSubscriptionStatus(it) + } + + /** + * key: workbookId + * value: workbook의 currentDay에 해당하는 articleId + */ + val workbookSubscriptionCurrentArticleIdRecords = subscriptionRecords.associate { it -> + val articleId = ReadArticleIdByWorkbookIdAndDayDto(it.workbookId, it.currentDay).let { + subscriptionArticleService.readArticleIdByWorkbookIdAndDay(it) + } ?: throw IllegalArgumentException("articleId is null") + it.workbookId to articleId + } + + val subscriptionWorkbookIds = subscriptionRecords.map { it.workbookId } + val workbookSubscriptionCountRecords = + CountAllWorkbooksSubscription(subscriptionWorkbookIds).let { + subscriptionDao.countAllWorkbookSubscription(it) + } + + subscriptionRecords.map { + /** + * 임시 코드 + * Batch 코드에서 currentDay가 totalDay보다 큰 경우가 발생하여 + * currentDay가 totalDay보다 크면 totalDay로 변경 + * */ + var currentDay = it.currentDay + if (it.currentDay > it.totalDay) { + currentDay = it.totalDay + } + + SubscribeWorkbookDetail( + workbookId = it.workbookId, + isActiveSub = WorkBookStatus.fromStatus(it.isActiveSub), + currentDay = currentDay, + totalDay = it.totalDay, + totalSubscriber = workbookSubscriptionCountRecords[it.workbookId]?.toLong() ?: 0, + articleInfo = objectMapper.writeValueAsString( + mapOf( + "articleId" to workbookSubscriptionCurrentArticleIdRecords[it.workbookId] + ) + ) + ) + }.let { + return BrowseSubscribeWorkbooksUseCaseOut(it) + } + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseIn.kt b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseIn.kt new file mode 100644 index 000000000..7fb389b90 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseIn.kt @@ -0,0 +1,5 @@ +package com.few.api.domain.subscription.usecase.dto + +data class BrowseSubscribeWorkbooksUseCaseIn( + val memberId: Long, +) \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseOut.kt b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseOut.kt new file mode 100644 index 000000000..5ec182507 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/domain/subscription/usecase/dto/BrowseSubscribeWorkbooksUseCaseOut.kt @@ -0,0 +1,17 @@ +package com.few.api.domain.subscription.usecase.dto + +import com.few.api.web.support.WorkBookStatus + +data class BrowseSubscribeWorkbooksUseCaseOut( + val workbooks: List, +) + +data class SubscribeWorkbookDetail( + val workbookId: Long, + val isActiveSub: WorkBookStatus, + val currentDay: Int, + val totalDay: Int, + val rank: Long = 0, + val totalSubscriber: Long, + val articleInfo: String = "{}", +) \ No newline at end of file diff --git a/api/src/main/kotlin/com/few/api/web/controller/subscription/SubscriptionController.kt b/api/src/main/kotlin/com/few/api/web/controller/subscription/SubscriptionController.kt index 5f7459427..54933314e 100644 --- a/api/src/main/kotlin/com/few/api/web/controller/subscription/SubscriptionController.kt +++ b/api/src/main/kotlin/com/few/api/web/controller/subscription/SubscriptionController.kt @@ -1,5 +1,6 @@ package com.few.api.web.controller.subscription +import com.few.api.domain.subscription.usecase.BrowseSubscribeWorkbooksUseCase import com.few.api.web.controller.subscription.request.SubscribeWorkbookRequest import com.few.api.web.controller.subscription.request.UnsubscribeWorkbookRequest import com.few.api.web.support.ApiResponse @@ -7,6 +8,7 @@ import com.few.api.web.support.ApiResponseGenerator import com.few.api.domain.subscription.usecase.SubscribeWorkbookUseCase import com.few.api.domain.subscription.usecase.UnsubscribeAllUseCase import com.few.api.domain.subscription.usecase.UnsubscribeWorkbookUseCase +import com.few.api.domain.subscription.usecase.dto.BrowseSubscribeWorkbooksUseCaseIn import com.few.api.domain.subscription.usecase.dto.SubscribeWorkbookUseCaseIn import com.few.api.domain.subscription.usecase.dto.UnsubscribeAllUseCaseIn import com.few.api.domain.subscription.usecase.dto.UnsubscribeWorkbookUseCaseIn @@ -28,6 +30,7 @@ class SubscriptionController( private val subscribeWorkbookUseCase: SubscribeWorkbookUseCase, private val unsubscribeWorkbookUseCase: UnsubscribeWorkbookUseCase, private val unsubscribeAllUseCase: UnsubscribeAllUseCase, + private val browseSubscribeWorkbooksUseCase: BrowseSubscribeWorkbooksUseCase, ) { // todo add auth @@ -38,29 +41,26 @@ class SubscriptionController( required = false ) view: ViewCategory? = ViewCategory.MAIN_CARD, ): ApiResponse> { - SubscribeWorkbooksResponse( - listOf( - SubscribeWorkbookInfo( - id = 1, - status = "ACTIVE", - totalDay = 10, - currentDay = 1, - rank = 0, - totalSubscriber = 100, - articleInfo = "{}" - ), + // todo fix memberId + val memberId = 1L + val useCaseOut = BrowseSubscribeWorkbooksUseCaseIn(memberId).let { + browseSubscribeWorkbooksUseCase.execute(it) + } + + return SubscribeWorkbooksResponse( + workbooks = useCaseOut.workbooks.map { SubscribeWorkbookInfo( - id = 2, - status = "DONE", - totalDay = 10, - currentDay = 10, - rank = 22, - totalSubscriber = 100, - articleInfo = "{}" + id = it.workbookId, + currentDay = it.currentDay, + totalDay = it.totalDay, + status = it.isActiveSub.name, + rank = it.rank, + totalSubscriber = it.totalSubscriber, + articleInfo = it.articleInfo ) - ) + } ).let { - return ApiResponseGenerator.success(it, HttpStatus.OK) + ApiResponseGenerator.success(it, HttpStatus.OK) } } diff --git a/api/src/main/kotlin/com/few/api/web/support/WorkBookStatus.kt b/api/src/main/kotlin/com/few/api/web/support/WorkBookStatus.kt new file mode 100644 index 000000000..1aac91f42 --- /dev/null +++ b/api/src/main/kotlin/com/few/api/web/support/WorkBookStatus.kt @@ -0,0 +1,16 @@ +package com.few.api.web.support + +enum class WorkBookStatus { + ACTIVE, + DONE, + ; + + companion object { + /** + * status ture -> ACTIVE, false -> DONE + */ + fun fromStatus(status: Boolean): WorkBookStatus { + return if (status) ACTIVE else DONE + } + } +} \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCaseTest.kt b/api/src/test/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCaseTest.kt new file mode 100644 index 000000000..177365ecc --- /dev/null +++ b/api/src/test/kotlin/com/few/api/domain/subscription/usecase/BrowseSubscribeWorkbooksUseCaseTest.kt @@ -0,0 +1,67 @@ +package com.few.api.domain.subscription.usecase + +import com.fasterxml.jackson.databind.ObjectMapper +import com.few.api.domain.subscription.service.SubscriptionArticleService +import com.few.api.domain.subscription.usecase.dto.BrowseSubscribeWorkbooksUseCaseIn +import com.few.api.repo.dao.subscription.SubscriptionDao +import com.few.api.repo.dao.subscription.record.MemberWorkbookSubscriptionStatusRecord +import io.github.oshai.kotlinlogging.KotlinLogging +import io.kotest.core.spec.style.BehaviorSpec +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class BrowseSubscribeWorkbooksUseCaseTest : BehaviorSpec({ + val log = KotlinLogging.logger {} + + lateinit var subscriptionDao: SubscriptionDao + lateinit var subscriptionArticleService: SubscriptionArticleService + lateinit var objectMapper: ObjectMapper + lateinit var useCase: BrowseSubscribeWorkbooksUseCase + + beforeContainer { + subscriptionDao = mockk() + subscriptionArticleService = mockk() + objectMapper = mockk() + useCase = BrowseSubscribeWorkbooksUseCase(subscriptionDao, subscriptionArticleService, objectMapper) + } + + given("사용자 구독 정보 조회 요청이 온 상황에서") { + `when`("사용자의 구독 정보가 있는 경우") { + every { subscriptionDao.selectAllWorkbookSubscriptionStatus(any()) } returns listOf( + MemberWorkbookSubscriptionStatusRecord( + workbookId = 1L, + isActiveSub = true, + currentDay = 1, + totalDay = 3 + ), + MemberWorkbookSubscriptionStatusRecord( + workbookId = 2L, + isActiveSub = true, + currentDay = 2, + totalDay = 3 + ) + ) + + every { + subscriptionArticleService.readArticleIdByWorkbookIdAndDay(any()) + } returns 1L andThen 2L + + every { subscriptionDao.countAllWorkbookSubscription(any()) } returns mapOf( + 1L to 1, + 2L to 2 + ) + + every { objectMapper.writeValueAsString(any()) } returns "{\"articleId\":1}" andThen "{\"articleId\":2}" + + then("사용자의 구독 정보를 조회한다") { + val useCaseIn = BrowseSubscribeWorkbooksUseCaseIn(memberId = 1L) + useCase.execute(useCaseIn) + + verify(exactly = 1) { subscriptionDao.selectAllWorkbookSubscriptionStatus(any()) } + verify(exactly = 1) { subscriptionDao.countAllWorkbookSubscription(any()) } + verify(exactly = 2) { objectMapper.writeValueAsString(any()) } + } + } + } +}) \ No newline at end of file diff --git a/api/src/test/kotlin/com/few/api/web/controller/subscription/SubscriptionControllerTest.kt b/api/src/test/kotlin/com/few/api/web/controller/subscription/SubscriptionControllerTest.kt index 0fb50a4df..4cda425f5 100644 --- a/api/src/test/kotlin/com/few/api/web/controller/subscription/SubscriptionControllerTest.kt +++ b/api/src/test/kotlin/com/few/api/web/controller/subscription/SubscriptionControllerTest.kt @@ -5,6 +5,7 @@ import com.epages.restdocs.apispec.ResourceDocumentation.parameterWithName import com.epages.restdocs.apispec.ResourceSnippetParameters import com.epages.restdocs.apispec.Schema import com.fasterxml.jackson.databind.ObjectMapper +import com.few.api.domain.subscription.usecase.BrowseSubscribeWorkbooksUseCase import com.few.api.web.controller.ControllerTestSpec import com.few.api.web.controller.description.Description import com.few.api.web.controller.subscription.request.SubscribeWorkbookRequest @@ -12,15 +13,15 @@ import com.few.api.web.controller.subscription.request.UnsubscribeWorkbookReques import com.few.api.domain.subscription.usecase.SubscribeWorkbookUseCase import com.few.api.domain.subscription.usecase.UnsubscribeAllUseCase import com.few.api.domain.subscription.usecase.UnsubscribeWorkbookUseCase -import com.few.api.domain.subscription.usecase.dto.SubscribeWorkbookUseCaseIn -import com.few.api.domain.subscription.usecase.dto.UnsubscribeAllUseCaseIn -import com.few.api.domain.subscription.usecase.dto.UnsubscribeWorkbookUseCaseIn +import com.few.api.domain.subscription.usecase.dto.* import com.few.api.web.controller.helper.* import com.few.api.web.support.ViewCategory +import com.few.api.web.support.WorkBookStatus import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.Mockito.doNothing +import org.mockito.Mockito.doReturn import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType @@ -51,6 +52,9 @@ class SubscriptionControllerTest : ControllerTestSpec() { @MockBean private lateinit var unsubscribeAllUseCase: UnsubscribeAllUseCase + @MockBean + private lateinit var browseSubscribeWorkbooksUseCase: BrowseSubscribeWorkbooksUseCase + companion object { private val BASE_URL = "/api/v1/" private val TAG = "WorkbookSubscriptionController" @@ -81,6 +85,43 @@ class SubscriptionControllerTest : ControllerTestSpec() { .build() .toUriString() + // set usecase mock + val memberId = 1L + val useCaseIn = BrowseSubscribeWorkbooksUseCaseIn(memberId) + val useCaseOut = BrowseSubscribeWorkbooksUseCaseOut( + workbooks = listOf( + SubscribeWorkbookDetail( + workbookId = 1L, + isActiveSub = WorkBookStatus.ACTIVE, + currentDay = 1, + totalDay = 3, + rank = 0, + totalSubscriber = 100, + articleInfo = "{\"articleId\":1}" + ), + SubscribeWorkbookDetail( + workbookId = 2L, + isActiveSub = WorkBookStatus.ACTIVE, + currentDay = 2, + totalDay = 3, + rank = 0, + totalSubscriber = 1, + articleInfo = "{\"articleId\":5}" + ), + SubscribeWorkbookDetail( + workbookId = 3L, + isActiveSub = WorkBookStatus.DONE, + currentDay = 3, + totalDay = 3, + rank = 0, + totalSubscriber = 2, + articleInfo = "{}" + ) + ) + ) + + doReturn(useCaseOut).`when`(browseSubscribeWorkbooksUseCase).execute(useCaseIn) + // when this.webTestClient.get() .uri(uri)