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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ out/

### Kotlin ###
.kotlin

### claude ###
CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface SendLetterUsecase {
)

data class AnonymousCommand(
val senderName: String? = null,
val receiverName: String,
val content: String,
val images: List<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class LetterCommandService(
letterCodeGenerator.generateCode(
content = command.content,
),
senderName = command.senderName ?: ANONYMOUS_SENDER_NAME,
)

sendLetterManagementPort.save(sendLetter)
Expand Down Expand Up @@ -111,9 +112,10 @@ class LetterCommandService(
SenderInfo(
senderId = sendLetter.senderId,
senderName =
sendLetter.senderId
?.let { userManagementPort.getUserNotNull(it).username }
.orEmpty(),
sendLetter.senderName
?: sendLetter.senderId
?.let { userManagementPort.getUserNotNull(it).username }
.orEmpty(),
),
receiver =
ReceiverInfo(
Expand Down Expand Up @@ -273,4 +275,8 @@ class LetterCommandService(
)
spaceLetterManagementPort.save(spaceLetter)
}

companion object {
private const val ANONYMOUS_SENDER_NAME = "Anonymous"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,52 @@ class LetterCommandServiceTest :
verify { mockSendLetterManagementPort.save(any()) }
}
}

val commandWithSenderName =
SendLetterUsecase.AnonymousCommand(
senderName = "Test Sender",
receiverName = "receiver-name",
content = "content",
images = emptyList(),
templateType = 1,
)
`when`("발송자 이름이 제공된 익명 편지 전송 요청을 처리하면") {
val response = letterCommandService.sendAnonymous(commandWithSenderName)
then("편지 코드가 생성되고, 제공된 발송자 이름으로 편지가 저장되어야 한다") {
response.letterCode shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
}
verify {
mockSendLetterManagementPort.save(match { sendLetter ->
sendLetter.senderName == "Test Sender"
})
}
}
}

val commandWithNullSenderName =
SendLetterUsecase.AnonymousCommand(
senderName = null,
receiverName = "receiver-name",
content = "content",
images = emptyList(),
templateType = 1,
)
`when`("발송자 이름이 null인 익명 편지 전송 요청을 처리하면") {
val response = letterCommandService.sendAnonymous(commandWithNullSenderName)
then("편지 코드가 생성되고, Anonymous로 편지가 저장되어야 한다") {
response.letterCode shouldNotBeNull {
this.isNotBlank()
this.isNotEmpty()
}
verify {
mockSendLetterManagementPort.save(match { sendLetter ->
sendLetter.senderName == "Anonymous"
})
}
}
}
}

given("편지 검증 시에") {
Expand Down Expand Up @@ -381,6 +427,7 @@ class LetterCommandServiceTest :
content = content,
receiverName = "receiverName",
letterCode = letterCode,
senderName = "Anonymous",
)

