From 0b8b42b2587a420ee91cb06b0d7dcbcbd8acc8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9D=B8=EC=A4=80?= <54973090+dlswns2480@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:47:39 +0900 Subject: [PATCH] =?UTF-8?q?[feat=20#161]=20=EC=95=88=EC=9D=BD=EC=9D=8C,=20?= =?UTF-8?q?=EC=A6=90=EA=B2=A8=EC=B0=BE=EA=B8=B0=20=EA=B0=9C=EC=88=98=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : 안읽음, 즐겨찾기 개수 조회 dto * feat : 안읽음, 즐겨찾기 개수 조회 api * feat : 안읽음, 즐겨찾기 개수 조회 유스케이스 구현 * feat : 안읽음, 즐겨찾기 개수 조회 포트 구현 --- .../com/pokit/content/RemindController.kt | 21 ++++++++++++ .../dto/response/RemindContentResponse.kt | 8 +++++ .../bookmark/persist/BookMarkRepository.kt | 2 ++ .../content/impl/ContentCountAdapter.kt | 32 +++++++++++++++++++ .../pokit/content/port/in/ContentUseCase.kt | 4 +++ .../content/port/out/ContentCountPort.kt | 7 ++++ .../content/port/service/ContentService.kt | 10 +++++- 7 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/content/impl/ContentCountAdapter.kt create mode 100644 application/src/main/kotlin/com/pokit/content/port/out/ContentCountPort.kt diff --git a/adapters/in-web/src/main/kotlin/com/pokit/content/RemindController.kt b/adapters/in-web/src/main/kotlin/com/pokit/content/RemindController.kt index 5822470c..02a23f56 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/content/RemindController.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/content/RemindController.kt @@ -4,7 +4,9 @@ import com.pokit.auth.model.PrincipalUser import com.pokit.common.dto.SliceResponseDto import com.pokit.common.wrapper.ResponseWrapper.wrapOk import com.pokit.common.wrapper.ResponseWrapper.wrapSlice +import com.pokit.content.dto.response.BookmarkCountResponse import com.pokit.content.dto.response.RemindContentResponse +import com.pokit.content.dto.response.UnreadCountResponse import com.pokit.content.dto.response.toResponse import com.pokit.content.port.`in`.ContentUseCase import com.pokit.content.port.`in`.DailyContentUseCase @@ -65,4 +67,23 @@ class RemindController( .map { it.toResponse() } .wrapOk() + @GetMapping("/unread/count") + @Operation(summary = "안읽음 컨텐츠 개수 조회 API") + fun getUnreadCount( + @AuthenticationPrincipal user: PrincipalUser + ): ResponseEntity { + val unreadCount = contentUseCase.getUnreadCount(user.id) + return UnreadCountResponse(unreadCount) + .wrapOk() + } + + @GetMapping("/bookmark/count") + @Operation(summary = "즐겨찾기 컨텐츠 개수 조회 API") + fun getBookmarkCount( + @AuthenticationPrincipal user: PrincipalUser + ): ResponseEntity { + val bookmarkCount = contentUseCase.getBookmarkCount(user.id) + return BookmarkCountResponse(bookmarkCount) + .wrapOk() + } } diff --git a/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/RemindContentResponse.kt b/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/RemindContentResponse.kt index 1c1329fd..a491e0ce 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/RemindContentResponse.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/RemindContentResponse.kt @@ -16,6 +16,14 @@ data class RemindContentResponse( val thumbNail: String, ) +data class UnreadCountResponse( + val unreadContentCount: Int +) + +data class BookmarkCountResponse( + val bookmarkContentCount: Int +) + fun RemindContentResult.toResponse(): RemindContentResponse { val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") diff --git a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/bookmark/persist/BookMarkRepository.kt b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/bookmark/persist/BookMarkRepository.kt index 407769a0..b78660ad 100644 --- a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/bookmark/persist/BookMarkRepository.kt +++ b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/bookmark/persist/BookMarkRepository.kt @@ -14,4 +14,6 @@ interface BookMarkRepository : JpaRepository { fun findByUserIdAndDeleted(userId: Long, deleted: Boolean, pageable: Pageable): Slice fun existsByContentIdAndUserIdAndDeleted(contentId: Long, userId: Long, deleted: Boolean): Boolean + + fun countByUserIdAndDeleted(userId: Long, deleted: Boolean): Int } diff --git a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/content/impl/ContentCountAdapter.kt b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/content/impl/ContentCountAdapter.kt new file mode 100644 index 00000000..c4ae02ca --- /dev/null +++ b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/content/impl/ContentCountAdapter.kt @@ -0,0 +1,32 @@ +package com.pokit.out.persistence.content.impl + +import com.pokit.content.port.out.ContentCountPort +import com.pokit.log.model.LogType +import com.pokit.out.persistence.bookmark.persist.BookMarkRepository +import com.pokit.out.persistence.category.persist.QCategoryEntity.categoryEntity +import com.pokit.out.persistence.content.persist.QContentEntity.contentEntity +import com.pokit.out.persistence.log.persist.QUserLogEntity.userLogEntity +import com.querydsl.jpa.impl.JPAQueryFactory +import org.springframework.stereotype.Repository + +@Repository +class ContentCountAdapter( + private val queryFactory: JPAQueryFactory, + private val bookMarkRepository: BookMarkRepository +) : ContentCountPort { + override fun getUnreadCount(userId: Long): Int { + return queryFactory.select(contentEntity.count()) + .from(contentEntity) + .leftJoin(userLogEntity).on(userLogEntity.contentId.eq(contentEntity.id)) + .join(categoryEntity).on(categoryEntity.id.eq(contentEntity.categoryId)) + .where( + categoryEntity.userId.eq(userId), + contentEntity.deleted.isFalse, + userLogEntity.id.isNull.or(userLogEntity.type.ne(LogType.READ)) + ) + .fetchFirst()!!.toInt() + } + + override fun getBookmarkContent(userId: Long) = + bookMarkRepository.countByUserIdAndDeleted(userId, false) +} diff --git a/application/src/main/kotlin/com/pokit/content/port/in/ContentUseCase.kt b/application/src/main/kotlin/com/pokit/content/port/in/ContentUseCase.kt index 3e947014..f0c9f864 100644 --- a/application/src/main/kotlin/com/pokit/content/port/in/ContentUseCase.kt +++ b/application/src/main/kotlin/com/pokit/content/port/in/ContentUseCase.kt @@ -36,4 +36,8 @@ interface ContentUseCase { fun getBookmarkContents(userId: Long, pageable: Pageable): Slice fun getUnreadContents(userId: Long, pageable: Pageable): Slice + + fun getUnreadCount(userId: Long): Int + + fun getBookmarkCount(userId: Long): Int } diff --git a/application/src/main/kotlin/com/pokit/content/port/out/ContentCountPort.kt b/application/src/main/kotlin/com/pokit/content/port/out/ContentCountPort.kt new file mode 100644 index 00000000..14c72984 --- /dev/null +++ b/application/src/main/kotlin/com/pokit/content/port/out/ContentCountPort.kt @@ -0,0 +1,7 @@ +package com.pokit.content.port.out + +interface ContentCountPort { + fun getUnreadCount(userId: Long): Int + + fun getBookmarkContent(userId: Long): Int +} diff --git a/application/src/main/kotlin/com/pokit/content/port/service/ContentService.kt b/application/src/main/kotlin/com/pokit/content/port/service/ContentService.kt index 79525603..8f5e6c20 100644 --- a/application/src/main/kotlin/com/pokit/content/port/service/ContentService.kt +++ b/application/src/main/kotlin/com/pokit/content/port/service/ContentService.kt @@ -18,6 +18,7 @@ import com.pokit.content.dto.response.* import com.pokit.content.exception.ContentErrorCode import com.pokit.content.model.Content import com.pokit.content.port.`in`.ContentUseCase +import com.pokit.content.port.out.ContentCountPort import com.pokit.content.port.out.ContentPort import com.pokit.log.model.LogType import com.pokit.log.model.UserLog @@ -37,7 +38,8 @@ class ContentService( private val bookMarkPort: BookmarkPort, private val categoryPort: CategoryPort, private val userLogPort: UserLogPort, - private val publisher: ApplicationEventPublisher + private val publisher: ApplicationEventPublisher, + private val contentCountPort: ContentCountPort ) : ContentUseCase { companion object { private const val MIN_CONTENT_COUNT = 3 @@ -155,6 +157,12 @@ class ContentService( return SliceImpl(remindContents, pageable, unreadContents.hasNext()) } + override fun getUnreadCount(userId: Long) = + contentCountPort.getUnreadCount(userId) + + override fun getBookmarkCount(userId: Long) = + contentCountPort.getBookmarkContent(userId) + private fun verifyContent(userId: Long, contentId: Long): Content { return contentPort.loadByUserIdAndId(userId, contentId) ?: throw NotFoundCustomException(ContentErrorCode.NOT_FOUND_CONTENT)