Skip to content

Commit

Permalink
Merge pull request #87 from ASAP-Lettering/ASAP-189
Browse files Browse the repository at this point in the history
ASAP-189 feat: 지금까지 전송한 편지 목록 조회 Api 추가
  • Loading branch information
tlarbals824 authored Oct 13, 2024
2 parents 32fbf91 + 0ff5ea2 commit 3149439
Show file tree
Hide file tree
Showing 16 changed files with 266 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.asap.application.letter.port.`in`

import java.time.LocalDate

interface GetSendLetterUsecase {
fun getHistory(query: Query.AllHistory): List<Response.History>

sealed class Query {

data class AllHistory(
val userId: String,
) : Query()
}

sealed class Response {

data class History(
val letterId: String,
val receiverName: String,
val sendDate: LocalDate,
) : Response()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ interface SendLetterManagementPort {
receiverId: DomainId,
letterCode: String,
): Boolean

fun getAllSendLetter(senderId: DomainId): List<SendLetter>
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class LetterQueryService(
GetIndependentLettersUsecase,
GetSpaceLettersUsecase,
GetSpaceLetterDetailUsecase,
GetAllLetterCountUsecase {
GetAllLetterCountUsecase,
GetSendLetterUsecase {
override fun get(query: GetVerifiedLetterUsecase.Query): GetVerifiedLetterUsecase.Response {
sendLetterManagementPort
.getReadLetterNotNull(
Expand Down Expand Up @@ -171,4 +172,13 @@ class LetterQueryService(
count = independentLetterCount + spaceLetterCount,
)
}

override fun getHistory(query: GetSendLetterUsecase.Query.AllHistory): List<GetSendLetterUsecase.Response.History> =
sendLetterManagementPort.getAllSendLetter(DomainId(query.userId)).map {
GetSendLetterUsecase.Response.History(
letterId = it.id.value,
receiverName = it.receiverName,
sendDate = it.createdDate,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
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
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
import com.asap.application.space.port.out.SpaceManagementPort
import com.asap.application.user.port.out.UserManagementPort
import com.asap.domain.LetterFixture
import com.asap.domain.UserFixture
import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.IndependentLetter
Expand Down Expand Up @@ -365,4 +363,19 @@ class LetterQueryServiceTest :
}
}
}

given("작성한 편지에 대해 조회할 떄") {
val sender = UserFixture.createUser()
val query = GetSendLetterUsecase.Query.AllHistory(sender.id.value)
val sendLetters = LetterFixture.generateSendLetter(senderId = sender.id)
every { mockSendLetterManagementPort.getAllSendLetter(sender.id) } returns listOf(sendLetters)
`when`("전체 편지 조회 요청이 들어오면") {
val response = letterQueryService.getHistory(query)
then("전체 편지를 반환한다") {
response[0].letterId shouldBe sendLetters.id.value
response[0].receiverName shouldBe sendLetters.receiverName
response[0].sendDate shouldBe sendLetters.createdDate
}
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class LetterMockManager(
fun generateMockSendLetter(
receiverName: String,
senderId: String = DomainId.generate().value,
): Map<String, Any> {
): SendLetter {
val sendLetter =
SendLetter(
receiverName = receiverName,
Expand All @@ -45,10 +45,7 @@ class LetterMockManager(
),
)
sendLetterManagementPort.save(sendLetter)
return mapOf(
"letterCode" to sendLetter.letterCode!!,
"letterId" to sendLetter.id.value,
)
return sendLetter
}

fun generateMockReadLetter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.asap.bootstrap.letter.api
import com.asap.bootstrap.common.exception.ExceptionResponse
import com.asap.bootstrap.common.security.annotation.AccessUser
import com.asap.bootstrap.letter.dto.*
import com.asap.common.page.ListResponse
import com.asap.common.page.SliceResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
Expand Down Expand Up @@ -254,4 +255,9 @@ interface LetterApi {
fun getLetterCount(
@AccessUser userId: String,
): AllLetterCountResponse

@GetMapping("/send")
fun getSendLetterHistory(
@AccessUser userId: String,
): ListResponse<SendLetterHistoryResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.asap.bootstrap.letter.controller
import com.asap.application.letter.port.`in`.*
import com.asap.bootstrap.letter.api.LetterApi
import com.asap.bootstrap.letter.dto.*
import com.asap.common.page.ListResponse
import com.asap.common.page.SliceResponse
import org.springframework.web.bind.annotation.RestController

Expand All @@ -16,6 +17,7 @@ class LetterController(
private val removeLetterUsecase: RemoveLetterUsecase,
private val updateLetterUsecase: UpdateLetterUsecase,
private val getAllLetterCountUsecase: GetAllLetterCountUsecase,
private val getSendLetterUsecase: GetSendLetterUsecase,
) : LetterApi {
override fun verifyLetter(
request: LetterVerifyRequest,
Expand Down Expand Up @@ -196,4 +198,23 @@ class LetterController(
count = response.count,
)
}

override fun getSendLetterHistory(userId: String): ListResponse<SendLetterHistoryResponse> {
val response =
getSendLetterUsecase.getHistory(
GetSendLetterUsecase.Query.AllHistory(
userId = userId,
),
)
return ListResponse.of(
content =
response.map {
SendLetterHistoryResponse(
letterId = it.letterId,
receiverName = it.receiverName,
sendDate = it.sendDate,
)
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.asap.bootstrap.letter.dto

import java.time.LocalDate

data class SendLetterHistoryResponse(
val letterId: String,
val receiverName: String,
val sendDate: LocalDate,
)
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ abstract class LetterAcceptanceSupporter : AcceptanceSupporter() {

@MockBean
lateinit var getAllLetterCountUsecase: GetAllLetterCountUsecase

@MockBean
lateinit var getSendLetterUsecase: GetSendLetterUsecase
}
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ class LetterControllerTest : LetterAcceptanceSupporter() {
}

@Test
fun getAllLetterCount() {
fun getAllLetterCount() {
// given
val accessToken = jwtMockManager.generateAccessToken()
val response = GetAllLetterCountUsecase.Response(5)
Expand Down Expand Up @@ -406,4 +406,58 @@ class LetterControllerTest : LetterAcceptanceSupporter() {
}
}
}

@Test
fun getAllSendLetterHistory() {
// given
val accessToken = jwtMockManager.generateAccessToken()
val response =
(0..2).map {
GetSendLetterUsecase.Response.History(
letterId = "letterId$it",
receiverName = "receiverName$it",
sendDate = LocalDate.now(),
)
}
BDDMockito
.given(
getSendLetterUsecase.getHistory(
GetSendLetterUsecase.Query.AllHistory(
userId = "userId",
),
),
).willReturn(response)

// when
val result =
mockMvc.get("/api/v1/letters/send") {
contentType = MediaType.APPLICATION_JSON
header("Authorization", "Bearer $accessToken")
}
// then
result.andExpect {
status { isOk() }
jsonPath("$.content") {
exists()
isArray()
(0..2).forEach {
jsonPath("$.content[$it].letterId") {
exists()
isString()
isNotEmpty()
}
jsonPath("$.content[$it].receiverName") {
exists()
isString()
isNotEmpty()
}
jsonPath("$.content[$it].sendDate") {
exists()
isString()
isNotEmpty()
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class LetterApiIntegrationTest : IntegrationSupporter() {
val userId = userMockManager.settingUser(username = "username")
val accessToken = jwtMockManager.generateAccessToken(userId)
val letterCode =
letterMockManager.generateMockSendLetter("username", senderId = senderId)["letterCode"] as String
letterMockManager.generateMockSendLetter("username", senderId = senderId).letterCode!!
val request = LetterVerifyRequest(letterCode)
// when
val response =
Expand Down Expand Up @@ -83,7 +83,7 @@ class LetterApiIntegrationTest : IntegrationSupporter() {
val userId = userMockManager.settingUser(username = "username")
val accessToken = jwtMockManager.generateAccessToken(userId)
val letterCode =
letterMockManager.generateMockSendLetter("otherUsername_invalidUser", senderId)["letterCode"] as String
letterMockManager.generateMockSendLetter("otherUsername_invalidUser", senderId).letterCode!!
val request = LetterVerifyRequest(letterCode)
// when
val response =
Expand Down Expand Up @@ -658,4 +658,52 @@ class LetterApiIntegrationTest : IntegrationSupporter() {
}
}
}

@Test
fun getAllSendLetterHistory() {
// given
val senderId = userMockManager.settingUser()
val accessToken = jwtMockManager.generateAccessToken(senderId)
val sendLetters =
(0..3).map {
letterMockManager.generateMockSendLetter(
receiverName = "receiverName",
senderId = senderId,
)
}
// when
val response =
mockMvc.get("/api/v1/letters/send") {
contentType = MediaType.APPLICATION_JSON
header("Authorization", "Bearer $accessToken")
}
// then
response.andExpect {
status { isOk() }
jsonPath("$.content") {
exists()
isArray()
(0..3).forEach {
jsonPath("$.content[$it].letterId") {
exists()
isString()
isNotEmpty()
value(sendLetters[it].id.value)
}
jsonPath("$.content[$it].receiverName") {
exists()
isString()
isNotEmpty()
value(sendLetters[it].receiverName)
}
jsonPath("$.content[$it].sendDate") {
exists()
isString()
isNotEmpty()
value(sendLetters[it].createdDate.toString())
}
}
}
}
}
}
10 changes: 10 additions & 0 deletions Common-Module/src/main/kotlin/com/asap/common/page/ListResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.asap.common.page

data class ListResponse<T> internal constructor(
val content: List<T>,
val size: Int,
) {
companion object {
fun <T> of(content: List<T>): ListResponse<T> = ListResponse(content, content.size)
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
package com.asap.common.page

data class PageResponse<T>(
data class PageResponse<T> internal constructor(
val content: List<T>,
val totalElements: Long,
val totalPages: Int,
val size: Int,
val page: Int
val page: Int,
) {

companion object {
fun <T> of(
content: List<T>,
totalElements: Long,
totalPages: Int,
size: Int,
page: Int
): PageResponse<T> {
return PageResponse(
page: Int,
): PageResponse<T> =
PageResponse(
content = content,
totalElements = totalElements,
totalPages = totalPages,
size = size,
page = page
page = page,
)
}
}
}
}
Loading

0 comments on commit 3149439

Please sign in to comment.