Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASAP-389 실물 편지 임시 저장한 내용을 수정하기 위한 api 추가 #111

Merged
merged 1 commit into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,34 @@ sealed class LetterException(
class SendLetterNotFoundException(
message: String = "존재하지 않는 편지입니다.",
) : LetterException(
errorCode = 1,
message = message,
httpStatus = 404,
)
errorCode = 1,
message = message,
httpStatus = 404,
)

class InvalidLetterAccessException(
message: String = "편지에 대한 접근 권한이 없습니다.",
) : LetterException(
errorCode = 2,
message = message,
httpStatus = 403,
)
errorCode = 2,
message = message,
httpStatus = 403,
)

class ReceiveLetterNotFoundException(
message: String = "존재하지 않는 편지입니다.",
) : LetterException(
errorCode = 3,
message = message,
httpStatus = 404,
)
errorCode = 3,
message = message,
httpStatus = 404,
)

class DraftLetterNotFoundException(
message: String = "존재하지 않는 임시 편지입니다.",
) : LetterException(
errorCode = 4,
message = message,
httpStatus = 404,
)
errorCode = 4,
message = message,
httpStatus = 404,
)

companion object {
const val CODE_PREFIX = "LETTER"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package com.asap.application.letter.port.`in`

interface UpdateDraftLetterUsecase {
fun command(command: Command)

data class Command(
val draftId: String,
val userId: String,
val content: String,
val receiverName: String,
val images: List<String>,
)
fun command(command: Command.Send)

fun command(command: Command.Physical)

sealed class Command {
data class Send(
val draftId: String,
val userId: String,
val content: String,
val images: List<String>,
val receiverName: String,
) : Command()

data class Physical(
val draftId: String,
val userId: String,
val content: String,
val images: List<String>,
val senderName: String,
) : Command()
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.asap.application.letter.port.out

import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.ReceiveDraftLetter

interface ReceiveDraftLetterManagementPort {
fun save(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetter

fun getDraftLetterNotNull(draftId: DomainId, ownerId: DomainId): ReceiveDraftLetter
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class DraftLetterCommandService(
return GenerateDraftKeyUsecase.Response(receiveDraftLetter.id.value)
}

override fun command(command: UpdateDraftLetterUsecase.Command) {
override fun command(command: UpdateDraftLetterUsecase.Command.Send) {
val draftLetter =
draftLetterManagementPort.getDraftLetterNotNull(
draftId = DomainId(command.draftId),
Expand Down Expand Up @@ -63,4 +63,19 @@ class DraftLetterCommandService(
draftLetterManagementPort.remove(it)
}
}

override fun command(command: UpdateDraftLetterUsecase.Command.Physical) {
val receiveDraftLetter =
receiveDraftLetterManagementPort.getDraftLetterNotNull(
draftId = DomainId(command.draftId),
ownerId = DomainId(command.userId),
)

receiveDraftLetter.update(
content = command.content,
senderName = command.senderName,
images = command.images,
)
receiveDraftLetterManagementPort.save(receiveDraftLetter)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.asap.application.letter.service

import com.asap.application.letter.exception.LetterException
import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
import com.asap.application.letter.port.`in`.RemoveDraftLetterUsecase
import com.asap.application.letter.port.`in`.UpdateDraftLetterUsecase
Expand All @@ -8,6 +9,7 @@ import com.asap.application.letter.port.out.ReceiveDraftLetterManagementPort
import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.DraftLetter
import com.asap.domain.letter.entity.ReceiveDraftLetter
import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import io.mockk.every
Expand All @@ -16,6 +18,7 @@ import io.mockk.verify

class DraftLetterCommandServiceTest :
BehaviorSpec({
isolationMode = IsolationMode.InstancePerLeaf

val mockGenerateDraftKeyUsecase = mockk<DraftLetterManagementPort>(relaxed = true)
val mockReceiveDraftLetterManagementPort = mockk<ReceiveDraftLetterManagementPort>(relaxed = true)
Expand All @@ -36,7 +39,7 @@ class DraftLetterCommandServiceTest :

given("임시 저장 편지를 수정할 때") {
val command =
UpdateDraftLetterUsecase.Command(
UpdateDraftLetterUsecase.Command.Send(
draftId = "draftId",
userId = "userId",
content = "content",
Expand Down Expand Up @@ -86,4 +89,50 @@ class DraftLetterCommandServiceTest :
}
}
}

given("받은 임시 저장편지를 수저할 때"){

`when`("사용자 아이디와 임시 저장 편지 아이디, 내용, 발신자 이름, 이미지를 입력하면"){
val command = UpdateDraftLetterUsecase.Command.Physical(
draftId = "draftId",
userId = "userId",
content = "content",
images = listOf("image1", "image2"),
senderName = "senderName",
)
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(command.userId))
every {
mockReceiveDraftLetterManagementPort.getDraftLetterNotNull(
draftId = receiveDraftLetter.id,
ownerId = receiveDraftLetter.ownerId,
)
} returns receiveDraftLetter
draftLetterCommandService.command(command)
then("받은 임시 저장편지를 수정한다"){
verify { mockReceiveDraftLetterManagementPort.save(any()) }
}
}

`when`("임시 저장 편지가 없으면"){

val command = UpdateDraftLetterUsecase.Command.Physical(
draftId = "draftId",
userId = "userId",
content = "content",
images = listOf("image1", "image2"),
senderName = "senderName",
)
every {
mockReceiveDraftLetterManagementPort.getDraftLetterNotNull(
draftId = DomainId(command.draftId),
ownerId = DomainId(command.userId),
)
} throws LetterException.DraftLetterNotFoundException()
then("임시 저장 편지가 수정되지 않는다"){
verify(exactly = 0) {
mockReceiveDraftLetterManagementPort.save(any())
}
}
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.asap.application.letter

import com.asap.application.letter.port.out.DraftLetterManagementPort
import com.asap.application.letter.port.out.IndependentLetterManagementPort
import com.asap.application.letter.port.out.ReceiveDraftLetterManagementPort
import com.asap.application.letter.port.out.SendLetterManagementPort
import com.asap.application.letter.port.out.SpaceLetterManagementPort
import org.springframework.boot.test.context.TestConfiguration
Expand All @@ -13,6 +14,7 @@ class LetterApplicationConfig(
private val independentLetterManagementPort: IndependentLetterManagementPort,
private val spaceLetterManagementPort: SpaceLetterManagementPort,
private val draftLetterManagementPort: DraftLetterManagementPort,
private val receiveDraftLetterManagementPort: ReceiveDraftLetterManagementPort,
) {
@Bean
fun letterMockManager(): LetterMockManager =
Expand All @@ -21,5 +23,6 @@ class LetterApplicationConfig(
independentLetterManagementPort,
spaceLetterManagementPort,
draftLetterManagementPort,
receiveDraftLetterManagementPort
)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package com.asap.application.letter

import com.asap.application.letter.port.out.DraftLetterManagementPort
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.letter.port.out.*
import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.DraftLetter
import com.asap.domain.letter.entity.IndependentLetter
import com.asap.domain.letter.entity.SendLetter
import com.asap.domain.letter.entity.SpaceLetter
import com.asap.domain.letter.entity.*
import com.asap.domain.letter.service.LetterCodeGenerator
import com.asap.domain.letter.vo.LetterContent
import com.asap.domain.letter.vo.ReceiverInfo
Expand All @@ -21,6 +15,7 @@ class LetterMockManager(
private val independentLetterManagementPort: IndependentLetterManagementPort,
private val spaceLetterManagementPort: SpaceLetterManagementPort,
private val draftLetterManagementPort: DraftLetterManagementPort,
private val receiveDraftLetterManagementPort: ReceiveDraftLetterManagementPort,
) {
private val letterCodeGenerator = LetterCodeGenerator()

Expand Down Expand Up @@ -158,4 +153,10 @@ class LetterMockManager(
draftLetterManagementPort.save(draftLetter)
return draftLetter.id.value
}

fun generateMockReceiveDraftLetter(userId: String): String {
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(userId))
receiveDraftLetterManagementPort.save(receiveDraftLetter)
return receiveDraftLetter.id.value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ interface DraftLetterApi {
@RequestBody request: UpdateDraftLetterRequest,
)

@Operation(summary = "실물 편지 임시 저장하기")
@PostMapping("/physical/{draftId}")
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "임시 저장 성공"),
],
)
fun updatePhysicalDraft(
@PathVariable draftId: String,
@AccessUser userId: String,
@RequestBody request: UpdatePhysicalDraftLetterRequest,
)

@Operation(summary = "임시 저장 목록 조회")
@GetMapping()
@ApiResponses(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class DraftLetterController(
request: UpdateDraftLetterRequest,
) {
updateDraftLetterUsecase.command(
UpdateDraftLetterUsecase.Command(
UpdateDraftLetterUsecase.Command.Send(
draftId = draftId,
userId = userId,
content = request.content,
Expand All @@ -41,6 +41,22 @@ class DraftLetterController(
)
}

override fun updatePhysicalDraft(
draftId: String,
userId: String,
request: UpdatePhysicalDraftLetterRequest
) {
updateDraftLetterUsecase.command(
UpdateDraftLetterUsecase.Command.Physical(
draftId = draftId,
userId = userId,
content = request.content,
images = request.images,
senderName = request.senderName,
),
)
}

override fun getAllDrafts(userId: String): GetAllDraftLetterResponse =
getDraftLetterUsecase
.getAll(GetDraftLetterUsecase.Query.All(userId))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.asap.bootstrap.web.letter.dto

data class UpdatePhysicalDraftLetterRequest(
val senderName: String,
val content: String,
val images: List<String>
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
import com.asap.application.letter.port.`in`.GetDraftLetterUsecase
import com.asap.bootstrap.acceptance.letter.LetterAcceptanceSupporter
import com.asap.bootstrap.web.letter.dto.UpdateDraftLetterRequest
import com.asap.bootstrap.web.letter.dto.UpdatePhysicalDraftLetterRequest
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito
import org.springframework.http.MediaType
Expand Down Expand Up @@ -204,4 +205,29 @@ class DraftLetterControllerTest : LetterAcceptanceSupporter() {
jsonPath("$.draftId") { isString() }
}
}

@Test
fun `update physical draft`() {
// given
val userId = userMockManager.settingUser()
val accessToken = jwtMockManager.generateAccessToken(userId)
val request =
UpdatePhysicalDraftLetterRequest(
content = "content",
senderName = "senderName",
images = listOf("image"),
)
// when
val response =
mockMvc.post("/api/v1/letters/drafts/physical/draftId") {
contentType = MediaType.APPLICATION_JSON
header("Authorization", "Bearer $accessToken")
content = objectMapper.writeValueAsString(request)
}

// then
response.andExpect {
status { isOk() }
}
}
}
Loading
Loading