Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Commit 7f5159a

Browse files
authored
Merge pull request #110 from ASAP-Lettering/ASAP-388
ASAP-388 실물 편지 임시 저장을 위한 키 발급 api 추가
2 parents 3b6c60b + 005f530 commit 7f5159a

14 files changed

Lines changed: 287 additions & 9 deletions

File tree

Application-Module/src/main/kotlin/com/asap/application/letter/port/in/GenerateDraftKeyUsecase.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
package com.asap.application.letter.port.`in`
22

33
interface GenerateDraftKeyUsecase {
4-
fun command(command: Command): Response
4+
fun command(command: Command.Send): Response
55

6-
data class Command(
7-
val userId: String,
8-
)
6+
fun command(command: Command.Physical): Response
7+
8+
sealed class Command {
9+
data class Send(
10+
val userId: String,
11+
): Command()
12+
13+
data class Physical(
14+
val userId: String,
15+
): Command()
16+
}
917

1018
data class Response(
1119
val draftId: String,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.asap.application.letter.port.out
2+
3+
import com.asap.domain.letter.entity.ReceiveDraftLetter
4+
5+
interface ReceiveDraftLetterManagementPort {
6+
fun save(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetter
7+
}

Application-Module/src/main/kotlin/com/asap/application/letter/service/DraftLetterCommandService.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,33 @@ import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
44
import com.asap.application.letter.port.`in`.RemoveDraftLetterUsecase
55
import com.asap.application.letter.port.`in`.UpdateDraftLetterUsecase
66
import com.asap.application.letter.port.out.DraftLetterManagementPort
7+
import com.asap.application.letter.port.out.ReceiveDraftLetterManagementPort
78
import com.asap.domain.common.DomainId
89
import com.asap.domain.letter.entity.DraftLetter
10+
import com.asap.domain.letter.entity.ReceiveDraftLetter
911
import org.springframework.stereotype.Service
1012
import org.springframework.transaction.annotation.Transactional
1113

1214
@Service
1315
@Transactional
1416
class DraftLetterCommandService(
1517
private val draftLetterManagementPort: DraftLetterManagementPort,
18+
private val receiveDraftLetterManagementPort: ReceiveDraftLetterManagementPort,
1619
) : GenerateDraftKeyUsecase,
1720
UpdateDraftLetterUsecase,
1821
RemoveDraftLetterUsecase {
19-
override fun command(command: GenerateDraftKeyUsecase.Command): GenerateDraftKeyUsecase.Response {
22+
override fun command(command: GenerateDraftKeyUsecase.Command.Send): GenerateDraftKeyUsecase.Response {
2023
val draftLetter = DraftLetter.default(DomainId(command.userId))
2124
draftLetterManagementPort.save(draftLetter)
2225
return GenerateDraftKeyUsecase.Response(draftLetter.id.value)
2326
}
2427

28+
override fun command(command: GenerateDraftKeyUsecase.Command.Physical): GenerateDraftKeyUsecase.Response {
29+
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(command.userId))
30+
receiveDraftLetterManagementPort.save(receiveDraftLetter)
31+
return GenerateDraftKeyUsecase.Response(receiveDraftLetter.id.value)
32+
}
33+
2534
override fun command(command: UpdateDraftLetterUsecase.Command) {
2635
val draftLetter =
2736
draftLetterManagementPort.getDraftLetterNotNull(

Application-Module/src/test/kotlin/com/asap/application/letter/service/DraftLetterCommandServiceTest.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
44
import com.asap.application.letter.port.`in`.RemoveDraftLetterUsecase
55
import com.asap.application.letter.port.`in`.UpdateDraftLetterUsecase
66
import com.asap.application.letter.port.out.DraftLetterManagementPort
7+
import com.asap.application.letter.port.out.ReceiveDraftLetterManagementPort
78
import com.asap.domain.common.DomainId
89
import com.asap.domain.letter.entity.DraftLetter
10+
import com.asap.domain.letter.entity.ReceiveDraftLetter
911
import io.kotest.core.spec.style.BehaviorSpec
1012
import io.kotest.matchers.nulls.shouldNotBeNull
1113
import io.mockk.every
@@ -16,14 +18,16 @@ class DraftLetterCommandServiceTest :
1618
BehaviorSpec({
1719

1820
val mockGenerateDraftKeyUsecase = mockk<DraftLetterManagementPort>(relaxed = true)
19-
val draftLetterCommandService = DraftLetterCommandService(mockGenerateDraftKeyUsecase)
21+
val mockReceiveDraftLetterManagementPort = mockk<ReceiveDraftLetterManagementPort>(relaxed = true)
22+
val draftLetterCommandService =
23+
DraftLetterCommandService(mockGenerateDraftKeyUsecase, mockReceiveDraftLetterManagementPort)
2024

2125
given("임시 저장 키를 발급할 때") {
2226
val userId = "userId"
2327
val draftLetter = DraftLetter.default(DomainId(userId))
2428
every { mockGenerateDraftKeyUsecase.save(any()) } returns draftLetter
2529
`when`("사용자 아이디를 입력하면") {
26-
val response = draftLetterCommandService.command(GenerateDraftKeyUsecase.Command(userId))
30+
val response = draftLetterCommandService.command(GenerateDraftKeyUsecase.Command.Send(userId))
2731
then("임시 저장 키를 발급한다") {
2832
response.draftId.shouldNotBeNull()
2933
}
@@ -70,4 +74,16 @@ class DraftLetterCommandServiceTest :
7074
}
7175
}
7276
}
77+
78+
given("받은 편지를 임시저장하려 할때"){
79+
val command = GenerateDraftKeyUsecase.Command.Physical("userId")
80+
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(command.userId))
81+
every { mockReceiveDraftLetterManagementPort.save(any()) } returns receiveDraftLetter
82+
`when`("사용자 아이디를 입력하면"){
83+
val response = draftLetterCommandService.command(command)
84+
then("받은 편지를 임시저장한다"){
85+
response.draftId.shouldNotBeNull()
86+
}
87+
}
88+
}
7389
})

Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/letter/api/DraftLetterApi.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ interface DraftLetterApi {
3131
@AccessUser userId: String,
3232
): GenerateDraftKeyResponse
3333

34+
@Operation(summary = "실물 편지 임시 저장 키 발급")
35+
@PostMapping("/physical/key")
36+
@ApiResponses(
37+
value = [
38+
ApiResponse(
39+
responseCode = "200",
40+
description = "임시 저장 키 발급 성공",
41+
content = [
42+
Content(
43+
schema =
44+
Schema(implementation = GenerateDraftKeyResponse::class),
45+
),
46+
],
47+
),
48+
],
49+
)
50+
fun getPhysicalDraftKey(
51+
@AccessUser userId: String,
52+
): GenerateDraftKeyResponse
53+
3454
@Operation(summary = "임시 저장하기")
3555
@PostMapping("/{draftId}")
3656
@ApiResponses(

Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/letter/controller/DraftLetterController.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ class DraftLetterController(
1616
private val removeDraftLetterUsecase: RemoveDraftLetterUsecase,
1717
) : DraftLetterApi {
1818
override fun getDraftKey(userId: String): GenerateDraftKeyResponse {
19-
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command(userId))
19+
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Send(userId))
20+
return GenerateDraftKeyResponse(response.draftId)
21+
}
22+
23+
override fun getPhysicalDraftKey(userId: String): GenerateDraftKeyResponse {
24+
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Physical(userId))
2025
return GenerateDraftKeyResponse(response.draftId)
2126
}
2227

Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/letter/controller/DraftLetterControllerTest.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class DraftLetterControllerTest : LetterAcceptanceSupporter() {
2020
val accessToken = jwtMockManager.generateAccessToken(userId)
2121

2222
BDDMockito
23-
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command(userId)))
23+
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Send(userId)))
2424
.willReturn(GenerateDraftKeyUsecase.Response("draftId"))
2525

