Skip to content

Commit 8262750

Browse files
committed
fix: 만남 초대장 생성과 모임 등록 로직 합침
1 parent 7abd691 commit 8262750

File tree

6 files changed

+113
-39
lines changed

6 files changed

+113
-39
lines changed

tuk-api/src/main/kotlin/nexters/tuk/application/proposal/ProposalCreateService.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package nexters.tuk.application.proposal
22

3+
import nexters.tuk.application.gathering.GatheringProposalService
4+
import nexters.tuk.application.gathering.dto.request.GatheringProposalCommand
35
import nexters.tuk.application.proposal.dto.request.ProposalCommand
46
import nexters.tuk.application.proposal.dto.response.ProposalResponse
57
import org.springframework.stereotype.Service
@@ -8,11 +10,23 @@ import org.springframework.transaction.annotation.Transactional
810
@Service
911
class ProposalCreateService(
1012
private val proposalService: ProposalService,
13+
private val gatheringProposalService: GatheringProposalService,
1114
) {
15+
1216
@Transactional
1317
fun propose(command: ProposalCommand.Propose): ProposalResponse.Propose {
1418
val proposal = proposalService.propose(command)
1519

20+
if (command.gatheringId != null) {
21+
gatheringProposalService.addProposal(
22+
GatheringProposalCommand.AddProposal(
23+
memberId = command.memberId,
24+
gatheringId = command.gatheringId,
25+
proposalId = proposal.proposalId
26+
)
27+
)
28+
}
29+
1630
return ProposalResponse.Propose(proposalId = proposal.proposalId)
1731
}
1832
}

tuk-api/src/main/kotlin/nexters/tuk/application/proposal/dto/request/ProposalCommand.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import nexters.tuk.application.proposal.vo.ProposalPurposeInfo
55
class ProposalCommand {
66
data class Propose(
77
val memberId: Long,
8-
val purpose: ProposalPurposeInfo
8+
val gatheringId: Long?,
9+
val purpose: ProposalPurposeInfo,
910
)
1011
}

tuk-api/src/main/kotlin/nexters/tuk/ui/gathering/GatheringProposalController.kt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package nexters.tuk.ui.gathering
22

3-
import nexters.tuk.application.gathering.GatheringProposalService
43
import nexters.tuk.application.proposal.ProposalDirection
54
import nexters.tuk.application.proposal.ProposalQueryService
65
import nexters.tuk.application.proposal.dto.request.ProposalQuery
@@ -16,7 +15,6 @@ import org.springframework.web.bind.annotation.*
1615
@RequestMapping("/api/v1/gatherings/{gatheringId}/proposals")
1716
class GatheringProposalController(
1817
private val proposalQueryService: ProposalQueryService,
19-
private val gatheringProposalService: GatheringProposalService,
2018
) : GatheringProposalSpec {
2119

2220
@GetMapping("/{type}")
@@ -37,20 +35,4 @@ class GatheringProposalController(
3735

3836
return ApiResponse.ok(response)
3937
}
40-
41-
@PostMapping
42-
override fun addProposal(
43-
@Authenticated memberId: Long,
44-
@PathVariable("gatheringId") gatheringId: Long,
45-
request: GatheringProposalDto.Request.AddProposal
46-
): ApiResponse<Unit> {
47-
gatheringProposalService.addProposal(
48-
request.toCommand(
49-
memberId = memberId,
50-
gatheringId = gatheringId
51-
)
52-
)
53-
54-
return ApiResponse.ok(Unit)
55-
}
5638
}

tuk-api/src/main/kotlin/nexters/tuk/ui/gathering/GatheringProposalSpec.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,4 @@ interface GatheringProposalSpec {
2121
type: ProposalDirection,
2222
page: SliceRequest
2323
): ApiResponse<SliceResponse<ProposalResponse.ProposalOverview>>
24-
25-
@Operation(
26-
summary = "만남 초대장 모임 등록",
27-
security = [SecurityRequirement(name = SwaggerConfig.SECURITY_SCHEME_NAME)]
28-
)
29-
fun addProposal(
30-
memberId: Long,
31-
gatheringId: Long,
32-
request: GatheringProposalDto.Request.AddProposal
33-
): ApiResponse<Unit>
3424
}

