Skip to content

Commit

Permalink
Merge pull request #31 from ASAP-Lettering/ASAP-112
Browse files Browse the repository at this point in the history
ASAP-112 feat: 받은 편지 내 스페이스로 옮기는 api 구현 및 테스트 추가
  • Loading branch information
tlarbals824 authored Sep 12, 2024
2 parents 57b75ff + 609fdd6 commit 0630e27
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.asap.application.letter.port.`in`

interface AddLetterUsecase {

fun addVerifiedLetter(
command: Command.VerifyLetter
)

sealed class Command {

data class VerifyLetter(
val letterId: String,
val userId: String
): Command()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.asap.application.letter.port.out

import com.asap.domain.letter.entity.IndependentLetter

interface IndependentLetterManagementPort {

fun save(letter: IndependentLetter)
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ interface SendLetterManagementPort {
letterCode: String
): Boolean

fun verifiedLetter(
receiverId: DomainId,
fun remove(
letterId: DomainId
): Boolean
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.asap.application.letter.port.out.memory

import com.asap.application.letter.port.out.IndependentLetterManagementPort
import com.asap.domain.letter.entity.IndependentLetter
import org.springframework.stereotype.Component

@Component
class MemoryIndependentLetterManagementAdapter(

): IndependentLetterManagementPort {

private val independentLetters = mutableListOf<IndependentLetter>()

override fun save(letter: IndependentLetter) {
independentLetters.add(letter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class MemorySendLetterManagementAdapter(
?: false
}

override fun verifiedLetter(receiverId: DomainId, letterId: DomainId): Boolean {
TODO("Not yet implemented")
override fun remove(letterId: DomainId) {
sendLetters.removeIf { it.id == letterId.value }
}

private fun matchingNotExpired(query: SendLetterEntity.() -> Boolean): SendLetterEntity? {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
package com.asap.application.letter.service

import com.asap.application.letter.exception.LetterException
import com.asap.application.letter.port.`in`.AddLetterUsecase
import com.asap.application.letter.port.`in`.SendLetterUsecase
import com.asap.application.letter.port.`in`.VerifyLetterAccessibleUsecase
import com.asap.application.letter.port.out.IndependentLetterManagementPort
import com.asap.application.letter.port.out.SendLetterManagementPort
import com.asap.application.user.port.out.UserManagementPort
import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.IndependentLetter
import com.asap.domain.letter.entity.SendLetter
import com.asap.domain.letter.service.LetterCodeGenerator
import org.springframework.stereotype.Service

@Service
class LetterCommandService(
private val sendLetterManagementPort: SendLetterManagementPort,
private val userManagementPort: UserManagementPort
) : SendLetterUsecase, VerifyLetterAccessibleUsecase {
private val independentLetterManagementPort: IndependentLetterManagementPort,
private val userManagementPort: UserManagementPort,
) : SendLetterUsecase, VerifyLetterAccessibleUsecase, AddLetterUsecase {

private val letterCodeGenerator = LetterCodeGenerator()

Expand Down Expand Up @@ -60,4 +64,21 @@ class LetterCommandService(
return VerifyLetterAccessibleUsecase.Response(letterId = sendLetter.id.value)
} ?: throw LetterException.InvalidLetterAccessException()
}

override fun addVerifiedLetter(command: AddLetterUsecase.Command.VerifyLetter) {
val sendLetter = sendLetterManagementPort.getExpiredLetterNotNull(
receiverId = DomainId(command.userId),
letterId = DomainId(command.letterId)
)
val independentLetter = IndependentLetter(
senderId = sendLetter.senderId,
receiverId = DomainId(command.userId),
content = sendLetter.content,
images = sendLetter.images,
templateType = sendLetter.templateType,
receiveDate = sendLetter.createdDate
)
independentLetterManagementPort.save(independentLetter)
sendLetterManagementPort.remove(sendLetter.id)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.asap.application.letter.service

import com.asap.application.letter.exception.LetterException
import com.asap.application.letter.port.`in`.AddLetterUsecase
import com.asap.application.letter.port.`in`.SendLetterUsecase
import com.asap.application.letter.port.`in`.VerifyLetterAccessibleUsecase
import com.asap.application.letter.port.out.IndependentLetterManagementPort
import com.asap.application.letter.port.out.SendLetterManagementPort
import com.asap.application.user.port.out.UserManagementPort
import com.asap.domain.common.DomainId
Expand All @@ -18,19 +20,21 @@ import io.mockk.verify
import java.time.LocalDate


class LetterCommandServiceTest:BehaviorSpec({
class LetterCommandServiceTest : BehaviorSpec({

val mockSendLetterManagementPort = mockk<SendLetterManagementPort>(relaxed=true)
val mockUserManagementPort = mockk<UserManagementPort>(relaxed=true)
val mockSendLetterManagementPort = mockk<SendLetterManagementPort>(relaxed = true)
val mockIndependentLetterManagementPort = mockk<IndependentLetterManagementPort>(relaxed = true)
val mockUserManagementPort = mockk<UserManagementPort>(relaxed = true)

val letterCommandService = LetterCommandService(
mockSendLetterManagementPort,
mockIndependentLetterManagementPort,
mockUserManagementPort
)



given("편지 전송 요청이 들어올 때"){
given("편지 전송 요청이 들어올 때") {
val command = SendLetterUsecase.Command(
userId = "user-id",
receiverName = "receiver-name",
Expand All @@ -39,9 +43,9 @@ class LetterCommandServiceTest:BehaviorSpec({
templateType = 1,
draftId = null
)
`when`("편지 전송 요청을 처리하면"){
`when`("편지 전송 요청을 처리하면") {
val response = letterCommandService.send(command)
then("편지 코드가 생성되고, 편지가 저장되어야 한다"){
then("편지 코드가 생성되고, 편지가 저장되어야 한다") {
response.letterCode shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
Expand All @@ -51,7 +55,7 @@ class LetterCommandServiceTest:BehaviorSpec({
}
}

given("편지 검증 시에"){
given("편지 검증 시에") {
val letterCode = "letter-code"
val verifyCommand = VerifyLetterAccessibleUsecase.Command(
letterCode = letterCode,
Expand All @@ -69,15 +73,15 @@ class LetterCommandServiceTest:BehaviorSpec({
id = DomainId("user-id"),
username = "receiver-name",
profileImage = "profile-image",
permission = UserPermission(true,true,true),
birthday = LocalDate.now()
permission = UserPermission(true, true, true),
birthday = LocalDate.now()
)
every { mockSendLetterManagementPort.verifiedLetter(any(), letterCode) } returns false
every { mockSendLetterManagementPort.getLetterByCodeNotNull(any()) } returns sendLetter
every { mockUserManagementPort.getUserNotNull(any()) } returns mockUser
`when`("이전에 열람한 적이 없고, 수신자 이름과 같다면"){
`when`("이전에 열람한 적이 없고, 수신자 이름과 같다면") {
val response = letterCommandService.verify(verifyCommand)
then("편지 코드가 검증되고, 편지 ID가 반환되어야 한다"){
then("편지 코드가 검증되고, 편지 ID가 반환되어야 한다") {
response.letterId shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
Expand All @@ -87,8 +91,8 @@ class LetterCommandServiceTest:BehaviorSpec({
}

every { mockSendLetterManagementPort.getLetterByCodeNotNull(any()) } throws LetterException.SendLetterNotFoundException()
`when`("코드가 존재하지 않는다면"){
then("예외가 발생해야 한다"){
`when`("코드가 존재하지 않는다면") {
then("예외가 발생해야 한다") {
shouldThrow<LetterException.SendLetterNotFoundException> {
letterCommandService.verify(verifyCommand)
}
Expand All @@ -99,13 +103,13 @@ class LetterCommandServiceTest:BehaviorSpec({
id = DomainId("user-id"),
username = "another-name",
profileImage = "profile-image",
permission = UserPermission(true,true,true),
permission = UserPermission(true, true, true),
birthday = LocalDate.now()
)
every { mockSendLetterManagementPort.getLetterByCodeNotNull(any()) } returns sendLetter
every { mockUserManagementPort.getUserNotNull(any()) } returns anotherUser
`when`("편지의 수신자 이름과 사용자 이름이 다르면"){
then("예외가 발생해야 한다"){
`when`("편지의 수신자 이름과 사용자 이름이 다르면") {
then("예외가 발생해야 한다") {
shouldThrow<LetterException.InvalidLetterAccessException> {
letterCommandService.verify(verifyCommand)
}
Expand All @@ -114,15 +118,44 @@ class LetterCommandServiceTest:BehaviorSpec({

every { mockSendLetterManagementPort.verifiedLetter(any(), letterCode) } returns true
every { mockSendLetterManagementPort.getExpiredLetterNotNull(any(), letterCode) } returns sendLetter
`when`("이전에 열람한 적이 있는 사용자라면"){
`when`("이전에 열람한 적이 있는 사용자라면") {
val response = letterCommandService.verify(verifyCommand)
then("편지 코드가 검증되고, 편지 ID가 반환되어야 한다"){
then("편지 코드가 검증되고, 편지 ID가 반환되어야 한다") {
response.letterId shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
}
}
}
}


given("검증된 편지를 추가할 때") {
val letterId = "letter-id"
val command = AddLetterUsecase.Command.VerifyLetter(letterId, "user-id")
val sendLetter = SendLetter(
id = DomainId(letterId),
receiverName = "receiver-name",
content = "content",
images = emptyList(),
templateType = 1,
senderId = DomainId("sender-id"),
letterCode = "letter-code"
)
every {
mockSendLetterManagementPort.getExpiredLetterNotNull(
any(), any(DomainId::class)
)
} returns sendLetter
`when`("해당 편지가 아직 받지 않은 상태라면") {
letterCommandService.addVerifiedLetter(command)
then("독립 편지로 저장된다.") {
verify {
mockIndependentLetterManagementPort.save(any())
}
verify { mockSendLetterManagementPort.remove(sendLetter.id) }
}
}
}
}) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,16 @@ class LetterMockManager(
"letterId" to sendLetter.id.value
)
}

fun isExistVerifiedLetter(
letterId: String,
userId: String
): Boolean{
return try{
sendLetterManagementPort.getExpiredLetterNotNull(DomainId(userId), DomainId(letterId))
true
}catch (e: Exception){
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,30 @@ interface LetterApi {


@Operation(summary = "편지 수령 처리")
@PostMapping("/receive/indirect")
fun addReceiveLetter(
@RequestBody request: AddIndirectLetterRequest
@PostMapping("/verify/receive")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "편지 수령 처리 성공",
),
ApiResponse(
responseCode = "400",
description = """
LETTER-001 :편지가 존재하지 않음
""",
content = [
Content(
mediaType = "application/json",
schema = Schema(implementation = ExceptionResponse::class)
)
]
)
]
)
fun addVerifiedLetter(
@RequestBody request: AddVerifiedLetterRequest,
@AccessUser userId: String
)

@Operation(summary = "실물 편지 내용 추가")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.asap.bootstrap.letter.controller

import com.asap.application.letter.port.`in`.AddLetterUsecase
import com.asap.application.letter.port.`in`.GetVerifiedLetterUsecase
import com.asap.application.letter.port.`in`.SendLetterUsecase
import com.asap.application.letter.port.`in`.VerifyLetterAccessibleUsecase
Expand All @@ -11,7 +12,8 @@ import org.springframework.web.bind.annotation.RestController
class LetterController(
private val sendLetterUsecase: SendLetterUsecase,
private val verifyLetterAccessibleUsecase: VerifyLetterAccessibleUsecase,
private val getVerifiedLetterUsecase: GetVerifiedLetterUsecase
private val getVerifiedLetterUsecase: GetVerifiedLetterUsecase,
private val addLetterUsecase: AddLetterUsecase
) : LetterApi {
override fun verifyLetter(
request: LetterVerifyRequest,
Expand Down Expand Up @@ -47,8 +49,16 @@ class LetterController(
)
}

override fun addReceiveLetter(request: AddIndirectLetterRequest) {
TODO("Not yet implemented")
override fun addVerifiedLetter(
request: AddVerifiedLetterRequest,
userId: String
) {
addLetterUsecase.addVerifiedLetter(
AddLetterUsecase.Command.VerifyLetter(
letterId = request.letterId,
userId = userId
)
)
}

override fun addAnonymousLetter(request: AddDirectLetterRequest) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.asap.bootstrap.letter.dto

data class AddIndirectLetterRequest(
data class AddVerifiedLetterRequest(
val letterId: String
) {
}
Loading

0 comments on commit 0630e27

Please sign in to comment.