Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.
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 @@ -3,23 +3,18 @@ package com.asap.application.letter.port.`in`
import java.time.LocalDate

interface GetVerifiedLetterUsecase {

fun get(
query: Query
): Response
fun get(query: Query): Response

data class Query(
val letterId: String,
val userId: String
val userId: String,
)

data class Response(
val senderName: String,
val senderName: String?,
val content: String,
val sendDate: LocalDate,
val templateType: Int,
val images: List<String>
val images: List<String>,
)


}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package com.asap.application.letter.port.`in`

interface SendLetterUsecase {
fun send(command: Command): Response

fun send(
command: Command
): Response
fun sendAnonymous(command: AnonymousCommand): Response

data class Command(
val receiverName: String,
val content: String,
val images: List<String>,
val templateType: Int,
val draftId: String?,
val userId: String
val userId: String,
)

data class AnonymousCommand(
val receiverName: String,
val content: String,
val images: List<String>,
val templateType: Int,
)

data class Response(
val letterCode: String
val letterCode: String,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@ class LetterCommandService(
return SendLetterUsecase.Response(letterCode = sendLetter.letterCode!!)
}

override fun sendAnonymous(command: SendLetterUsecase.AnonymousCommand): SendLetterUsecase.Response {
val sendLetter =
SendLetter.createAnonymous(
receiverName = command.receiverName,
content =
LetterContent(
content = command.content,
templateType = command.templateType,
images = command.images.toMutableList(),
),
letterCode =
letterCodeGenerator.generateCode(
content = command.content,
),
)

sendLetterManagementPort.save(sendLetter)

return SendLetterUsecase.Response(letterCode = sendLetter.letterCode!!)
}

override fun verify(command: VerifyLetterAccessibleUsecase.Command): VerifyLetterAccessibleUsecase.Response {
if (sendLetterManagementPort.verifiedLetter(DomainId(command.userId), command.letterCode)) {
val sendLetter =
Expand All @@ -67,15 +88,15 @@ class LetterCommandService(
}

val sendLetter = sendLetterManagementPort.getLetterByCodeNotNull(command.letterCode)
sendLetter
.isSameReceiver {
userManagementPort.getUserNotNull(DomainId(command.userId))
}.takeIf { it }
?.let {
sendLetter.readLetter(DomainId(command.userId))
sendLetterManagementPort.save(sendLetter)
return VerifyLetterAccessibleUsecase.Response(letterId = sendLetter.id.value)
} ?: throw LetterException.InvalidLetterAccessException()
val receiver = userManagementPort.getUserNotNull(DomainId(command.userId))

if (sendLetter.isSameReceiver(receiver)) {
sendLetter.readLetter(DomainId(command.userId))
sendLetterManagementPort.save(sendLetter)
return VerifyLetterAccessibleUsecase.Response(letterId = sendLetter.id.value)
}

throw LetterException.InvalidLetterAccessException()
}

override fun addVerifiedLetter(command: AddLetterUsecase.Command.VerifyLetter) {
Expand All @@ -89,7 +110,10 @@ class LetterCommandService(
sender =
SenderInfo(
senderId = sendLetter.senderId,
senderName = userManagementPort.getUserNotNull(sendLetter.senderId).username,
senderName =
sendLetter.senderId
?.let { userManagementPort.getUserNotNull(it).username }
.orEmpty(),
),
receiver =
ReceiverInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class LetterQueryService(
receiverId = DomainId(query.userId),
letterId = DomainId(query.letterId),
).also {
val sender = userManagementPort.getUserNotNull(it.senderId)
val sender = it.senderId?.let { userManagementPort.getUserNotNull(it) }
return GetVerifiedLetterUsecase.Response(
senderName = sender.username,
senderName = sender?.username,
content = it.content.content,
sendDate = it.createdDate,
templateType = it.content.templateType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ class LetterCommandServiceTest :
}
}

given("익명 편지 전송 요청이 들어올 때") {
val command =
SendLetterUsecase.AnonymousCommand(
receiverName = "receiver-name",
content = "content",
images = emptyList(),
templateType = 1,
)
`when`("익명 편지 전송 요청을 처리하면") {
val response = letterCommandService.sendAnonymous(command)
then("편지 코드가 생성되고, 편지가 저장되어야 한다") {
response.letterCode shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
}
verify { mockSendLetterManagementPort.save(any()) }
}
}
}

given("편지 검증 시에") {
val letterCode = "letter-code"
val mockUser = UserFixture.createUser(username = "receiver-name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class LetterQueryServiceTest :
userId = user.id.value,
)
val mockSendLetter = LetterFixture.generateSendLetter(user.id)
val mockSender = UserFixture.createUser(mockSendLetter.senderId, "sender-name")
val mockSender = UserFixture.createUser(mockSendLetter.senderId!!, "sender-name")
every {
mockSendLetterManagementPort.getReadLetterNotNull(
receiverId = DomainId(query.userId),
Expand Down Expand Up @@ -96,9 +96,10 @@ class LetterQueryServiceTest :
letterId = "letter-id",
userId = "user-id",
)
val space = SpaceFixture.createSpace(
userId = DomainId(query.userId),
)
val space =
SpaceFixture.createSpace(
userId = DomainId(query.userId),
)
val spaceLetter = LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id)
val prevSpaceLetter =
LetterFixture.generateSpaceLetter(receiverId = DomainId(query.userId), spaceId = space.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,7 @@ package com.asap.bootstrap.web.letter.api

import com.asap.bootstrap.common.exception.ExceptionResponse
import com.asap.bootstrap.common.security.annotation.AccessUser
import com.asap.bootstrap.web.letter.dto.AddPhysicalLetterRequest
import com.asap.bootstrap.web.letter.dto.AddVerifiedLetterRequest
import com.asap.bootstrap.web.letter.dto.AllLetterCountResponse
import com.asap.bootstrap.web.letter.dto.DeleteSendLettersRequest
import com.asap.bootstrap.web.letter.dto.GetIndependentLetterDetailResponse
import com.asap.bootstrap.web.letter.dto.GetIndependentLetterSimpleInfo
import com.asap.bootstrap.web.letter.dto.LetterVerifyRequest
import com.asap.bootstrap.web.letter.dto.LetterVerifyResponse
import com.asap.bootstrap.web.letter.dto.ModifyLetterRequest
import com.asap.bootstrap.web.letter.dto.SendLetterDetailResponse
import com.asap.bootstrap.web.letter.dto.SendLetterHistoryResponse
import com.asap.bootstrap.web.letter.dto.SendLetterRequest
import com.asap.bootstrap.web.letter.dto.SendLetterResponse
import com.asap.bootstrap.web.letter.dto.VerifiedLetterInfoResponse
import com.asap.bootstrap.web.letter.dto.*
import com.asap.common.page.ListResponse
import com.asap.common.page.SliceResponse
import io.swagger.v3.oas.annotations.Operation
Expand Down Expand Up @@ -317,4 +304,28 @@ interface LetterApi {
@RequestBody request: DeleteSendLettersRequest,
@AccessUser userId: String,
)

@Operation(summary = "비회원 편지 쓰기")
@PostMapping("/anonymous/send")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "비회원 편지 전송 성공",
content = [
Content(
mediaType = "application/json",
schema = Schema(implementation = SendLetterResponse::class),
),
],
),
ApiResponse(
responseCode = "4XX",
description = "비회원 편지 전송 실패",
),
],
)
fun sendAnonymousLetter(
@RequestBody request: AnonymousSendLetterRequest,
): SendLetterResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,19 @@ class LetterController(
),
)
}

override fun sendAnonymousLetter(request: AnonymousSendLetterRequest): SendLetterResponse {
val response =
sendLetterUsecase.sendAnonymous(
SendLetterUsecase.AnonymousCommand(
receiverName = request.receiverName,
content = request.content,
images = request.images,
templateType = request.templateType,
),
)
return SendLetterResponse(
letterCode = response.letterCode,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.asap.bootstrap.web.letter.dto

data class AnonymousSendLetterRequest(
val receiverName: String,
val content: String,
val images: List<String>,
val templateType: Int,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ package com.asap.bootstrap.web.letter.dto
import java.time.LocalDate

data class VerifiedLetterInfoResponse(
val senderName: String,
val senderName: String?,
val content: String,
val date: LocalDate,
val templateType: Int,
val images: List<String>
) {
}
val images: List<String>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class DraftLetterEventHandler(
event.draftId?.let {
removeDraftLetterUsecase.deleteBy(
RemoveDraftLetterUsecase.Command.Send(
userId = event.sendLetter.senderId.value,
userId = event.sendLetter.senderId!!.value,
draftId = it,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,4 +589,41 @@ class LetterControllerTest : LetterAcceptanceSupporter() {
}
}
}
@Test
fun sendAnonymousLetter() {
// given
val request =
AnonymousSendLetterRequest(
receiverName = "receiverName",
content = "content",
images = listOf("images"),
templateType = 1,
)
BDDMockito
.given(
sendLetterUsecase.sendAnonymous(
SendLetterUsecase.AnonymousCommand(
receiverName = request.receiverName,
content = request.content,
images = request.images,
templateType = request.templateType,
),
),
).willReturn(SendLetterUsecase.Response("letterCode"))
// when
val response =
mockMvc.post("/api/v1/letters/anonymous/send") {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(request)
}
// then
response.andExpect {
status { isOk() }
jsonPath("$.letterCode") {
exists()
isString()
isNotEmpty()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1081,4 +1081,32 @@ class LetterApiIntegrationTest : IntegrationSupporter() {
}
}
}

@Test
@DisplayName("비회원 편지 쓰기")
fun sendAnonymousLetter() {
// given
val request =
AnonymousSendLetterRequest(
receiverName = "receiverName",
content = "content",
images = listOf("images"),
templateType = 1,
)
// when
val response =
mockMvc.post("/api/v1/letters/anonymous/send") {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(request)
}
// then
response.andExpect {
status { isOk() }
jsonPath("$.letterCode") {
exists()
isString()
isNotEmpty()
}
}
}
}
Loading