Skip to content

Commit

Permalink
Merge pull request #110 from ASAP-Lettering/ASAP-388
Browse files Browse the repository at this point in the history
ASAP-388 실물 편지 임시 저장을 위한 키 발급 api 추가
  • Loading branch information
tlarbals824 authored Jan 23, 2025
2 parents 3b6c60b + 005f530 commit 7f5159a
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package com.asap.application.letter.port.`in`

interface GenerateDraftKeyUsecase {
fun command(command: Command): Response
fun command(command: Command.Send): Response

data class Command(
val userId: String,
)
fun command(command: Command.Physical): Response

sealed class Command {
data class Send(
val userId: String,
): Command()

data class Physical(
val userId: String,
): Command()
}

data class Response(
val draftId: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.asap.application.letter.port.out

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

interface ReceiveDraftLetterManagementPort {
fun save(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetter
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,33 @@ import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
import com.asap.application.letter.port.`in`.RemoveDraftLetterUsecase
import com.asap.application.letter.port.`in`.UpdateDraftLetterUsecase
import com.asap.application.letter.port.out.DraftLetterManagementPort
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 org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional
class DraftLetterCommandService(
private val draftLetterManagementPort: DraftLetterManagementPort,
private val receiveDraftLetterManagementPort: ReceiveDraftLetterManagementPort,
) : GenerateDraftKeyUsecase,
UpdateDraftLetterUsecase,
RemoveDraftLetterUsecase {
override fun command(command: GenerateDraftKeyUsecase.Command): GenerateDraftKeyUsecase.Response {
override fun command(command: GenerateDraftKeyUsecase.Command.Send): GenerateDraftKeyUsecase.Response {
val draftLetter = DraftLetter.default(DomainId(command.userId))
draftLetterManagementPort.save(draftLetter)
return GenerateDraftKeyUsecase.Response(draftLetter.id.value)
}

override fun command(command: GenerateDraftKeyUsecase.Command.Physical): GenerateDraftKeyUsecase.Response {
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(command.userId))
receiveDraftLetterManagementPort.save(receiveDraftLetter)
return GenerateDraftKeyUsecase.Response(receiveDraftLetter.id.value)
}

override fun command(command: UpdateDraftLetterUsecase.Command) {
val draftLetter =
draftLetterManagementPort.getDraftLetterNotNull(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import com.asap.application.letter.port.`in`.GenerateDraftKeyUsecase
import com.asap.application.letter.port.`in`.RemoveDraftLetterUsecase
import com.asap.application.letter.port.`in`.UpdateDraftLetterUsecase
import com.asap.application.letter.port.out.DraftLetterManagementPort
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.style.BehaviorSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import io.mockk.every
Expand All @@ -16,14 +18,16 @@ class DraftLetterCommandServiceTest :
BehaviorSpec({

val mockGenerateDraftKeyUsecase = mockk<DraftLetterManagementPort>(relaxed = true)
val draftLetterCommandService = DraftLetterCommandService(mockGenerateDraftKeyUsecase)
val mockReceiveDraftLetterManagementPort = mockk<ReceiveDraftLetterManagementPort>(relaxed = true)
val draftLetterCommandService =
DraftLetterCommandService(mockGenerateDraftKeyUsecase, mockReceiveDraftLetterManagementPort)

given("임시 저장 키를 발급할 때") {
val userId = "userId"
val draftLetter = DraftLetter.default(DomainId(userId))
every { mockGenerateDraftKeyUsecase.save(any()) } returns draftLetter
`when`("사용자 아이디를 입력하면") {
val response = draftLetterCommandService.command(GenerateDraftKeyUsecase.Command(userId))
val response = draftLetterCommandService.command(GenerateDraftKeyUsecase.Command.Send(userId))
then("임시 저장 키를 발급한다") {
response.draftId.shouldNotBeNull()
}
Expand Down Expand Up @@ -70,4 +74,16 @@ class DraftLetterCommandServiceTest :
}
}
}

given("받은 편지를 임시저장하려 할때"){
val command = GenerateDraftKeyUsecase.Command.Physical("userId")
val receiveDraftLetter = ReceiveDraftLetter.default(DomainId(command.userId))
every { mockReceiveDraftLetterManagementPort.save(any()) } returns receiveDraftLetter
`when`("사용자 아이디를 입력하면"){
val response = draftLetterCommandService.command(command)
then("받은 편지를 임시저장한다"){
response.draftId.shouldNotBeNull()
}
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ interface DraftLetterApi {
@AccessUser userId: String,
): GenerateDraftKeyResponse

@Operation(summary = "실물 편지 임시 저장 키 발급")
@PostMapping("/physical/key")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "임시 저장 키 발급 성공",
content = [
Content(
schema =
Schema(implementation = GenerateDraftKeyResponse::class),
),
],
),
],
)
fun getPhysicalDraftKey(
@AccessUser userId: String,
): GenerateDraftKeyResponse

@Operation(summary = "임시 저장하기")
@PostMapping("/{draftId}")
@ApiResponses(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ class DraftLetterController(
private val removeDraftLetterUsecase: RemoveDraftLetterUsecase,
) : DraftLetterApi {
override fun getDraftKey(userId: String): GenerateDraftKeyResponse {
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command(userId))
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Send(userId))
return GenerateDraftKeyResponse(response.draftId)
}

override fun getPhysicalDraftKey(userId: String): GenerateDraftKeyResponse {
val response = generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Physical(userId))
return GenerateDraftKeyResponse(response.draftId)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class DraftLetterControllerTest : LetterAcceptanceSupporter() {
val accessToken = jwtMockManager.generateAccessToken(userId)

BDDMockito
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command(userId)))
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Send(userId)))
.willReturn(GenerateDraftKeyUsecase.Response("draftId"))

// when
Expand Down Expand Up @@ -180,4 +180,28 @@ class DraftLetterControllerTest : LetterAcceptanceSupporter() {
status { isOk() }
}
}


@Test
fun `get physical draft key`() {
// given
val userId = userMockManager.settingUser()
val accessToken = jwtMockManager.generateAccessToken(userId)

BDDMockito
.given(generateDraftKeyUsecase.command(GenerateDraftKeyUsecase.Command.Physical(userId)))
.willReturn(GenerateDraftKeyUsecase.Response("draftId"))

// when
val response =
mockMvc.post("/api/v1/letters/drafts/physical/key") {
header("Authorization", "Bearer $accessToken")
}

// then
response.andExpect {
status { isOk() }
jsonPath("$.draftId") { isString() }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,22 @@ class DraftLetterApiIntegrationTest : IntegrationSupporter() {
status { isOk() }
}
}

@Test
fun `get physical draft key`() {
// given
val userId = userMockManager.settingUser()
val accessToken = jwtMockManager.generateAccessToken(userId)
// when
val response =
mockMvc.post("/api/v1/letters/drafts/physical/key") {
header("Authorization", "Bearer $accessToken")
}

// then
response.andExpect {
status { isOk() }
jsonPath("$.draftId") { isString() }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.asap.domain.letter.entity

import com.asap.domain.common.BaseEntity
import com.asap.domain.common.DomainId
import java.time.LocalDateTime

class ReceiveDraftLetter(
id: DomainId,
var content: String,
var senderName: String,
val ownerId: DomainId,
var images: List<String>,
var lastUpdated: LocalDateTime = LocalDateTime.now(),
val type: ReceiveDraftLetterType,
) : BaseEntity() {
companion object {
fun default(ownerId: DomainId) =
ReceiveDraftLetter(
id = DomainId.generate(),
ownerId = ownerId,
content = "",
senderName = "",
images = emptyList(),
type = ReceiveDraftLetterType.PHYSICAL,
)
}

fun update(
content: String,
senderName: String,
images: List<String>,
) {
this.content = content
this.senderName = senderName
this.images = images
this.lastUpdated = LocalDateTime.now()
}
}

enum class ReceiveDraftLetterType{
PHYSICAL,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.asap.persistence.jpa.letter

import com.asap.domain.common.DomainId
import com.asap.domain.letter.entity.ReceiveDraftLetter
import com.asap.persistence.jpa.letter.entity.ReceiveDraftLetterEntity

object ReceiveDraftLetterMapper {
fun toEntity(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetterEntity =
ReceiveDraftLetterEntity(
id = receiveDraftLetter.id.value,
content = receiveDraftLetter.content,
senderName = receiveDraftLetter.senderName,
ownerId = receiveDraftLetter.ownerId.value,
images = receiveDraftLetter.images,
updatedAt = receiveDraftLetter.lastUpdated,
type = receiveDraftLetter.type,
)

fun toDomain(receiveDraftLetterEntity: ReceiveDraftLetterEntity): ReceiveDraftLetter =
ReceiveDraftLetter(
id = DomainId(receiveDraftLetterEntity.id),
content = receiveDraftLetterEntity.content,
senderName = receiveDraftLetterEntity.senderName,
ownerId = DomainId(receiveDraftLetterEntity.ownerId),
images = receiveDraftLetterEntity.images,
lastUpdated = receiveDraftLetterEntity.updatedAt,
type = receiveDraftLetterEntity.type,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.asap.persistence.jpa.letter.adapter

import com.asap.application.letter.port.out.ReceiveDraftLetterManagementPort
import com.asap.domain.letter.entity.ReceiveDraftLetter
import com.asap.persistence.jpa.letter.ReceiveDraftLetterMapper
import com.asap.persistence.jpa.letter.repository.ReceiveDraftLetterJpaRepository
import org.springframework.stereotype.Repository

@Repository
class ReceiveDraftLetterManagementJpaAdapter(
private val receiveDraftLetterJpaRepository: ReceiveDraftLetterJpaRepository,
) : ReceiveDraftLetterManagementPort {
override fun save(receiveDraftLetter: ReceiveDraftLetter): ReceiveDraftLetter {
val receiveDraftLetterEntity = ReceiveDraftLetterMapper.toEntity(receiveDraftLetter)
return receiveDraftLetterJpaRepository.save(receiveDraftLetterEntity)
.let { ReceiveDraftLetterMapper.toDomain(it) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.asap.persistence.jpa.letter.entity

import com.asap.domain.letter.entity.ReceiveDraftLetterType
import com.asap.persistence.jpa.common.BaseEntity
import com.asap.persistence.jpa.user.entity.UserEntity
import jakarta.persistence.*
import org.hibernate.annotations.JdbcTypeCode
import org.hibernate.type.SqlTypes
import java.time.LocalDateTime

@Entity
@Table(
name = "receive_draft_letters"
)
class ReceiveDraftLetterEntity(
id: String,
content: String,
senderName: String,
ownerId: String,
images: List<String>,
updatedAt: LocalDateTime,
type: ReceiveDraftLetterType
) : BaseEntity(id) {

var content: String = content
var senderName: String = senderName

@Column(
name = "owner_id",
nullable = false,
)
var ownerId: String = ownerId

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "owner_id",
insertable = false,
updatable = false,
)
lateinit var owner: UserEntity

@JdbcTypeCode(SqlTypes.JSON)
@Column(
name = "images",
nullable = false,
columnDefinition = "text",
)
var images: List<String> = images

override var updatedAt: LocalDateTime = updatedAt

@Enumerated(EnumType.STRING)
@Column(
name = "type",
nullable = false,
columnDefinition = "VARCHAR(20)",
)
var type: ReceiveDraftLetterType = type

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.asap.persistence.jpa.letter.repository

import com.asap.persistence.jpa.letter.entity.ReceiveDraftLetterEntity
import org.springframework.data.jpa.repository.JpaRepository

interface ReceiveDraftLetterJpaRepository : JpaRepository<ReceiveDraftLetterEntity, String>{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE TABLE receive_draft_letters
(
id VARCHAR(255) NOT NULL,
created_at datetime NULL,
updated_at datetime NULL,
content VARCHAR(255) NULL,
sender_name VARCHAR(255) NULL,
owner_id VARCHAR(255) NOT NULL,
images TEXT NOT NULL,
type VARCHAR(20) NOT NULL,
CONSTRAINT pk_receive_draft_letters PRIMARY KEY (id)
);

ALTER TABLE receive_draft_letters
ADD CONSTRAINT FK_RECEIVE_DRAFT_LETTERS_ON_OWNER FOREIGN KEY (owner_id) REFERENCES user (id);

0 comments on commit 7f5159a

Please sign in to comment.