every {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ class LetterController(
val response =
sendLetterUsecase.sendAnonymous(
SendLetterUsecase.AnonymousCommand(
senderName = request.senderName,
receiverName = request.receiverName,
content = request.content,
images = request.images,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.asap.bootstrap.web.letter.dto

data class AnonymousSendLetterRequest(
val senderName: String? = null,
val receiverName: String,
val content: String,
val images: List<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,84 @@ class LetterControllerTest : LetterAcceptanceSupporter() {
}
}
}

@Test
fun sendAnonymousLetterWithSenderName() {
// given
val request =
AnonymousSendLetterRequest(
senderName = "Test Sender",
receiverName = "receiverName",
content = "content",
images = listOf("images"),
templateType = 1,
)
BDDMockito
.given(
sendLetterUsecase.sendAnonymous(
SendLetterUsecase.AnonymousCommand(
senderName = request.senderName,
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()
}
}
}

@Test
fun sendAnonymousLetterWithNullSenderName() {
// given
val request =
AnonymousSendLetterRequest(
senderName = null,
receiverName = "receiverName",
content = "content",
images = listOf("images"),
templateType = 1,
)
BDDMockito
.given(
sendLetterUsecase.sendAnonymous(
SendLetterUsecase.AnonymousCommand(
senderName = null,
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 @@ -3,7 +3,13 @@ package com.asap.bootstrap.integration.letter
import com.asap.application.letter.LetterMockManager
import com.asap.application.space.SpaceMockManager
import com.asap.bootstrap.IntegrationSupporter
import com.asap.bootstrap.web.letter.dto.*
import com.asap.bootstrap.web.letter.dto.AddPhysicalLetterRequest
import com.asap.bootstrap.web.letter.dto.AddVerifiedLetterRequest
import com.asap.bootstrap.web.letter.dto.AnonymousSendLetterRequest
import com.asap.bootstrap.web.letter.dto.DeleteSendLettersRequest
import com.asap.bootstrap.web.letter.dto.LetterVerifyRequest
import com.asap.bootstrap.web.letter.dto.ModifyLetterRequest
import com.asap.bootstrap.web.letter.dto.SendLetterRequest
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -1082,30 +1088,92 @@ 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)
@Nested
@DisplayName("익명 편지 전송")
inner class SendAnonymousLetter {
@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()
}
}
// then
response.andExpect {
status { isOk() }
jsonPath("$.letterCode") {
exists()
isString()
isNotEmpty()
}

@Test
@DisplayName("발송자 이름과 함께 익명 편지 전송")
fun sendAnonymousLetterWithSenderName() {
// given
val request =
AnonymousSendLetterRequest(
senderName = "Test Sender",
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()
}
}
}

@Test
@DisplayName("발송자 이름이 null인 익명 편지 전송")
fun sendAnonymousLetterWithNullSenderName() {
// given
val request =
AnonymousSendLetterRequest(
senderName = null,
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()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class UserApiIntegrationTest(
content = letterContent,
receiverName = receiverName,
letterCode = "test-letter-code",
status = LetterStatus.SENDING,
senderName = "Anonymous",
)
sendLetterManagementPort.save(anonymousSendLetter)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class SendLetter(
id: DomainId,
val content: LetterContent,
var senderId: DomainId?,
var senderName: String?,
var receiverName: String,
var letterCode: String?,
var status: LetterStatus,
Expand All @@ -37,6 +38,7 @@ class SendLetter(
id = DomainId.generate(),
content = content,
senderId = senderId,
senderName = null,
receiverName = receiverName,
letterCode = letterCode,
status = status,
Expand All @@ -51,6 +53,7 @@ class SendLetter(
content: LetterContent,
receiverName: String,
letterCode: String?,
senderName: String,
status: LetterStatus = LetterStatus.SENDING,
receiverId: DomainId? = null,
createdAt: LocalDateTime = LocalDateTime.now(),
Expand All @@ -60,6 +63,7 @@ class SendLetter(
id = DomainId.generate(),
content = content,
senderId = null,
senderName = senderName,
receiverName = receiverName,
letterCode = letterCode,
status = status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object SendLetterMapper {
receiverName = sendLetterEntity.receiverName,
letterCode = sendLetterEntity.letterCode ?: "",
senderId = sendLetterEntity.senderId?.let { DomainId(it) },
senderName = sendLetterEntity.senderName,
receiverId = sendLetterEntity.receiverId?.let { DomainId(it) },
status = sendLetterEntity.letterStatus,
createdAt = sendLetterEntity.createdAt,
Expand All @@ -32,6 +33,7 @@ object SendLetterMapper {
templateType = sendLetter.content.templateType,
receiverName = sendLetter.receiverName,
senderId = sendLetter.senderId?.value,
senderName = sendLetter.senderName,
letterCode = sendLetter.letterCode,
receiverId = sendLetter.receiverId?.value,
letterStatus = sendLetter.status,
Expand Down
Loading