Skip to content

Commit 5bfb92e

Browse files
authored
Merge pull request #41 from Nexters/feat/delete-gathering
Feat/delete gathering
2 parents b28ccad + 2526242 commit 5bfb92e

File tree

9 files changed

+206
-27
lines changed

9 files changed

+206
-27
lines changed

tuk-api/src/main/kotlin/nexters/tuk/application/gathering/GatheringQueryService.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,26 @@ class GatheringQueryService(
4040
proposalService.getGatheringProposalStat(query.gatheringId, query.memberId)
4141

4242
val gatheringMemberIds = gatheringMemberService.getGatheringMemberIds(query.gatheringId)
43+
val gathering = gatheringRepository.findByIdOrThrow(query.gatheringId)
44+
4345
val members = memberService.getMemberOverviews(gatheringMemberIds).map {
44-
GatheringResponse.GatheringDetail.MemberOverview(it.memberId, it.memberName)
46+
GatheringResponse.GatheringDetail.MemberOverview(
47+
memberId = it.memberId,
48+
memberName = it.memberName,
49+
isMe = it.memberId == query.memberId,
50+
isHost = gathering.isHost(it.memberId)
51+
)
4552
}
4653

47-
val gathering = gatheringRepository.findByIdOrThrow(query.gatheringId)
48-
4954
return GatheringResponse.GatheringDetail(
5055
gatheringId = gathering.id,
5156
gatheringIntervalDays = gathering.intervalDays,
5257
gatheringName = gathering.name,
5358
lastPushRelativeTime = RelativeTime.from(gathering.lastPushedAt ?: gathering.createdAt),
5459
sentProposalCount = proposalStat.sentCount,
5560
receivedProposalCount = proposalStat.receivedCount,
56-
members = members
61+
members = members,
62+
isHost = gathering.isHost(query.memberId)
5763
)
5864
}
5965

tuk-api/src/main/kotlin/nexters/tuk/application/gathering/GatheringService.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package nexters.tuk.application.gathering
22

