Skip to content

Commit f99797f

Browse files
authored
Merge pull request #14 from Nexters/feat/gathering-crud
✨ Feature: 모임 CRUD API 스펙 변경
2 parents d95f62f + a62aa2d commit f99797f

37 files changed

+1383
-932
lines changed

docker/init.sql

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ CREATE TABLE IF NOT EXISTS gathering
2121
id BIGINT AUTO_INCREMENT PRIMARY KEY,
2222
gathering_name VARCHAR(255) NOT NULL,
2323
member_id BIGINT NOT NULL,
24-
first_gathering_date DATE NOT NULL,
25-
last_gathering_date DATE NOT NULL,
2624
interval_days BIGINT NOT NULL,
27-
tags JSON NULL,
2825
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
2926
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
3027
deleted_at TIMESTAMP NULL,
@@ -64,4 +61,39 @@ CREATE TABLE IF NOT EXISTS invitation
6461
CONSTRAINT fk_invitation_member_id FOREIGN KEY (member_id) REFERENCES member(id),
6562
INDEX idx_gathering_member (gathering_id, member_id),
6663
INDEX idx_deleted_at (deleted_at)
64+
);
65+
66+
CREATE TABLE IF NOT EXISTS category
67+
(
68+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
69+
name VARCHAR(255) NOT NULL,
70+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
71+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
72+
deleted_at TIMESTAMP NULL,
73+
74+
INDEX idx_deleted_at (deleted_at)
75+
);
76+
77+
CREATE TABLE IF NOT EXISTS tag
78+
(
79+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
80+
name VARCHAR(255) NOT NULL,
81+
category_id BIGINT NOT NULL,
82+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
83+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
84+
deleted_at TIMESTAMP NULL,
85+
86+
CONSTRAINT fk_tag_category FOREIGN KEY (category_id) REFERENCES category(id),
87+
INDEX idx_deleted_at (deleted_at)
88+
);
89+
90+
CREATE TABLE IF NOT EXISTS gathering_tag
91+
(
92+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
93+
gathering_id BIGINT NOT NULL,
94+
tag_id BIGINT NOT NULL,
95+
96+
CONSTRAINT fk_gathering_tag_gathering FOREIGN KEY (gathering_id) REFERENCES gathering(id),
97+
CONSTRAINT fk_gathering_tag_tag FOREIGN KEY (tag_id) REFERENCES tag(id),
98+
UNIQUE KEY uk_gathering_tag (gathering_id, tag_id)
6799
);

tuk-api/src/main/kotlin/nexters/tuk/application/auth/dto/response/AuthResponse.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package nexters.tuk.application.auth.dto.response
22