2626
// when
@@ -180,4 +180,28 @@ class DraftLetterControllerTest : LetterAcceptanceSupporter() {
180180
status { isOk() }
181181
}
182182
}
183+
184+
185+
@Test
186+
fun `get physical draft key`() {
187+
// given
188+
val userId = userMockManager.settingUser()
189+
val accessToken = jwtMockManager.generateAccessToken(userId)
190+
191+
BDDMockito
192+
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Physical(userId)))
193+
.willReturn(GenerateDraftKeyUsecase.Response("draftId"))
194+
195+
// when
196+
val response =
197+
mockMvc.post("/api/v1/letters/drafts/physical/key") {
198+
header("Authorization", "Bearer $accessToken")
199+
}
200+
201+
// then
202+
response.andExpect {
203+
status { isOk() }
204+
jsonPath("$.draftId") { isString() }
205+
}
206+
}
183207
}

Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/letter/DraftLetterApiIntegrationTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,22 @@ class DraftLetterApiIntegrationTest : IntegrationSupporter() {
142142
status { isOk() }
143143
}
144144
}
145+
146+
@Test
147+
fun `get physical draft key`() {
148+
// given
149+
val userId = userMockManager.settingUser()
150+
val accessToken = jwtMockManager.generateAccessToken(userId)
151+
// when
152+
val response =
153+
mockMvc.post("/api/v1/letters/drafts/physical/key") {
154+
header("Authorization", "Bearer $accessToken")
155+
}
156+
157+
// then
158+
response.andExpect {
159+
status { isOk() }
160+
jsonPath("$.draftId") { isString() }
161+
}
162+
}
145163
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.asap.domain.letter.entity
2+
3+
import com.asap.domain.common.BaseEntity
4+
import com.asap.domain.common.DomainId
5+
import java.time.LocalDateTime
6+
7+
class ReceiveDraftLetter(
8+
id: DomainId,
9+
var content: String,
10+
var senderName: String,
11+
val ownerId: DomainId,
12+
var images: List<String>,
13+
var lastUpdated: LocalDateTime = LocalDateTime.now(),
14+
val type: ReceiveDraftLetterType,
15+
) : BaseEntity() {
16+
companion object {
17+
fun default(ownerId: DomainId) =
18+
ReceiveDraftLetter(
19+
id = DomainId.generate(),
20+
ownerId = ownerId,
21+
content = "",
22+
senderName = "",
23+
images = emptyList(),
24+
type = ReceiveDraftLetterType.PHYSICAL,
25+
)
26+
}
27+
28+
fun update(
29+
content: String,
30+
senderName: String,
31+
images: List<String>,
32+
) {
33+
this.content = content
34+
this.senderName = senderName
35+
this.images = images
36+
this.lastUpdated = LocalDateTime.now()
37+
}
38+
}
39+
40+
enum class ReceiveDraftLetterType{
41+
PHYSICAL,
42+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.asap.persistence.jpa.letter
2+
3+
import com.asap.domain.common.DomainId
4+
import com.asap.domain.letter.entity.ReceiveDraftLetter
5+
import com.asap.persistence.jpa.letter.entity.ReceiveDraftLetterEntity
6+
7+
object ReceiveDraftLetterMapper {
8+
fun toEntity(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetterEntity =
9+
ReceiveDraftLetterEntity(
10+
id = receiveDraftLetter.id.value,
11+
content = receiveDraftLetter.content,
12+
senderName = receiveDraftLetter.senderName,
13+
ownerId = receiveDraftLetter.ownerId.value,
14+
images = receiveDraftLetter.images,
15+
updatedAt = receiveDraftLetter.lastUpdated,
16+
type = receiveDraftLetter.type,
17+
)
18+
19+
fun toDomain(receiveDraftLetterEntity: ReceiveDraftLetterEntity): ReceiveDraftLetter =
20+
ReceiveDraftLetter(
21+
id = DomainId(receiveDraftLetterEntity.id),
22+
content = receiveDraftLetterEntity.content,
23+
senderName = receiveDraftLetterEntity.senderName,
24+
ownerId = DomainId(receiveDraftLetterEntity.ownerId),
25+
images = receiveDraftLetterEntity.images,
26+
lastUpdated = receiveDraftLetterEntity.updatedAt,
27+
type = receiveDraftLetterEntity.type,
28+
)
29+
}

0 commit comments

Comments
 (0)