33
import nexters.tuk.application.gathering.dto.request.GatheringCommand
44
import nexters.tuk.application.gathering.dto.response.GatheringResponse
5+
import nexters.tuk.contract.BaseException
6+
import nexters.tuk.contract.ErrorType
57
import nexters.tuk.domain.gathering.Gathering
68
import nexters.tuk.domain.gathering.GatheringRepository
79
import nexters.tuk.domain.gathering.findByIdOrThrow
@@ -37,6 +39,9 @@ class GatheringService(
3739
@Transactional
3840
fun updateGathering(command: GatheringCommand.Update): GatheringResponse.Simple {
3941
val gathering = gatheringRepository.findByIdOrThrow(command.gatheringId)
42+
43+
validateHostPermission(gathering = gathering, memberId = command.memberId)
44+
4045
gathering.update(command)
4146

4247
return GatheringResponse.Simple(
@@ -45,4 +50,22 @@ class GatheringService(
4550
intervalDays = gathering.intervalDays,
4651
)
4752
}
53+
54+
private fun validateHostPermission(
55+
gathering: Gathering,
56+
memberId: Long,
57+
) {
58+
if (!gathering.isHost(memberId)) {
59+
throw BaseException(ErrorType.BAD_REQUEST, "수정 권한이 없습니다.")
60+
}
61+
}
62+
63+
@Transactional
64+
fun deleteGathering(command: GatheringCommand.Delete) {
65+
val gathering = gatheringRepository.findByIdOrThrow(command.gatheringId)
66+
67+
validateHostPermission(gathering = gathering, command.memberId)
68+
69+
gathering.delete()
70+
}
4871
}

tuk-api/src/main/kotlin/nexters/tuk/application/gathering/dto/request/GatheringCommand.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package nexters.tuk.application.gathering.dto.request
22

3-
import io.swagger.v3.oas.annotations.media.Schema
4-
53

64
class GatheringCommand {
75
data class Generate(
@@ -11,12 +9,13 @@ class GatheringCommand {
119
val tags: List<Long>,
1210
)
1311

14-
data class JoinGathering(
12+
data class Delete(
1513
val memberId: Long,
1614
val gatheringId: Long,
1715
)
1816

1917
data class Update(
18+
val memberId: Long,
2019
val gatheringId: Long,
2120
val gatheringIntervalDays: Long,
2221
)

tuk-api/src/main/kotlin/nexters/tuk/application/gathering/dto/response/GatheringResponse.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,20 @@ class GatheringResponse {
3232
}
3333

3434
data class GatheringDetail(
35-
@Schema(description = "모임 id")
3635
val gatheringId: Long,
37-
@Schema(description = "모임 주기")
3836
val gatheringIntervalDays: Long,
39-
@Schema(description = "모임명")
4037
val gatheringName: String,
41-
@Schema(description = "상대 시간 타입 - \"오늘\", \"n일 전\", \"n주 전\", \"n개월 전\", \"n년 전\" ")
4238
val lastPushRelativeTime: RelativeTime,
43-
@Schema(description = "보낸 제안 수")
4439
val sentProposalCount: Int,
45-
@Schema(description = "받은 제안 수")
4640
val receivedProposalCount: Int,
47-
@Schema(description = "모임원")
4841
val members: List<MemberOverview>,
42+
val isHost: Boolean
4943
) {
5044
data class MemberOverview(
51-
@Schema(description = "사용자 id")
5245
val memberId: Long,
53-
@Schema(description = "사용자 명")
5446
val memberName: String,
47+
val isMe: Boolean,
48+
val isHost: Boolean,
5549
)
5650
}
5751

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class GatheringController(
3939
val response = gatheringService.updateGathering(
4040
GatheringCommand.Update(
4141
gatheringId = gatheringId,
42-
gatheringIntervalDays = request.gatheringIntervalDays
42+
gatheringIntervalDays = request.gatheringIntervalDays,
43+
memberId = memberId
4344
)
4445
)
4546

@@ -89,4 +90,19 @@ class GatheringController(
8990

9091
return ApiResponse.ok(response)
9192
}
93+
94+
@DeleteMapping("/{gatheringId}")
95+
override fun deleteGathering(
96+
@Authenticated memberId: Long,
97+
@PathVariable("gatheringId") gatheringId: Long
98+
): ApiResponse<Unit> {
99+
gatheringService.deleteGathering(
100+
GatheringCommand.Delete(
101+
memberId = memberId,
102+
gatheringId = gatheringId
103+
)
104+
)
105+
106+
return ApiResponse.ok()
107+
}
92108
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ class GatheringDto {
3131
@Schema(description = "모임 주기 (일 단위)")
3232
val gatheringIntervalDays: Long,
3333
) {
34-
fun toCommand(gatheringId: Long): GatheringCommand.Update {
34+
fun toCommand(gatheringId: Long, memberId: Long): GatheringCommand.Update {
3535
return GatheringCommand.Update(
36+
memberId = memberId,
3637
gatheringId = gatheringId,
3738
gatheringIntervalDays = gatheringIntervalDays
3839
)

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ interface GatheringSpec {
6161
fun getGatheringName(
6262
gatheringId: Long
6363
): ApiResponse<GatheringResponse.GatheringName>
64+
65+
@Operation(
66+
summary = "모임 삭제",
67+
)
68+
fun deleteGathering(memberId: Long, gatheringId: Long): ApiResponse<Unit>
6469
}

tuk-api/src/test/kotlin/nexters/tuk/application/gathering/GatheringQueryServiceIntegrationTest.kt

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class GatheringQueryServiceIntegrationTest @Autowired constructor(
9999
}
100100

101101
@Test
102-
fun `모임 상세 정보를 정상적으로 조회한다`() {
102+
fun `호스트가 모임 상세를 조회할 때 모든 정보가 올바르게 설정된다`() {
103103
// given
104104
val host = memberFixture.createMember(socialId = "host", email = "[email protected]")
105105
val member1 = memberFixture.createMember(socialId = "member1", email = "[email protected]")
@@ -130,17 +130,31 @@ class GatheringQueryServiceIntegrationTest @Autowired constructor(
130130
// when
131131
val result = gatheringQueryService.getGatheringDetail(query)
132132

133-
// then
133+
// then - 기본 정보
134134
assertThat(result.gatheringId).isEqualTo(gathering.id)
135135
assertThat(result.gatheringIntervalDays).isEqualTo(gathering.intervalDays)
136136
assertThat(result.gatheringName).isEqualTo("테스트 모임")
137137
assertThat(result.lastPushRelativeTime).isNotNull()
138138
assertThat(result.sentProposalCount).isEqualTo(2)
139139
assertThat(result.receivedProposalCount).isEqualTo(1)
140140
assertThat(result.members).hasSize(3)
141-
142-
val memberNames = result.members.map { it.memberName }
143-
assertThat(memberNames).containsExactlyInAnyOrder("테스트사용자", "테스트사용자", "테스트사용자")
141+
assertThat(result.isHost).isTrue()
142+
143+
// then - isMe와 isHost 검증
144+
val hostMember = result.members.find { it.memberId == host.id }
145+
assertThat(hostMember).isNotNull
146+
assertThat(hostMember!!.isMe).isTrue()
147+
assertThat(hostMember.isHost).isTrue()
148+
149+
val member1Info = result.members.find { it.memberId == member1.id }
150+
assertThat(member1Info).isNotNull
151+
assertThat(member1Info!!.isMe).isFalse()
152+
assertThat(member1Info.isHost).isFalse()
153+
154+
val member2Info = result.members.find { it.memberId == member2.id }
155+
assertThat(member2Info).isNotNull
156+
assertThat(member2Info!!.isMe).isFalse()
157+
assertThat(member2Info.isHost).isFalse()
144158
}
145159

146160
@Test
@@ -200,7 +214,7 @@ class GatheringQueryServiceIntegrationTest @Autowired constructor(
200214
}
201215

202216
@Test
203-
fun `혼자만 있는 모임의 상세 정보를 조회한다`() {
217+
fun `혼자만 있는 모임에서 호스트의 모든 정보가 올바르게 설정된다`() {
204218
// given
205219
val host = memberFixture.createMember(socialId = "host", email = "[email protected]")
206220

@@ -212,16 +226,22 @@ class GatheringQueryServiceIntegrationTest @Autowired constructor(
212226
// when
213227
val result = gatheringQueryService.getGatheringDetail(query)
214228

215-
// then
229+
// then - 기본 정보
216230
assertThat(result.gatheringId).isEqualTo(gathering.id)
217231
assertThat(result.gatheringIntervalDays).isEqualTo(gathering.intervalDays)
218232
assertThat(result.gatheringName).isEqualTo("혼자 모임")
219233
assertThat(result.lastPushRelativeTime).isNotNull()
220234
assertThat(result.sentProposalCount).isEqualTo(0)
221235
assertThat(result.receivedProposalCount).isEqualTo(0)
222236
assertThat(result.members).hasSize(1)
223-
assertThat(result.members.first().memberName).isEqualTo("테스트사용자")
224-
assertThat(result.members.first().memberId).isEqualTo(host.id)
237+
assertThat(result.isHost).isTrue()
238+
239+
// then - isMe와 isHost 검증
240+
val hostMember = result.members.first()
241+
assertThat(hostMember.memberId).isEqualTo(host.id)
242+
assertThat(hostMember.memberName).isEqualTo("테스트사용자")
243+
assertThat(hostMember.isMe).isTrue()
244+
assertThat(hostMember.isHost).isTrue()
225245
}
226246

227247
@Test
@@ -286,4 +306,43 @@ class GatheringQueryServiceIntegrationTest @Autowired constructor(
286306
val actualNames = result.gatheringOverviews.map { it.gatheringName }
287307
assertThat(actualNames).containsExactlyInAnyOrderElementsOf(expectedNames)
288308
}
309+
310+
311+
@Test
312+
fun `일반 멤버가 모임 상세를 조회할 때 isMe와 isHost가 올바르게 설정된다`() {
313+
// given
314+
val host = memberFixture.createMember(socialId = "host", email = "[email protected]")
315+
val member1 = memberFixture.createMember(socialId = "member1", email = "[email protected]")
316+
val member2 = memberFixture.createMember(socialId = "member2", email = "[email protected]")
317+
318+
val gathering = gatheringFixture.createGathering(host, "테스트 모임")
319+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, host.id))
320+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, member1.id))
321+
gatheringMemberRepository.save(GatheringMember.registerMember(gathering, member2.id))
322+
323+
val query = GatheringQuery.GatheringDetail(member1.id, gathering.id)
324+
325+
// when
326+
val result = gatheringQueryService.getGatheringDetail(query)
327+
328+
// then
329+
assertThat(result.isHost).isFalse()
330+
assertThat(result.members).hasSize(3)
331+
332+
val hostMember = result.members.find { it.memberId == host.id }
333+
assertThat(hostMember).isNotNull
334+
assertThat(hostMember!!.isMe).isFalse()
335+
assertThat(hostMember.isHost).isTrue()
336+
337+
val member1Info = result.members.find { it.memberId == member1.id }
338+
assertThat(member1Info).isNotNull
339+
assertThat(member1Info!!.isMe).isTrue()
340+
assertThat(member1Info.isHost).isFalse()
341+
342+
val member2Info = result.members.find { it.memberId == member2.id }
343+
assertThat(member2Info).isNotNull
344+
assertThat(member2Info!!.isMe).isFalse()
345+
assertThat(member2Info.isHost).isFalse()
346+
}
347+
289348
}

0 commit comments

Comments
 (0)