Skip to content

Commit 2ab3ba7

Browse files
authored
[DPMBE-45] 약속 생성, 변경, 조회기능을 만든다 (#48)
* feat: Promise Type 변경 및 Promise CRUD * style: 일부 변경 * feat : Promise Event 등록, CI getVersion 변경, validator 분리
1 parent 524cbaa commit 2ab3ba7

File tree

17 files changed

+324
-12
lines changed

17 files changed

+324
-12
lines changed

.github/workflows/BuildApiServer.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
id: get_version
3434
run: |
3535
RELEASE_VERSION_WITHOUT_V="$(cut -d'v' -f2 <<< ${GITHUB_REF#refs/*/})"
36-
echo "RELEASE_VERSION_WITHOUT_V=$RELEASE_VERSION_WITHOUT_V" >> $GITHUB_ENV
36+
echo ::set-output name=VERSION::$RELEASE_VERSION_WITHOUT_V
3737
3838
- name: Start containers # test 돌릴때 레디스 필요
3939
run: docker-compose up -d

.github/workflows/BuildLocationServer.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
id: get_version
3434
run: |
3535
RELEASE_VERSION_WITHOUT_V="$(cut -d'v' -f2 <<< ${GITHUB_REF#refs/*/})"
36-
echo "RELEASE_VERSION_WITHOUT_V=$RELEASE_VERSION_WITHOUT_V" >> $GITHUB_ENV
36+
echo ::set-output name=VERSION::$RELEASE_VERSION_WITHOUT_V
3737
3838
- name: Start containers # test 돌릴때 레디스 필요
3939
run: docker-compose up -d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.depromeet.whatnow.domains.promise.adaptor
2+
3+
import com.depromeet.whatnow.domains.promise.domain.Promise
4+
import com.depromeet.whatnow.domains.promise.exception.PromiseNotFoundException
5+
import com.depromeet.whatnow.domains.promise.repository.PromiseRepository
6+
import org.springframework.data.repository.findByIdOrNull
7+
import org.springframework.stereotype.Component
8+
import java.time.LocalDateTime
9+
10+
// @Adaptor
11+
@Component
12+
class PromiseAdaptor(
13+
var promiseRepository: PromiseRepository,
14+
) {
15+
fun queryPromise(promiseId: Long): Promise {
16+
return promiseRepository.findByIdOrNull(promiseId) ?: run { throw PromiseNotFoundException.EXCEPTION }
17+
}
18+
19+
fun queryPromiseByMainUserId(mainUserId: Long): List<Promise> {
20+
return promiseRepository.findAllByMainUserId(mainUserId)
21+
}
22+
fun queryPromiseByMainUserIdAfterNow(mainUserId: Long): List<Promise> {
23+
return promiseRepository.findAllByMainUserIdAfterNow(mainUserId, LocalDateTime.now())
24+
}
25+
fun save(promise: Promise): Promise {
26+
return promiseRepository.save(promise)
27+
}
28+
29+
fun delete(promiseId: Long) {
30+
return promiseRepository.deleteById(promiseId)
31+
}
32+
}

Whatnow-Domain/src/main/kotlin/com/depromeet/whatnow/domains/promise/domain/Promise.kt

+40-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.depromeet.whatnow.domains.promise.domain
22

33
import com.depromeet.whatnow.common.BaseTimeEntity
4+
import com.depromeet.whatnow.common.aop.event.Events
45
import com.depromeet.whatnow.common.vo.PlaceVo
5-
import com.depromeet.whatnow.domains.promiseprogress.domain.PromiseProgressGroup
66
import java.time.LocalDateTime
77
import javax.persistence.Column
88
import javax.persistence.Embedded
@@ -11,6 +11,7 @@ import javax.persistence.Enumerated
1111
import javax.persistence.GeneratedValue
1212
import javax.persistence.GenerationType
1313
import javax.persistence.Id
14+
import javax.persistence.PostPersist
1415
import javax.persistence.Table
1516

1617
@Entity
@@ -29,10 +30,46 @@ class Promise(
2930
var meetPlace: PlaceVo?,
3031

3132
@Enumerated
32-
var promiseProgreeType: PromiseProgressGroup,
33+
var promiseType: PromiseType = PromiseType.BEFORE,
3334

3435
@Id
3536
@GeneratedValue(strategy = GenerationType.IDENTITY)
3637
@Column(name = "promise_history_id")
3738
val id: Long? = null,
38-
) : BaseTimeEntity()
39+
40+
// 차후 이벤트 domain 설계 되면 생성시에 Domain 계층에서 validate 하겠습니다
41+
// var promiseValidator: PromiseValidator,
42+
43+
) : BaseTimeEntity() {
44+
@PostPersist
45+
fun createPromise() {
46+
Events.raise(PromiseRegisterEvent.from(this))
47+
}
48+
49+
fun updateTitle(title: String) {
50+
this.title = title
51+
}
52+
53+
fun delayPromise(endTime: LocalDateTime) {
54+
this.endTime = endTime
55+
}
56+
57+
fun movePlace(placeVo: PlaceVo) {
58+
this.meetPlace = placeVo
59+
}
60+
61+
fun endPromise() {
62+
this.promiseType = PromiseType.END
63+
}
64+
fun pendingPromise() {
65+
this.promiseType = PromiseType.PENDING
66+
}
67+
68+
fun deletePromise() {
69+
this.promiseType = PromiseType.DELETED
70+
}
71+
72+
fun updatePromiseProgressType(promiseType: PromiseType) {
73+
this.promiseType = promiseType
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.depromeet.whatnow.domains.promise.domain
2+
3+
import com.depromeet.whatnow.common.aop.event.DomainEvent
4+
5+
class PromiseRegisterEvent(
6+
val promiseId: Long,
7+
) : DomainEvent(){
8+
// Factory method
9+
companion object {
10+
fun from(promise: Promise): PromiseRegisterEvent {
11+
return PromiseRegisterEvent(promise.id!!)
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.depromeet.whatnow.domains.promise.domain
2+
3+
enum class PromiseType {
4+
BEFORE, PENDING, END, DELETED
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.depromeet.whatnow.domains.promise.exception
2+
3+
import com.depromeet.whatnow.exception.WhatnowCodeException
4+
5+
class DoublePromiseException : WhatnowCodeException(
6+
PromiseErrorCode.PROMISE_DOUBLE_PROMISE,
7+
) {
8+
companion object {
9+
val EXCEPTION: WhatnowCodeException = DoublePromiseException()
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.depromeet.whatnow.domains.promise.exception
2+
3+
import com.depromeet.whatnow.annotation.ExplainError
4+
import com.depromeet.whatnow.consts.BAD_REQUEST
5+
import com.depromeet.whatnow.consts.FORBIDDEN
6+
import com.depromeet.whatnow.consts.NOT_FOUND
7+
import com.depromeet.whatnow.dto.ErrorReason
8+
import com.depromeet.whatnow.exception.BaseErrorCode
9+
import java.util.*
10+
11+
enum class PromiseErrorCode(val status: Int, val code: String, val reason: String) : BaseErrorCode {
12+
13+
@ExplainError("이미 등록된 약속일 경우 발생하는 오류.")
14+
PROMISE_ALREADY_REGISTER(BAD_REQUEST, "PROMISE_400_1", "이미 회원가입한 약속입니다."),
15+
16+
@ExplainError("정지 처리된 약속일 경우 발생하는 오류")
17+
PROMISE_FORBIDDEN(FORBIDDEN, "PROMISE_403_1", "접근이 제한된 약속입니다."),
18+
19+
@ExplainError("삭제된 약속로 접근하려는 경우")
20+
PROMISE_ALREADY_DELETED(FORBIDDEN, "PROMISE_403_2", "이미 지워진 약속입니다."),
21+
22+
@ExplainError("약속 정보를 찾을 수 없는 경우")
23+
PROMISE_NOT_FOUND(NOT_FOUND, "PROMISE_404_1", "약속 정보를 찾을 수 없습니다."),
24+
25+
@ExplainError("이중약속을 잡은 경우")
26+
PROMISE_DOUBLE_PROMISE(BAD_REQUEST, "PROMISE_400_2", "이미 약속을 잡았습니다."),
27+
;
28+
29+
override val errorReason: ErrorReason
30+
get() { return ErrorReason(status, code, reason) }
31+
32+
override val explainError: String
33+
get() {
34+
val field = this.javaClass.getField(name)
35+
val annotation = field.getAnnotation(ExplainError::class.java)
36+
return if (Objects.nonNull(annotation)) annotation.value else reason
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.depromeet.whatnow.domains.promise.exception
2+
3+
import com.depromeet.whatnow.exception.GlobalErrorCode
4+
import com.depromeet.whatnow.exception.WhatnowCodeException
5+
6+
class PromiseNotFoundException : WhatnowCodeException(
7+
GlobalErrorCode.REFRESH_TOKEN_EXPIRED,
8+
) {
9+
companion object {
10+
val EXCEPTION: WhatnowCodeException = PromiseNotFoundException()
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.depromeet.whatnow.domains.promise.repository
2+
3+
import com.depromeet.whatnow.domains.promise.domain.Promise
4+
import org.springframework.data.jpa.repository.JpaRepository
5+
import org.springframework.data.jpa.repository.Query
6+
import org.springframework.stereotype.Repository
7+
import java.time.LocalDateTime
8+
9+
@Repository
10+
interface PromiseRepository : JpaRepository<Promise, Long> {
11+
fun findAllByMainUserId(mainUserId: Long): List<Promise>
12+
13+
@Query("SELECT p FROM Promise p WHERE p.mainUserId = :mainUserId AND p.endTime > :now")
14+
fun findAllByMainUserIdAfterNow(mainUserId: Long, now: LocalDateTime): List<Promise>
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.depromeet.whatnow.domains.promise.service
2+
3+
import com.depromeet.whatnow.common.vo.PlaceVo
4+
import com.depromeet.whatnow.domains.promise.adaptor.PromiseAdaptor
5+
import com.depromeet.whatnow.domains.promise.domain.Promise
6+
import com.depromeet.whatnow.domains.promise.domain.PromiseType
7+
import com.depromeet.whatnow.domains.promiseprogress.domain.PromiseProgressType
8+
import org.springframework.stereotype.Service
9+
import java.time.LocalDateTime
10+
import javax.transaction.Transactional
11+
12+
@Service
13+
class PromiseDomainService(
14+
val promiseAdaptor: PromiseAdaptor,
15+
) {
16+
fun registerPromise(
17+
endTime: LocalDateTime,
18+
title: String,
19+
mainUserId: Long,
20+
meetPlace: PlaceVo?,
21+
promiseType: PromiseType,
22+
): Promise {
23+
val promise = Promise(
24+
endTime = endTime,
25+
title = title,
26+
mainUserId = mainUserId,
27+
meetPlace = meetPlace,
28+
promiseType = promiseType,
29+
)
30+
return promiseAdaptor.save(promise)
31+
}
32+
33+
@Transactional
34+
fun updatePromiseTitle(promiseId: Long, title: String): Promise {
35+
val promise = promiseAdaptor.queryPromise(promiseId)
36+
// dirty checking
37+
promise.updateTitle(title)
38+
return promise
39+
}
40+
41+
// 약속 지연시키기
42+
@Transactional
43+
fun delayPromise(promiseId: Long, endTime: LocalDateTime): Promise {
44+
val promise = promiseAdaptor.queryPromise(promiseId)
45+
promise.delayPromise(endTime)
46+
return promise
47+
}
48+
49+
// 약속장소 변경
50+
@Transactional
51+
fun movePromisePlace(promiseId: Long, placeVo: PlaceVo): Promise {
52+
val promise = promiseAdaptor.queryPromise(promiseId)
53+
promise.movePlace(placeVo)
54+
return promise
55+
}
56+
57+
// 약속 진행상태(출발 전, 이동 중, 도착, ETC) 변경
58+
@Transactional
59+
fun pendingPromiseProgressType(promiseId: Long, promiseProgressType: PromiseProgressType): Promise {
60+
val promise = promiseAdaptor.queryPromise(promiseId)
61+
promise.pendingPromise()
62+
return promise
63+
}
64+
65+
@Transactional
66+
fun endPromiseProgressType(promiseId: Long, promiseProgressType: PromiseProgressType): Promise {
67+
val promise = promiseAdaptor.queryPromise(promiseId)
68+
promise.endPromise()
69+
return promise
70+
}
71+
72+
// 약속 취소 처리
73+
@Transactional
74+
fun deletePromise(promiseId: Long) {
75+
val promise = promiseAdaptor.queryPromise(promiseId)
76+
promise.deletePromise()
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.depromeet.whatnow.domains.promise.service
2+
3+
import com.depromeet.whatnow.domains.promise.adaptor.PromiseAdaptor
4+
import com.depromeet.whatnow.domains.promise.domain.Promise
5+
import com.depromeet.whatnow.domains.promise.exception.DoublePromiseException
6+
import org.springframework.stereotype.Component
7+
8+
@Component
9+
class PromiseValidator(
10+
val promiseAdaptor: PromiseAdaptor,
11+
) {
12+
/**
13+
* validation: @endTime 현재 날짜와 비교해서 일치하지 않아야함
14+
* */
15+
fun validateDoublePromise(promise: Promise) {
16+
val promises = promiseAdaptor.queryPromiseByMainUserIdAfterNow(promise.mainUserId)
17+
promises.filter { it.endTime > promise.endTime }.forEach {
18+
// 약속시간이 1시간 사이에 겹치면 등록 불가능
19+
if (it.endTime.dayOfYear == promise.endTime.dayOfYear) {
20+
throw DoublePromiseException.EXCEPTION
21+
}
22+
}
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.depromeet.whatnow.domains.promiseuser.adaptor
2+
3+
import com.depromeet.whatnow.domains.promise.exception.PromiseNotFoundException
4+
import com.depromeet.whatnow.domains.promiseuser.domain.PromiseUser
5+
import com.depromeet.whatnow.domains.promiseuser.repository.PromiseUserRepository
6+
import org.springframework.data.repository.findByIdOrNull
7+
8+
// @Adaptor
9+
class PromiseUserAdaptor(
10+
val promiseUserRepository: PromiseUserRepository,
11+
) {
12+
fun queryPromise(promiseId: Long): PromiseUser {
13+
return promiseUserRepository.findByIdOrNull(promiseId) ?: run { throw PromiseNotFoundException.EXCEPTION }
14+
}
15+
16+
fun save(promiseUser: PromiseUser): PromiseUser {
17+
return promiseUserRepository.save(promiseUser)
18+
}
19+
20+
fun delete(promiseId: Long) {
21+
return promiseUserRepository.deleteById(promiseId)
22+
}
23+
}

Whatnow-Domain/src/main/kotlin/com/depromeet/whatnow/domains/promise/domain/PromiseUser.kt renamed to Whatnow-Domain/src/main/kotlin/com/depromeet/whatnow/domains/promiseuser/domain/PromiseUser.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.depromeet.whatnow.domains.promise.domain
1+
package com.depromeet.whatnow.domains.promiseuser.domain
22

33
import com.depromeet.whatnow.common.BaseTimeEntity
44
import com.depromeet.whatnow.common.vo.CoordinateVo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.depromeet.whatnow.domains.promiseuser.repository
2+
3+
import com.depromeet.whatnow.domains.promiseuser.domain.PromiseUser
4+
import org.springframework.data.jpa.repository.JpaRepository
5+
import org.springframework.stereotype.Repository
6+
7+
@Repository
8+
interface PromiseUserRepository : JpaRepository<PromiseUser, Long>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// package com.depromeet.whatnow.domains.promiseuser.service
2+
//
3+
// import com.depromeet.whatnow.domains.promise.adaptor.PromiseAdaptor
4+
// import org.springframework.stereotype.Service
5+
//
6+
// @Service
7+
// class PromiseDomainService(
8+
// promiseAdaptor: PromiseAdaptor
9+
// ) {
10+
// fun queryPromise(promiseId: Long) {
11+
//
12+
// }
13+
// }

Whatnow-Infrastructure/src/test/kotlin/com/depromeet/whatnow/config/InfraIntegrateSpringBootTest.kt

+8-6
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ package com.depromeet.whatnow.config
22

33
import org.springframework.boot.test.context.SpringBootTest
44
import org.springframework.test.context.ActiveProfiles
5-
import java.lang.annotation.Documented
6-
import java.lang.annotation.Retention
7-
import java.lang.annotation.RetentionPolicy
5+
import kotlin.annotation.AnnotationRetention.RUNTIME
6+
import kotlin.annotation.Retention
87

98
/** 도메인 모듈의 통합테스트의 편의성을 위해서 만든 어노테이션 -이찬진 */
10-
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
11-
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(
10+
AnnotationTarget.ANNOTATION_CLASS,
11+
AnnotationTarget.CLASS,
12+
)
13+
@Retention(RUNTIME)
1214
@SpringBootTest(classes = [InfraIntegrateTestConfig::class])
1315
@ActiveProfiles(resolver = InfraIntegrateProfileResolver::class)
14-
@Documented
16+
@MustBeDocumented
1517
annotation class InfraIntegrateSpringBootTest

0 commit comments

Comments
 (0)