tuk-api/src/main/kotlin/nexters/tuk/ui/proposal/ProposalDto.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import nexters.tuk.application.proposal.vo.ProposalPurposeInfo
66
class ProposalDto {
77
class Request {
88
data class Publish(
9+
val gatheringId: Long?,
910
val purpose: ProposalPurposeInfo,
1011
) {
1112
fun toCommand(memberId: Long): ProposalCommand.Propose {
1213
return ProposalCommand.Propose(
1314
memberId = memberId,
14-
purpose = purpose
15+
purpose = purpose,
16+
gatheringId = gatheringId
1517
)
1618
}
1719
}

tuk-api/src/test/kotlin/nexters/tuk/application/proposal/ProposalCreateServiceIntegrationTest.kt

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
5555

5656
val command = ProposalCommand.Propose(
5757
memberId = host.id,
58-
gatheringId = null, // 새로운 API에서는 gatheringId가 null
58+
gatheringId = null, // gatheringId가 null이면 모임에 자동으로 추가되지 않음
5959
purpose = ProposalPurposeInfo(
6060
whereTag = "카페",
6161
whenTag = "오후 3시",
@@ -73,13 +73,13 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
7373
val savedProposal = proposalRepository.findById(result.proposalId).orElse(null)
7474
assertThat(savedProposal).isNotNull
7575
assertThat(savedProposal.proposerId).isEqualTo(host.id)
76-
assertThat(savedProposal.gatheringId).isNull() // 새로운 API에서는 gatheringId가 null
76+
assertThat(savedProposal.gatheringId).isNull() // gatheringId가 null로 설정됨
7777
assertThat(savedProposal.purpose).isEqualTo("카페\n오후 3시\n커피 모임")
7878

79-
// 새로운 API에서는 ProposalCreateService가 모임 멤버에게 자동으로 발송하지 않음
80-
// ProposalMember는 GatheringProposalService.addProposal에서 생성됨
79+
// gatheringId가 null이면 GatheringProposalService.addProposal이 호출되지 않음
80+
// ProposalMember는 별도로 GatheringProposalService.addProposal을 호출해야 생성됨
8181
val proposalMembers = proposalMemberRepository.findAll()
82-
assertThat(proposalMembers).hasSize(0) // 모임에 추가되기 전까지는 멤버가 없음
82+
assertThat(proposalMembers).hasSize(0) // gatheringId가 null이므로 멤버가 없음
8383
}
8484

8585

@@ -95,7 +95,7 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
9595

9696
val command = ProposalCommand.Propose(
9797
memberId = host.id,
98-
gatheringId = null, // 새로운 API에서는 gatheringId가 null
98+
gatheringId = null, // gatheringId가 null이면 모임에 자동으로 추가되지 않음
9999
purpose = ProposalPurposeInfo(
100100
whereTag = "강남역 스타벅스 2층",
101101
whenTag = "2024년 12월 25일 오후 2시 30분",
@@ -123,13 +123,13 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
123123

124124
val command1 = ProposalCommand.Propose(
125125
memberId = host.id,
126-
gatheringId = null, // 새로운 API에서는 gatheringId가 null
126+
gatheringId = null, // gatheringId가 null이면 모임에 자동으로 추가되지 않음
127127
purpose = ProposalPurposeInfo(whereTag = "카페", whenTag = "오후 3시", whatTag = "첫 번째 모임")
128128
)
129129

130130
val command2 = ProposalCommand.Propose(
131131
memberId = host.id,
132-
gatheringId = null, // 새로운 API에서는 gatheringId가 null
132+
gatheringId = null, // gatheringId가 null이면 모임에 자동으로 추가되지 않음
133133
purpose = ProposalPurposeInfo(whereTag = "레스토랑", whenTag = "저녁 7시", whatTag = "두 번째 모임")
134134
)
135135

@@ -144,7 +144,7 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
144144
val proposals = proposalRepository.findAll()
145145
assertThat(proposals).hasSize(2)
146146

147-
// 새로운 API에서는 ProposalCreateService가 자동으로 멤버에게 발송하지 않음
147+
// gatheringId가 null이면 GatheringProposalService.addProposal이 호출되지 않음
148148
val proposalMembers = proposalMemberRepository.findAll()
149149
assertThat(proposalMembers).hasSize(0)
150150

@@ -156,4 +156,89 @@ class ProposalCreateServiceIntegrationTest @Autowired constructor(
156156
assertThat(proposal1?.gatheringId).isNull()
157157
assertThat(proposal2?.gatheringId).isNull()
158158
}
159+
160+
@Test
161+
fun `gatheringId가 존재할 때 제안을 생성하고 모임에 자동으로 추가한다`() {
162+
// given
163+
val host = memberFixture.createMember(socialId = "host", email = "[email protected]")
164+
val member1 = memberFixture.createMember(socialId = "member1", email = "[email protected]")
165+
val member2 = memberFixture.createMember(socialId = "member2", email = "[email protected]")
166+
167+
val gathering = gatheringFixture.createGathering(host, "테스트 모임")
168+
169+
// 모임 멤버 등록
170+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, host.id))
171+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, member1.id))
172+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, member2.id))
173+
174+
val command = ProposalCommand.Propose(
175+
memberId = host.id,
176+
gatheringId = gathering.id, // gatheringId가 존재하는 경우
177+
purpose = ProposalPurposeInfo(
178+
whereTag = "카페",
179+
whenTag = "오후 3시",
180+
whatTag = "모임 제안"
181+
)
182+
)
183+
184+
// when
185+
val result = proposalCreateService.propose(command)
186+
187+
// then
188+
assertThat(result.proposalId).isNotNull()
189+
190+
// 제안이 생성되었는지 확인
191+
val savedProposal = proposalRepository.findById(result.proposalId).orElse(null)
192+
assertThat(savedProposal).isNotNull
193+
assertThat(savedProposal.proposerId).isEqualTo(host.id)
194+
assertThat(savedProposal.gatheringId).isEqualTo(gathering.id) // gatheringId가 설정되어야 함
195+
assertThat(savedProposal.purpose).isEqualTo("카페\n오후 3시\n모임 제안")
196+
197+
// gatheringId가 존재할 때는 GatheringProposalService.addProposal이 호출되어
198+
// 모든 모임 멤버에게 제안이 발송되어야 함
199+
val proposalMembers = proposalMemberRepository.findAll()
200+
assertThat(proposalMembers).hasSize(3) // host, member1, member2
201+
202+
val proposalMemberIds = proposalMembers.map { it.memberId }
203+
assertThat(proposalMemberIds).containsExactlyInAnyOrder(host.id, member1.id, member2.id)
204+
}
205+
206+
@Test
207+
fun `gatheringId가 null일 때 제안만 생성하고 모임에 추가하지 않는다`() {
208+
// given
209+
val host = memberFixture.createMember(socialId = "host", email = "[email protected]")
210+
val member1 = memberFixture.createMember(socialId = "member1", email = "[email protected]")
211+
212+
val gathering = gatheringFixture.createGathering(host, "테스트 모임")
213+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, host.id))
214+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, member1.id))
215+
216+
val command = ProposalCommand.Propose(
217+
memberId = host.id,
218+
gatheringId = null, // gatheringId가 null인 경우
219+
purpose = ProposalPurposeInfo(
220+
whereTag = "카페",
221+
whenTag = "오후 3시",
222+
whatTag = "개별 제안"
223+
)
224+
)
225+
226+
// when
227+
val result = proposalCreateService.propose(command)
228+
229+
// then
230+
assertThat(result.proposalId).isNotNull()
231+
232+
// 제안이 생성되었는지 확인
233+
val savedProposal = proposalRepository.findById(result.proposalId).orElse(null)
234+
assertThat(savedProposal).isNotNull
235+
assertThat(savedProposal.proposerId).isEqualTo(host.id)
236+
assertThat(savedProposal.gatheringId).isNull() // gatheringId가 null이어야 함
237+
assertThat(savedProposal.purpose).isEqualTo("카페\n오후 3시\n개별 제안")
238+
239+
// gatheringId가 null일 때는 GatheringProposalService.addProposal이 호출되지 않아
240+
// 제안 멤버가 생성되지 않아야 함
241+
val proposalMembers = proposalMemberRepository.findAll()
242+
assertThat(proposalMembers).hasSize(0)
243+
}
159244
}

0 commit comments

Comments
 (0)