3+
import io.swagger.v3.oas.annotations.media.Schema
4+
35
class AuthResponse {
6+
@Schema(name = "LoginResponse")
47
data class Login(
58
val memberId: Long,
69
val accessToken: String,
710
val refreshToken: String,
811
)
912

13+
@Schema(name = "RefreshResponse")
1014
data class Refresh(
1115
val accessToken: String,
1216
val refreshToken: String,

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

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package nexters.tuk.application.gathering
2+
3+
import nexters.tuk.application.gathering.dto.request.GatheringCommand
4+
import nexters.tuk.application.gathering.dto.response.GatheringResponse
5+
import nexters.tuk.domain.gathering.Gathering
6+
import nexters.tuk.domain.gathering.GatheringRepository
7+
import org.springframework.stereotype.Service
8+
import org.springframework.transaction.annotation.Transactional
9+
10+
@Service
11+
class GatheringGenerateService(
12+
private val gatheringRepository: GatheringRepository,
13+
private val gatheringMemberService: GatheringMemberService,
14+
private val gatheringTagService: GatheringTagService,
15+
) {
16+
@Transactional
17+
fun generateGathering(command: GatheringCommand.Generate): GatheringResponse.Generate {
18+
val gathering = Gathering.generate(
19+
hostId = command.memberId,
20+
name = command.gatheringName,
21+
intervalDays = command.gatheringIntervalDays
22+
).also { gatheringRepository.save(it) }
23+
24+
val gatheringTags = gatheringTagService.addTags(gathering.id, command.tags)
25+
26+
gatheringMemberService.joinGathering(
27+
gatheringId = gathering.id,
28+
memberId = command.memberId,
29+
)
30+
31+
// TODO 알림 등록하기
32+
return GatheringResponse.Generate(
33+
gathering.id,
34+
)
35+
}
36+
}

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

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package nexters.tuk.application.gathering
22

3-
import nexters.tuk.application.gathering.dto.response.GatheringResponse
3+
import nexters.tuk.application.gathering.dto.response.GatheringMemberResponse
44
import nexters.tuk.contract.BaseException
55
import nexters.tuk.contract.ErrorType
66
import nexters.tuk.domain.gathering.*
77
import org.springframework.stereotype.Service
88
import org.springframework.transaction.annotation.Transactional
9-
import java.time.LocalDate
10-
import java.time.temporal.ChronoUnit
119

1210
@Service
1311
class GatheringMemberService(
1412
private val gatheringRepository: GatheringRepository,
1513
private val gatheringMemberRepository: GatheringMemberRepository
1614
) {
1715
@Transactional
18-
fun registerMember(gatheringId: Long, memberId: Long): Long {
16+
fun joinGathering(gatheringId: Long, memberId: Long): GatheringMemberResponse.JoinGathering {
1917
val gathering = gatheringRepository.findByIdOrThrow(gatheringId)
2018
if (gathering.hasMember(memberId)) {
2119
throw BaseException(ErrorType.BAD_REQUEST, "이미 가입된 사용자입니다.")
@@ -24,32 +22,27 @@ class GatheringMemberService(
2422
val gatheringMember = GatheringMember.registerMember(gathering, memberId)
2523
.also { gatheringMemberRepository.save(it) }
2624

27-
return gatheringMember.id
25+
return GatheringMemberResponse.JoinGathering(gatheringMember.id)
2826
}
2927

3028
private fun Gathering.hasMember(memberId: Long): Boolean {
3129
return gatheringMemberRepository.findByGatheringAndMemberId(this, memberId) != null
3230
}
3331

3432
@Transactional(readOnly = true)
35-
fun getMemberGatherings(memberId: Long): List<GatheringResponse.GatheringOverview> {
33+
fun getMemberGatherings(memberId: Long): List<GatheringMemberResponse.MemberGatherings> {
3634
val gatheringMembers = gatheringMemberRepository.findAllByMemberId(memberId)
3735

3836
return gatheringMembers
3937
.map { it.gathering }
4038
.map {
41-
GatheringResponse.GatheringOverview(
39+
GatheringMemberResponse.MemberGatherings(
4240
it.id,
4341
it.name,
44-
it.lastGatheringDate.monthsAgo()
4542
)
4643
}.sortedBy { it.name }
4744
}
4845

49-
private fun LocalDate.monthsAgo(): Int {
50-
return until(LocalDate.now(), ChronoUnit.MONTHS).toInt()
51-
}
52-
5346
@Transactional(readOnly = true)
5447
fun verifyGatheringAccess(gatheringId: Long, memberId: Long) {
5548
val gathering = gatheringRepository.findByIdOrThrow(gatheringId)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package nexters.tuk.application.gathering
2+
3+
import nexters.tuk.application.gathering.dto.request.GatheringQuery
4+
import nexters.tuk.application.gathering.dto.response.GatheringResponse
5+
import nexters.tuk.application.invitation.InvitationService
6+
import nexters.tuk.application.member.MemberService
7+
import nexters.tuk.domain.gathering.GatheringRepository
8+
import nexters.tuk.domain.gathering.findByIdOrThrow
9+
import org.springframework.stereotype.Service
10+
import org.springframework.transaction.annotation.Transactional
11+
12+
@Service
13+
// TODO 알림 추가시 마지막 알림 날짜를 가져오는 로직 구현, 현재는 0으로 설정
14+
class GatheringQueryService(
15+
private val gatheringRepository: GatheringRepository,
16+
private val gatheringMemberService: GatheringMemberService,
17+
private val invitationService: InvitationService,
18+
private val memberService: MemberService,
19+
) {
20+
@Transactional(readOnly = true)
21+
fun getMemberGatherings(query: GatheringQuery.MemberGathering): GatheringResponse.GatheringOverviews {
22+
val gatheringOverviews = gatheringMemberService.getMemberGatherings(query.memberId)
23+
.map {
24+
GatheringResponse.GatheringOverviews.GatheringOverview(
25+
gatheringId = it.id,
26+
gatheringName = it.name,
27+
monthsSinceLastGathering = 0
28+
)
29+
}
30+
31+
return GatheringResponse.GatheringOverviews(gatheringOverviews.size, gatheringOverviews)
32+
}
33+
34+
@Transactional(readOnly = true)
35+
fun getGatheringDetail(query: GatheringQuery.GatheringDetail): GatheringResponse.GatheringDetail {
36+
gatheringMemberService.verifyGatheringAccess(query.gatheringId, query.memberId)
37+
38+
val invitationStat = invitationService.getGatheringInvitationStat(query.gatheringId, query.memberId)
39+
40+
val gatheringMemberIds = gatheringMemberService.getGatheringMemberIds(query.gatheringId)
41+
val members = memberService.getMemberOverview(gatheringMemberIds).map {
42+
GatheringResponse.GatheringDetail.MemberOverview(it.memberId, it.memberName)
43+
}
44+
45+
val gatheringDetail = gatheringRepository.findByIdOrThrow(query.gatheringId)
46+
47+
return GatheringResponse.GatheringDetail(
48+
gatheringId = gatheringDetail.id,
49+
gatheringName = gatheringDetail.name,
50+
monthsSinceLastNotification = 0,
51+
sentInvitationCount = invitationStat.sentCount,
52+
receivedInvitationCount = invitationStat.receivedCount,
53+
members = members
54+
)
55+
}
56+
}

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

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package nexters.tuk.application.gathering
2+
3+
import nexters.tuk.application.gathering.dto.response.GatheringTagResponse
4+
import nexters.tuk.domain.gathering.GatheringRepository
5+
import nexters.tuk.domain.gathering.GatheringTag
6+
import nexters.tuk.domain.gathering.GatheringTagRepository
7+
import nexters.tuk.domain.gathering.findByIdOrThrow
8+
import org.springframework.stereotype.Service
9+
import org.springframework.transaction.annotation.Transactional
10+
11+
@Service
12+
class GatheringTagService(
13+
private val gatheringRepository: GatheringRepository,
14+
private val gatheringTagRepository: GatheringTagRepository
15+
) {
16+
@Transactional
17+
fun addTags(gatheringId: Long, tagsId: List<Long>): GatheringTagResponse.AddTag {
18+
val gathering = gatheringRepository.findByIdOrThrow(gatheringId)
19+
20+
val gatheringTags = tagsId.map { GatheringTag.addTag(gathering, it) }
21+
.also { gatheringTagRepository.saveAll(it) }
22+
23+
return GatheringTagResponse.AddTag(gatheringTags.map { it.id })
24+
}
25+
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ class GatheringCommand {
55
data class Generate(
66
val memberId: Long,
77
val gatheringName: String,
8-
val daysSinceLastGathering: Long,
98
val gatheringIntervalDays: Long,
10-
val tags: List<String>,
9+
val tags: List<Long>,
1110
)
1211

1312
data class JoinGathering(

0 commit comments

Comments
 (0)