diff --git a/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/dto/EntireSpotScheduleResponse.kt b/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/dto/EntireSpotScheduleResponse.kt new file mode 100644 index 00000000..e6a0b9e8 --- /dev/null +++ b/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/dto/EntireSpotScheduleResponse.kt @@ -0,0 +1,41 @@ +package team.comit.simtong.domain.schedule.dto + +import java.time.LocalDate +import java.util.UUID + +/** + * + * 모든 지점 일정 조회 정보를 전송하는 EntireSpotScheduleResponse + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +data class EntireSpotScheduleResponse( + val schedules: List +) + +/** + * + * 지점 일정 정보를 전송하는 SpotScheduleResponse + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +data class SpotScheduleResponse( + val id: UUID, + + val startAt: LocalDate, + + val endAt: LocalDate, + + val title: String, + + val spot: SpotElement +) { + data class SpotElement( + val id: UUID, + val name: String + ) +} \ No newline at end of file diff --git a/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCase.kt b/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCase.kt new file mode 100644 index 00000000..24df4ddd --- /dev/null +++ b/simtong-application/src/main/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCase.kt @@ -0,0 +1,41 @@ +package team.comit.simtong.domain.schedule.usecase + +import team.comit.simtong.domain.schedule.dto.EntireSpotScheduleResponse +import team.comit.simtong.domain.schedule.dto.SpotScheduleResponse +import team.comit.simtong.domain.schedule.spi.QuerySchedulePort +import team.comit.simtong.global.annotation.ReadOnlyUseCase +import java.time.LocalDate + +/** + * + * 모든 지점 일정 조회 요청을 담당하는 QuerySpotScheduleUseCase + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +@ReadOnlyUseCase +class EntireSpotScheduleUseCase( + private val querySchedulePort: QuerySchedulePort +) { + + fun execute(date: LocalDate): EntireSpotScheduleResponse { + val list = querySchedulePort.querySchedulesByDateContains(date) + + val response = list.map { + SpotScheduleResponse( + id = it.id, + startAt = it.startAt, + endAt = it.endAt, + title = it.title, + spot = SpotScheduleResponse.SpotElement( + id = it.spotId, + name = it.spotName + ) + ) + } + + return EntireSpotScheduleResponse(response) + } + +} \ No newline at end of file diff --git a/simtong-application/src/main/kotlin/team/comit/simtong/domain/spot/spi/SpotPort.kt b/simtong-application/src/main/kotlin/team/comit/simtong/domain/spot/spi/SpotPort.kt index 38131e7d..3716cde0 100644 --- a/simtong-application/src/main/kotlin/team/comit/simtong/domain/spot/spi/SpotPort.kt +++ b/simtong-application/src/main/kotlin/team/comit/simtong/domain/spot/spi/SpotPort.kt @@ -1,5 +1,6 @@ package team.comit.simtong.domain.spot.spi +import team.comit.simtong.domain.schedule.spi.ScheduleQuerySpotPort import team.comit.simtong.domain.user.spi.UserQuerySpotPort /** @@ -10,4 +11,4 @@ import team.comit.simtong.domain.user.spi.UserQuerySpotPort * @date 2022/09/18 * @version 1.0.0 **/ -interface SpotPort : UserQuerySpotPort, QuerySpotPort \ No newline at end of file +interface SpotPort : UserQuerySpotPort, QuerySpotPort, ScheduleQuerySpotPort \ No newline at end of file diff --git a/simtong-application/src/test/kotlin/team/comit/simtong/.gitkeep b/simtong-application/src/test/kotlin/team/comit/simtong/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/simtong-application/src/test/kotlin/team/comit/simtong/domain/DomainPropertiesInitialization.kt b/simtong-application/src/test/kotlin/team/comit/simtong/domain/DomainPropertiesInitialization.kt index e4c49d2b..ff76e8cb 100644 --- a/simtong-application/src/test/kotlin/team/comit/simtong/domain/DomainPropertiesInitialization.kt +++ b/simtong-application/src/test/kotlin/team/comit/simtong/domain/DomainPropertiesInitialization.kt @@ -12,9 +12,9 @@ class DomainPropertiesInitialization { DomainProperties.putAll( mapOf( Pair(DomainPropertiesPrefix.USER_DEFAULT_IMAGE, "test"), - Pair(DomainPropertiesPrefix.AUTHCODE_EXPIRED, "12345"), - Pair(DomainPropertiesPrefix.AUTHCODELIMIT_EXPIRED, "12345"), - Pair(DomainPropertiesPrefix.AUTHCODELIMIT_VERIFIED_EXPIRED, "12345"), + Pair(DomainPropertiesPrefix.AUTHCODE_EXP, "12345"), + Pair(DomainPropertiesPrefix.AUTHCODELIMIT_EXP, "12345"), + Pair(DomainPropertiesPrefix.AUTHCODELIMIT_VERIFIED_EXP, "12345"), Pair(DomainPropertiesPrefix.AUTHCODELIMIT_MAX_ATTEMPT_COUNT, "12345") ) ) diff --git a/simtong-application/src/test/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCaseTests.kt b/simtong-application/src/test/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCaseTests.kt new file mode 100644 index 00000000..ab3e29d8 --- /dev/null +++ b/simtong-application/src/test/kotlin/team/comit/simtong/domain/schedule/usecase/EntireSpotScheduleUseCaseTests.kt @@ -0,0 +1,75 @@ +package team.comit.simtong.domain.schedule.usecase + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.kotlin.given +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.context.junit.jupiter.SpringExtension +import team.comit.simtong.domain.schedule.dto.EntireSpotScheduleResponse +import team.comit.simtong.domain.schedule.dto.SpotScheduleResponse +import team.comit.simtong.domain.schedule.spi.QuerySchedulePort +import team.comit.simtong.domain.schedule.vo.SpotSchedule +import java.time.LocalDate +import java.util.UUID + +@ExtendWith(SpringExtension::class) +class EntireSpotScheduleUseCaseTests { + + @MockBean + private lateinit var querySchedulePort: QuerySchedulePort + + private lateinit var entireSpotScheduleUseCase: EntireSpotScheduleUseCase + + private val date: LocalDate = LocalDate.now() + + private val uuid: UUID = UUID.randomUUID() + + private val spotScheduleListStub = listOf( + SpotSchedule( + id = uuid, + spotId = uuid, + spotName = "test name", + title = "test title", + startAt = date, + endAt = date + ) + ) + + private val responseStub: EntireSpotScheduleResponse by lazy { + EntireSpotScheduleResponse( + listOf( + SpotScheduleResponse( + id = uuid, + startAt = date, + endAt = date, + title = "test title", + spot = SpotScheduleResponse.SpotElement( + id = uuid, + name = "test name" + ) + ) + ) + ) + } + + @BeforeEach + fun setUp() { + entireSpotScheduleUseCase = EntireSpotScheduleUseCase(querySchedulePort) + } + + @Test + fun `전체 지점 일정 조회 성공`() { + // given + given(querySchedulePort.querySchedulesByDateContains(date)) + .willReturn(spotScheduleListStub) + + // when + val response = entireSpotScheduleUseCase.execute(date) + + // then + assertEquals(response, responseStub) + } + +} \ No newline at end of file diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCode.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCode.kt index cf6b1435..35d17e28 100644 --- a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCode.kt +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCode.kt @@ -31,7 +31,7 @@ data class AuthCode @Default constructor( companion object { @JvmField - val EXPIRED = getProperty(DomainPropertiesPrefix.AUTHCODE_EXPIRED).toInt() + val EXPIRED = getProperty(DomainPropertiesPrefix.AUTHCODE_EXP).toInt() } } \ No newline at end of file diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCodeLimit.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCodeLimit.kt index ebb85bfd..543655c4 100644 --- a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCodeLimit.kt +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/auth/model/AuthCodeLimit.kt @@ -38,10 +38,10 @@ data class AuthCodeLimit @Default constructor( val MAX_ATTEMPT_COUNT: Short = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_MAX_ATTEMPT_COUNT).toShort() @JvmField - val EXPIRED: Int = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_EXPIRED).toInt() + val EXPIRED: Int = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_EXP).toInt() @JvmField - val VERIFIED_EXPIRED: Int = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_VERIFIED_EXPIRED).toInt() + val VERIFIED_EXPIRED: Int = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_VERIFIED_EXP).toInt() fun certified(email: String) = AuthCodeLimit( key = email, diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/QuerySchedulePort.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/QuerySchedulePort.kt index 5aac8c37..bf5256ed 100644 --- a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/QuerySchedulePort.kt +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/QuerySchedulePort.kt @@ -1,6 +1,8 @@ package team.comit.simtong.domain.schedule.spi import team.comit.simtong.domain.schedule.model.Schedule +import team.comit.simtong.domain.schedule.vo.SpotSchedule +import java.time.LocalDate import java.util.UUID /** @@ -15,4 +17,6 @@ interface QuerySchedulePort { fun queryScheduleById(id: UUID): Schedule? + fun querySchedulesByDateContains(date: LocalDate): List + } \ No newline at end of file diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/ScheduleQuerySpotPort.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/ScheduleQuerySpotPort.kt new file mode 100644 index 00000000..de1d1bc8 --- /dev/null +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/spi/ScheduleQuerySpotPort.kt @@ -0,0 +1,18 @@ +package team.comit.simtong.domain.schedule.spi + +import team.comit.simtong.domain.spot.model.Spot +import java.util.UUID + +/** + * + * Schedule Domain에서 Spot에 관한 Query를 요청하는 ScheduleQuerySpotPort + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +interface ScheduleQuerySpotPort { + + fun querySpotById(id: UUID) : Spot? + +} \ No newline at end of file diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/vo/SpotSchedule.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/vo/SpotSchedule.kt new file mode 100644 index 00000000..0c660ad0 --- /dev/null +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/domain/schedule/vo/SpotSchedule.kt @@ -0,0 +1,26 @@ +package team.comit.simtong.domain.schedule.vo + +import java.time.LocalDate +import java.util.UUID + +/** + * + * Schedule과 Schedule의 Spot 정보를 가지는 SpotSchedule + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +open class SpotSchedule( + val id: UUID, + + val title: String, + + val startAt: LocalDate, + + val endAt: LocalDate, + + val spotId: UUID, + + val spotName: String +) \ No newline at end of file diff --git a/simtong-domain/src/main/kotlin/team/comit/simtong/global/DomainPropertiesPrefix.kt b/simtong-domain/src/main/kotlin/team/comit/simtong/global/DomainPropertiesPrefix.kt index e7e60055..74ec11cf 100644 --- a/simtong-domain/src/main/kotlin/team/comit/simtong/global/DomainPropertiesPrefix.kt +++ b/simtong-domain/src/main/kotlin/team/comit/simtong/global/DomainPropertiesPrefix.kt @@ -14,11 +14,11 @@ object DomainPropertiesPrefix { const val USER_DEFAULT_IMAGE = "user.default-image" // AuthCode - const val AUTHCODE_EXPIRED = "authcode.expired" + const val AUTHCODE_EXP = "authcode.exp" // AuthCodeLimit - const val AUTHCODELIMIT_EXPIRED = "authcodelimit.expired" - const val AUTHCODELIMIT_VERIFIED_EXPIRED = "authcodelimit.verified-expired" + const val AUTHCODELIMIT_EXP = "authcodelimit.exp" + const val AUTHCODELIMIT_VERIFIED_EXP = "authcodelimit.verified-exp" const val AUTHCODELIMIT_MAX_ATTEMPT_COUNT = "authcodelimit.max-attempt-count" } \ No newline at end of file diff --git a/simtong-infrastructure/src/main/kotlin/team/comit/simtong/global/security/SecurityConfig.kt b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/global/security/SecurityConfig.kt index 253b1e0d..ade25349 100644 --- a/simtong-infrastructure/src/main/kotlin/team/comit/simtong/global/security/SecurityConfig.kt +++ b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/global/security/SecurityConfig.kt @@ -75,6 +75,7 @@ class SecurityConfig( .antMatchers(HttpMethod.POST, "/files/list").permitAll() // schedules + .antMatchers(HttpMethod.GET, "/schedules/spots").hasAnyRole(ROLE_ADMIN.role, ROLE_SUPER.role) .antMatchers(HttpMethod.POST, "/schedules/spots/{spot-id}").hasAnyRole(ROLE_ADMIN.role, ROLE_SUPER.role) .antMatchers(HttpMethod.PUT, "/schedules/spots/{schedule-id}").hasAnyRole(ROLE_ADMIN.role, ROLE_SUPER.role) .antMatchers(HttpMethod.DELETE, "/schedules/spots/{schedule-id}").hasAnyRole(ROLE_ADMIN.role, ROLE_SUPER.role) diff --git a/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/SchedulePersistenceAdapter.kt b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/SchedulePersistenceAdapter.kt index 1400ad80..366ed4d6 100644 --- a/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/SchedulePersistenceAdapter.kt +++ b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/SchedulePersistenceAdapter.kt @@ -1,11 +1,17 @@ package team.comit.simtong.persistence.schedule +import com.querydsl.jpa.impl.JPAQueryFactory import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Component import team.comit.simtong.domain.schedule.model.Schedule import team.comit.simtong.domain.schedule.spi.SchedulePort +import team.comit.simtong.domain.schedule.vo.SpotSchedule import team.comit.simtong.persistence.schedule.mapper.ScheduleMapper +import team.comit.simtong.persistence.schedule.vo.QSpotScheduleVo +import java.time.LocalDate import java.util.UUID +import team.comit.simtong.persistence.schedule.entity.QScheduleJpaEntity.scheduleJpaEntity as schedule +import team.comit.simtong.persistence.spot.entity.QSpotJpaEntity.spotJpaEntity as spot /** * @@ -18,7 +24,8 @@ import java.util.UUID @Component class SchedulePersistenceAdapter( private val scheduleJpaRepository: ScheduleJpaRepository, - private val scheduleMapper: ScheduleMapper + private val scheduleMapper: ScheduleMapper, + private val queryFactory: JPAQueryFactory ) : SchedulePort { override fun save(schedule: Schedule) = scheduleMapper.toDomain( @@ -39,4 +46,29 @@ class SchedulePersistenceAdapter( ) } + override fun querySchedulesByDateContains(date: LocalDate): List { + val startDate = date.withDayOfMonth(1) + val endDate = date.withDayOfMonth(date.lengthOfMonth()) + + return queryFactory + .select( + QSpotScheduleVo( + schedule.id, + schedule.title, + schedule.startAt, + schedule.endAt, + spot.id, + spot.name + )) + .from(schedule) + .join(spot) + .on(schedule.spot.eq(spot)) + .where( + schedule.startAt.between(startDate, endDate) + .or(schedule.endAt.between(startDate, endDate)) + ) + .orderBy(schedule.startAt.asc()) + .fetch() + } + } \ No newline at end of file diff --git a/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/vo/SpotScheduleVo.kt b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/vo/SpotScheduleVo.kt new file mode 100644 index 00000000..1eb0f121 --- /dev/null +++ b/simtong-infrastructure/src/main/kotlin/team/comit/simtong/persistence/schedule/vo/SpotScheduleVo.kt @@ -0,0 +1,30 @@ +package team.comit.simtong.persistence.schedule.vo + +import com.querydsl.core.annotations.QueryProjection +import team.comit.simtong.domain.schedule.vo.SpotSchedule +import java.time.LocalDate +import java.util.UUID + +/** + * + * Schedule과 Schedule의 Spot 정보를 가져오는 SpotScheduleVo + * + * @author Chokyunghyeon + * @date 2022/11/26 + * @version 1.0.0 + **/ +class SpotScheduleVo @QueryProjection constructor( + id: UUID, + title: String, + startAt: LocalDate, + endAt: LocalDate, + spotId: UUID, + spotName: String +) : SpotSchedule( + id = id, + title = title, + startAt = startAt, + endAt = endAt, + spotId = spotId, + spotName = spotName +) diff --git a/simtong-infrastructure/src/main/resources/application.yml b/simtong-infrastructure/src/main/resources/application.yml index 7d1a26c2..84840f0e 100644 --- a/simtong-infrastructure/src/main/resources/application.yml +++ b/simtong-infrastructure/src/main/resources/application.yml @@ -20,10 +20,10 @@ domain: user: default-image: ${USER_DEFAULT_IMAGE:TODO} authcode: - expired: ${AUTHCODE_EXPIRED:1234567890} + exp: ${AUTHCODE_EXP:1234567890} authcodelimit: - expired: ${AUTHCODELIMIT_EXPIRED:1234567890} - verified-expired: ${AUTHCODELIMIT_VERIFIED_EXPIRED:1234567890} + exp: ${AUTHCODELIMIT_EXP:1234567890} + verified-exp: ${AUTHCODELIMIT_VERIFIED_EXP:1234567890} max-attempt-count: ${AUTHCODELIMIT_MAX_ATTEMPT_COUNT:12345}