From 9f5489a0a1248b0e864e53d458ff7cf7f77e25cc Mon Sep 17 00:00:00 2001 From: Sim-km Date: Sat, 12 Oct 2024 18:55:59 +0900 Subject: [PATCH] =?UTF-8?q?ASAP-198=20feat:=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=80=20=EC=88=98=20=EC=A1=B0=ED=9A=8C=20api=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../port/in/GetAllLetterCountUsecase.kt | 13 ++++++ .../out/IndependentLetterManagementPort.kt | 2 +- .../port/out/SpaceLetterManagementPort.kt | 30 +++++++++---- .../letter/service/LetterQueryService.kt | 40 +++++++++++------ .../space/service/SpaceQueryService.kt | 2 +- .../letter/service/LetterQueryServiceTest.kt | 21 ++++++++- .../space/service/SpaceQueryServiceTest.kt | 2 +- .../asap/bootstrap/letter/api/LetterApi.kt | 37 ++++++++++++++++ .../letter/controller/LetterController.kt | 13 ++++++ .../letter/dto/AllLetterCountResponse.kt | 5 +++ .../letter/LetterAcceptanceSupporter.kt | 3 ++ .../letter/controller/LetterControllerTest.kt | 35 +++++++++++++-- .../letter/LetterApiIntegrationTest.kt | 30 +++++++++++++ .../ReceiveLetterManagementJpaAdapter.kt | 12 +++-- .../repository/ReceiveLetterJpaRepository.kt | 44 ++++++++++++++++--- 15 files changed, 249 insertions(+), 40 deletions(-) create mode 100644 Application-Module/src/main/kotlin/com/asap/application/letter/port/in/GetAllLetterCountUsecase.kt create mode 100644 Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/dto/AllLetterCountResponse.kt diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/port/in/GetAllLetterCountUsecase.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/port/in/GetAllLetterCountUsecase.kt new file mode 100644 index 0000000..79eb404 --- /dev/null +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/port/in/GetAllLetterCountUsecase.kt @@ -0,0 +1,13 @@ +package com.asap.application.letter.port.`in` + +interface GetAllLetterCountUsecase { + fun get(query: Query): Response + + data class Query( + val userId: String, + ) + + data class Response( + val count: Long, + ) +} diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/IndependentLetterManagementPort.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/IndependentLetterManagementPort.kt index fcbcc01..17a7a8e 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/IndependentLetterManagementPort.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/IndependentLetterManagementPort.kt @@ -15,7 +15,7 @@ interface IndependentLetterManagementPort { userId: DomainId, ): IndependentLetter - fun countIndependentLetterByReceiverId(receiverId: DomainId): Int + fun countIndependentLetterByReceiverId(receiverId: DomainId): Long fun getNearbyLetter( userId: DomainId, diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/SpaceLetterManagementPort.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/SpaceLetterManagementPort.kt index da51984..58bc4c3 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/SpaceLetterManagementPort.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/port/out/SpaceLetterManagementPort.kt @@ -7,25 +7,37 @@ import com.asap.domain.letter.entity.IndependentLetter import com.asap.domain.letter.entity.SpaceLetter interface SpaceLetterManagementPort { - - fun save(letter: SpaceLetter) fun saveByIndependentLetter( letter: IndependentLetter, spaceId: DomainId, - userId: DomainId + userId: DomainId, ): SpaceLetter - fun getSpaceLetterNotNull(id: DomainId, userId: DomainId): SpaceLetter + fun getSpaceLetterNotNull( + id: DomainId, + userId: DomainId, + ): SpaceLetter - fun getNearbyLetter(spaceId: DomainId, userId: DomainId, letterId: DomainId): Pair + fun getNearbyLetter( + spaceId: DomainId, + userId: DomainId, + letterId: DomainId, + ): Pair - fun countLetterBySpaceId(spaceId: DomainId): Long + fun countSpaceLetterBy( + spaceId: DomainId, + receiverId: DomainId, + ): Long + fun countAllSpaceLetterBy(receiverId: DomainId): Long - fun getAllBySpaceId(spaceId: DomainId, userId: DomainId, pageRequest: PageRequest): Page + fun getAllBy( + spaceId: DomainId, + userId: DomainId, + pageRequest: PageRequest, + ): Page fun delete(letter: SpaceLetter) - -} \ No newline at end of file +} diff --git a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt index 6262278..bce1fbb 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/letter/service/LetterQueryService.kt @@ -1,9 +1,6 @@ package com.asap.application.letter.service -import com.asap.application.letter.port.`in`.GetIndependentLettersUsecase -import com.asap.application.letter.port.`in`.GetSpaceLetterDetailUsecase -import com.asap.application.letter.port.`in`.GetSpaceLettersUsecase -import com.asap.application.letter.port.`in`.GetVerifiedLetterUsecase +import com.asap.application.letter.port.`in`.* import com.asap.application.letter.port.out.IndependentLetterManagementPort import com.asap.application.letter.port.out.SendLetterManagementPort import com.asap.application.letter.port.out.SpaceLetterManagementPort @@ -25,7 +22,8 @@ class LetterQueryService( ) : GetVerifiedLetterUsecase, GetIndependentLettersUsecase, GetSpaceLettersUsecase, - GetSpaceLetterDetailUsecase { + GetSpaceLetterDetailUsecase, + GetAllLetterCountUsecase { override fun get(query: GetVerifiedLetterUsecase.Query): GetVerifiedLetterUsecase.Response { sendLetterManagementPort .getReadLetterNotNull( @@ -60,10 +58,14 @@ class LetterQueryService( @Transactional override fun get(query: GetIndependentLettersUsecase.Query): GetIndependentLettersUsecase.Response.One { val letter = - independentLetterManagementPort.getIndependentLetterByIdNotNull(DomainId(query.letterId), DomainId(query.userId)).apply { - read() - independentLetterManagementPort.save(this) - } + independentLetterManagementPort + .getIndependentLetterByIdNotNull( + DomainId(query.letterId), + DomainId(query.userId), + ).apply { + read() + independentLetterManagementPort.save(this) + } val letterCount = independentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) val (prevLetter, nextLetter) = independentLetterManagementPort.getNearbyLetter(DomainId(query.userId), DomainId(query.letterId)) @@ -93,7 +95,7 @@ class LetterQueryService( override fun get(query: GetSpaceLettersUsecase.Query): GetSpaceLettersUsecase.Response { val letters = - spaceLetterManagementPort.getAllBySpaceId( + spaceLetterManagementPort.getAllBy( spaceId = DomainId(query.spaceId), userId = DomainId(query.userId), pageRequest = @@ -123,10 +125,14 @@ class LetterQueryService( spaceLetterManagementPort.getSpaceLetterNotNull(DomainId(query.letterId), DomainId(query.userId)) val space = spaceManagementPort.getSpaceNotNull( - spaceLetter.receiver.receiverId, - spaceLetter.spaceId, + userId = spaceLetter.receiver.receiverId, + spaceId = spaceLetter.spaceId, + ) + val letterCount = + spaceLetterManagementPort.countSpaceLetterBy( + spaceId = spaceLetter.spaceId, + receiverId = spaceLetter.receiver.receiverId, ) - val letterCount = spaceLetterManagementPort.countLetterBySpaceId(spaceLetter.spaceId) val (prevLetter, nextLetter) = spaceLetterManagementPort.getNearbyLetter( spaceId = spaceLetter.spaceId, @@ -157,4 +163,12 @@ class LetterQueryService( }, ) } + + override fun get(query: GetAllLetterCountUsecase.Query): GetAllLetterCountUsecase.Response { + val independentLetterCount = independentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) + val spaceLetterCount = spaceLetterManagementPort.countAllSpaceLetterBy(DomainId(query.userId)) + return GetAllLetterCountUsecase.Response( + count = independentLetterCount + spaceLetterCount, + ) + } } diff --git a/Application-Module/src/main/kotlin/com/asap/application/space/service/SpaceQueryService.kt b/Application-Module/src/main/kotlin/com/asap/application/space/service/SpaceQueryService.kt index d6bb878..f375e84 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/space/service/SpaceQueryService.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/space/service/SpaceQueryService.kt @@ -46,7 +46,7 @@ class SpaceQueryService( spaces.map { SpaceGetUsecase.SpaceDetail( spaceName = it.name, - letterCount = spaceLetterManagementPort.countLetterBySpaceId(it.id), + letterCount = spaceLetterManagementPort.countSpaceLetterBy(it.id, DomainId(query.userId)), isMainSpace = it.isMain(), spaceIndex = it.index, spaceId = it.id.value, diff --git a/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt b/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt index 4061e7f..a4d3499 100644 --- a/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt +++ b/Application-Module/src/test/kotlin/com/asap/application/letter/service/LetterQueryServiceTest.kt @@ -1,5 +1,6 @@ package com.asap.application.letter.service +import com.asap.application.letter.port.`in`.GetAllLetterCountUsecase import com.asap.application.letter.port.`in`.GetIndependentLettersUsecase import com.asap.application.letter.port.`in`.GetSpaceLetterDetailUsecase import com.asap.application.letter.port.`in`.GetVerifiedLetterUsecase @@ -212,7 +213,10 @@ class LetterQueryServiceTest : ) } returns space every { - mockSpaceLetterManagementPort.countLetterBySpaceId(spaceLetter.spaceId) + mockSpaceLetterManagementPort.countSpaceLetterBy( + spaceLetter.spaceId, + spaceLetter.receiver.receiverId, + ) } returns 3 every { mockSpaceLetterManagementPort.getNearbyLetter( @@ -346,4 +350,19 @@ class LetterQueryServiceTest : } } } + + given("전체 편지 조회 요청이 들어올 떄") { + val independentLetterCount = 10L + val spaceLetterCount = 20L + val query = GetAllLetterCountUsecase.Query("userId") + every { mockIndependentLetterManagementPort.countIndependentLetterByReceiverId(DomainId(query.userId)) } returns + independentLetterCount + every { mockSpaceLetterManagementPort.countAllSpaceLetterBy(DomainId(query.userId)) } returns spaceLetterCount + `when`("유저 아이디가 주어진다면") { + val response = letterQueryService.get(query) + then("전체 편지 개수를 반환한다") { + response.count shouldBe independentLetterCount + spaceLetterCount + } + } + } }) diff --git a/Application-Module/src/test/kotlin/com/asap/application/space/service/SpaceQueryServiceTest.kt b/Application-Module/src/test/kotlin/com/asap/application/space/service/SpaceQueryServiceTest.kt index 448d7f4..d3e13c1 100644 --- a/Application-Module/src/test/kotlin/com/asap/application/space/service/SpaceQueryServiceTest.kt +++ b/Application-Module/src/test/kotlin/com/asap/application/space/service/SpaceQueryServiceTest.kt @@ -92,7 +92,7 @@ class SpaceQueryServiceTest : userId = "userId", ) every { spaceManagementPort.getAllIndexedSpace(DomainId(query.userId)) } returns indexedSpaces - every { spaceLetterManagementPort.countLetterBySpaceId(any()) } returns 0 + every { spaceLetterManagementPort.countSpaceLetterBy(any(), any()) } returns 0 `when`("유저 아이디가 주어진다면") { val response = spaceQueryService.getAll(query) then("모든 스페이스를 반환한다") { diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/api/LetterApi.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/api/LetterApi.kt index 0a96e2a..a09caf5 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/api/LetterApi.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/api/LetterApi.kt @@ -179,7 +179,16 @@ interface LetterApi { @AccessUser userId: String, ): GetIndependentLetterDetailResponse + @Operation(summary = "궤도 편지 삭제") @DeleteMapping("/independent/{letterId}") + @ApiResponses( + value = [ + ApiResponse( + responseCode = "200", + description = "궤도 편지 삭제 성공", + ), + ], + ) fun deleteIndependentLetter( @PathVariable letterId: String, @AccessUser userId: String, @@ -187,6 +196,14 @@ interface LetterApi { @Operation(summary = "편지 수정") @PutMapping("/independent/{letterId}/content") + @ApiResponses( + value = [ + ApiResponse( + responseCode = "200", + description = "편지 수정 성공", + ), + ], + ) fun updateIndependentLetter( @PathVariable letterId: String, @RequestBody request: ModifyLetterRequest, @@ -217,4 +234,24 @@ interface LetterApi { @RequestBody request: SendLetterRequest, @AccessUser userId: String, ): SendLetterResponse + + @Operation(summary = "모든 편지 수 조회") + @GetMapping("/count") + @ApiResponses( + value = [ + ApiResponse( + responseCode = "200", + description = "모든 편지 수 조회 성공", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AllLetterCountResponse::class), + ), + ], + ), + ], + ) + fun getLetterCount( + @AccessUser userId: String, + ): AllLetterCountResponse } diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/controller/LetterController.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/controller/LetterController.kt index adf08bb..8308e8b 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/controller/LetterController.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/controller/LetterController.kt @@ -15,6 +15,7 @@ class LetterController( private val getIndependentLettersUsecase: GetIndependentLettersUsecase, private val removeLetterUsecase: RemoveLetterUsecase, private val updateLetterUsecase: UpdateLetterUsecase, + private val getAllLetterCountUsecase: GetAllLetterCountUsecase, ) : LetterApi { override fun verifyLetter( request: LetterVerifyRequest, @@ -183,4 +184,16 @@ class LetterController( letterCode = response.letterCode, ) } + + override fun getLetterCount(userId: String): AllLetterCountResponse { + val response = + getAllLetterCountUsecase.get( + GetAllLetterCountUsecase.Query( + userId = userId, + ), + ) + return AllLetterCountResponse( + count = response.count, + ) + } } diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/dto/AllLetterCountResponse.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/dto/AllLetterCountResponse.kt new file mode 100644 index 0000000..9325fa2 --- /dev/null +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/letter/dto/AllLetterCountResponse.kt @@ -0,0 +1,5 @@ +package com.asap.bootstrap.letter.dto + +data class AllLetterCountResponse( + val count: Long, +) diff --git a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/LetterAcceptanceSupporter.kt b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/LetterAcceptanceSupporter.kt index 3d4e819..24fd544 100644 --- a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/LetterAcceptanceSupporter.kt +++ b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/LetterAcceptanceSupporter.kt @@ -46,4 +46,7 @@ abstract class LetterAcceptanceSupporter : AcceptanceSupporter() { @MockBean lateinit var updateLetterUsecase: UpdateLetterUsecase + + @MockBean + lateinit var getAllLetterCountUsecase: GetAllLetterCountUsecase } diff --git a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/controller/LetterControllerTest.kt b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/controller/LetterControllerTest.kt index e34bc03..097426a 100644 --- a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/controller/LetterControllerTest.kt +++ b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/controller/LetterControllerTest.kt @@ -1,9 +1,6 @@ package com.asap.bootstrap.acceptance.letter.controller -import com.asap.application.letter.port.`in`.GetIndependentLettersUsecase -import com.asap.application.letter.port.`in`.GetVerifiedLetterUsecase -import com.asap.application.letter.port.`in`.SendLetterUsecase -import com.asap.application.letter.port.`in`.VerifyLetterAccessibleUsecase +import com.asap.application.letter.port.`in`.* import com.asap.bootstrap.acceptance.letter.LetterAcceptanceSupporter import com.asap.bootstrap.letter.dto.* import org.junit.jupiter.api.Test @@ -379,4 +376,34 @@ class LetterControllerTest : LetterAcceptanceSupporter() { status { isOk() } } } + + @Test + fun getAllLetterCount() { + // given + val accessToken = jwtMockManager.generateAccessToken() + val response = GetAllLetterCountUsecase.Response(5) + BDDMockito + .given( + getAllLetterCountUsecase.get( + GetAllLetterCountUsecase.Query( + userId = "userId", + ), + ), + ).willReturn(response) + // when + val result = + mockMvc.get("/api/v1/letters/count") { + contentType = MediaType.APPLICATION_JSON + header("Authorization", "Bearer $accessToken") + } + // then + result.andExpect { + status { isOk() } + jsonPath("$.count") { + exists() + isNumber() + value(5) + } + } + } } diff --git a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/letter/LetterApiIntegrationTest.kt b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/letter/LetterApiIntegrationTest.kt index ae80a79..8392ff0 100644 --- a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/letter/LetterApiIntegrationTest.kt +++ b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/letter/LetterApiIntegrationTest.kt @@ -628,4 +628,34 @@ class LetterApiIntegrationTest : IntegrationSupporter() { status { isOk() } } } + + @Test + fun getAllLetterCount() { + // given + val senderId = userMockManager.settingUser() + val receiverId = userMockManager.settingUser() + val accessToken = jwtMockManager.generateAccessToken(receiverId) + (0..3).forEach { + letterMockManager.generateMockIndependentLetter( + senderId = senderId, + receiverId = receiverId, + senderName = "senderUsername", + ) + } + // when + val response = + mockMvc.get("/api/v1/letters/count") { + contentType = MediaType.APPLICATION_JSON + header("Authorization", "Bearer $accessToken") + } + // then + response.andExpect { + status { isOk() } + jsonPath("$.count") { + exists() + isNumber() + value(4) + } + } + } } diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/adapter/ReceiveLetterManagementJpaAdapter.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/adapter/ReceiveLetterManagementJpaAdapter.kt index 77e9e51..e9e821d 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/adapter/ReceiveLetterManagementJpaAdapter.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/adapter/ReceiveLetterManagementJpaAdapter.kt @@ -57,7 +57,7 @@ class ReceiveLetterManagementJpaAdapter( return ReceiverLetterMapper.toIndependentLetter(letter) } - override fun countIndependentLetterByReceiverId(receiverId: DomainId): Int = + override fun countIndependentLetterByReceiverId(receiverId: DomainId): Long = receiveLetterJpaRepository.countActiveIndependentByReceiverId(receiverId.value) override fun getNearbyLetter( @@ -134,9 +134,15 @@ class ReceiveLetterManagementJpaAdapter( ) } - override fun countLetterBySpaceId(spaceId: DomainId): Long = receiveLetterJpaRepository.countBySpaceId(spaceId.value).toLong() + override fun countSpaceLetterBy( + spaceId: DomainId, + receiverId: DomainId, + ): Long = receiveLetterJpaRepository.countActiveSpaceLetterBy(spaceId.value, receiverId.value) + + override fun countAllSpaceLetterBy(receiverId: DomainId): Long = + receiveLetterJpaRepository.countAllActiveSpaceLetterBy(receiverId.value) - override fun getAllBySpaceId( + override fun getAllBy( spaceId: DomainId, userId: DomainId, pageRequest: PageRequest, diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/repository/ReceiveLetterJpaRepository.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/repository/ReceiveLetterJpaRepository.kt index 13758a5..9974779 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/repository/ReceiveLetterJpaRepository.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/letter/repository/ReceiveLetterJpaRepository.kt @@ -87,21 +87,45 @@ interface ReceiveLetterJpaRepository : JpaRepository