Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge: (#156) 개인 일정 변경 기능 설계 #157

Merged
merged 10 commits into from
Nov 27, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package team.comit.simtong.domain.schedule.dto

import java.time.LocalDate
import java.time.LocalTime
import java.util.UUID

/**
*
* 개인 일정 변경 요청 정보를 전달하는 ChangeIndividualScheduleRequest
*
* @author Chokyunghyeon
* @date 2022/11/27
* @version 1.0.0
**/
data class ChangeIndividualScheduleRequest(

val scheduleId: UUID,

val title: String,

val startAt: LocalDate,

val endAt: LocalDate,

val alarm: LocalTime
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package team.comit.simtong.domain.schedule.usecase

import team.comit.simtong.domain.schedule.dto.ChangeIndividualScheduleRequest
import team.comit.simtong.domain.schedule.exception.NotScheduleOwnerException
import team.comit.simtong.domain.schedule.exception.ScheduleNotFoundException
import team.comit.simtong.domain.schedule.spi.CommandSchedulePort
import team.comit.simtong.domain.schedule.spi.QuerySchedulePort
import team.comit.simtong.domain.schedule.spi.ScheduleQueryUserPort
import team.comit.simtong.domain.schedule.spi.ScheduleSecurityPort
import team.comit.simtong.domain.user.exception.UserNotFoundException
import team.comit.simtong.global.annotation.UseCase

/**
*
* 개인 일정 정보 변경 요청을 담당하는 ChangeIndividualScheduleUseCase
*
* @author Chokyunghyeon
* @date 2022/11/27
* @version 1.0.0
**/
@UseCase
class ChangeIndividualScheduleUseCase(
private val queryUserPort: ScheduleQueryUserPort,
private val querySchedulePort: QuerySchedulePort,
private val commandSchedulePort: CommandSchedulePort,
private val securityPort: ScheduleSecurityPort
) {

fun execute(request: ChangeIndividualScheduleRequest) {
val currentUserId = securityPort.getCurrentUserId()
val (scheduleId, title, startAt, endAt, alarm) = request

val schedule = querySchedulePort.queryScheduleById(scheduleId)
?: throw ScheduleNotFoundException.EXCEPTION

val user = queryUserPort.queryUserById(currentUserId)
?: throw UserNotFoundException.EXCEPTION

if (user.id != schedule.userId) {
throw NotScheduleOwnerException.EXCEPTION
}

commandSchedulePort.save(
schedule.copy(
title = title,
startAt = startAt,
endAt = endAt,
alarmTime = alarm
)
)
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package team.comit.simtong.domain.schedule.usecase

import team.comit.simtong.domain.schedule.dto.ChangeSpotScheduleRequest
import team.comit.simtong.domain.schedule.exception.NotScheduleOwnerException
import team.comit.simtong.domain.schedule.exception.ScheduleNotFoundException
import team.comit.simtong.domain.schedule.model.Scope
import team.comit.simtong.domain.schedule.spi.CommandSchedulePort
import team.comit.simtong.domain.schedule.spi.QuerySchedulePort
import team.comit.simtong.domain.schedule.spi.ScheduleQueryUserPort
Expand Down Expand Up @@ -36,8 +38,11 @@ class ChangeSpotScheduleUseCase(
val schedule = querySchedulePort.queryScheduleById(request.scheduleId)
?: throw ScheduleNotFoundException.EXCEPTION

if (user.spotId != schedule.spotId && user.authority != Authority.ROLE_SUPER) {
throw NotEnoughPermissionException.EXCEPTION
when {
Scope.ENTIRE != schedule.scope -> throw NotScheduleOwnerException.EXCEPTION

user.spotId != schedule.spotId &&
Authority.ROLE_SUPER != user.authority -> throw NotEnoughPermissionException.EXCEPTION
}

commandSchedulePort.save(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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.model.Scope
import team.comit.simtong.domain.schedule.spi.QuerySchedulePort
import team.comit.simtong.global.annotation.ReadOnlyUseCase
import java.time.LocalDate
Expand All @@ -20,7 +21,7 @@ class EntireSpotScheduleUseCase(
) {

fun execute(date: LocalDate): EntireSpotScheduleResponse {
val list = querySchedulePort.querySchedulesByDateContains(date)
val list = querySchedulePort.querySchedulesByMonthAndScope(date, Scope.ENTIRE)

val response = list.map {
SpotScheduleResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package team.comit.simtong.domain.schedule.usecase

import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock
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.ChangeIndividualScheduleRequest
import team.comit.simtong.domain.schedule.exception.NotScheduleOwnerException
import team.comit.simtong.domain.schedule.exception.ScheduleNotFoundException
import team.comit.simtong.domain.schedule.model.Schedule
import team.comit.simtong.domain.schedule.model.Scope
import team.comit.simtong.domain.schedule.spi.CommandSchedulePort
import team.comit.simtong.domain.schedule.spi.QuerySchedulePort
import team.comit.simtong.domain.schedule.spi.ScheduleQueryUserPort
import team.comit.simtong.domain.schedule.spi.ScheduleSecurityPort
import team.comit.simtong.domain.user.exception.UserNotFoundException
import team.comit.simtong.domain.user.model.Authority
import team.comit.simtong.domain.user.model.User
import java.time.LocalDate
import java.time.LocalTime
import java.util.UUID

@ExtendWith(SpringExtension::class)
class ChangeIndividualScheduleUseCaseTest {

@MockBean
private lateinit var queryUserPort: ScheduleQueryUserPort

@MockBean
private lateinit var querySchedulePort: QuerySchedulePort

@MockBean
private lateinit var commandSchedulePort: CommandSchedulePort

@Mock
private lateinit var securityPort: ScheduleSecurityPort

private lateinit var changeIndividualScheduleUseCase: ChangeIndividualScheduleUseCase

@BeforeEach
fun setUp() {
changeIndividualScheduleUseCase = ChangeIndividualScheduleUseCase(
queryUserPort = queryUserPort,
querySchedulePort = querySchedulePort,
commandSchedulePort = commandSchedulePort,
securityPort = securityPort
)
}

private val userId = UUID.randomUUID()

private val spotId = UUID.randomUUID()

private val scheduleId= UUID.randomUUID()

private val userStub: User by lazy {
User(
id = userId,
nickname = "test nickname",
name = "test name",
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
authority = Authority.ROLE_COMMON,
spotId = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
)
}

private val scheduleStub: Schedule by lazy {
Schedule(
id = scheduleId,
userId = userId,
spotId = spotId,
title = "test title",
scope = Scope.INDIVIDUAL,
startAt = LocalDate.now(),
endAt = LocalDate.now(),
alarmTime = Schedule.DEFAULT_ALARM_TIME
)
}

private val requestStub: ChangeIndividualScheduleRequest by lazy {
ChangeIndividualScheduleRequest(
scheduleId = scheduleId,
title = "test title",
startAt = LocalDate.now(),
endAt = LocalDate.now(),
alarm = LocalTime.now()
)
}

@Test
fun `개인 일정 변경 성공`() {
// given
given(securityPort.getCurrentUserId())
.willReturn(userId)

given(querySchedulePort.queryScheduleById(requestStub.scheduleId))
.willReturn(scheduleStub)

given(queryUserPort.queryUserById(userId))
.willReturn(userStub)

// when & then
assertDoesNotThrow {
changeIndividualScheduleUseCase.execute(requestStub)
}
}

@Test
fun `소유자가 아님`() {
// given
val otherScheduleStub = Schedule(
id = scheduleId,
userId = UUID.randomUUID(),
spotId = spotId,
title = "test title",
scope = Scope.INDIVIDUAL,
startAt = LocalDate.now(),
endAt = LocalDate.now(),
alarmTime = Schedule.DEFAULT_ALARM_TIME
)

given(securityPort.getCurrentUserId())
.willReturn(userId)

given(querySchedulePort.queryScheduleById(requestStub.scheduleId))
.willReturn(otherScheduleStub)

given(queryUserPort.queryUserById(userId))
.willReturn(userStub)

// when & then
assertThrows<NotScheduleOwnerException> {
changeIndividualScheduleUseCase.execute(requestStub)
}
}

@Test
fun `유저를 찾을 수 없음`() {
// given
given(securityPort.getCurrentUserId())
.willReturn(userId)

given(querySchedulePort.queryScheduleById(requestStub.scheduleId))
.willReturn(scheduleStub)

given(queryUserPort.queryUserById(userId))
.willReturn(null)

// when & then
assertThrows<UserNotFoundException> {
changeIndividualScheduleUseCase.execute(requestStub)
}
}

@Test
fun `일정을 찾을 수 없음`() {
// given
given(securityPort.getCurrentUserId())
.willReturn(userId)

given(querySchedulePort.queryScheduleById(requestStub.scheduleId))
.willReturn(null)

// when & then
assertThrows<ScheduleNotFoundException> {
changeIndividualScheduleUseCase.execute(requestStub)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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.ChangeSpotScheduleRequest
import team.comit.simtong.domain.schedule.exception.NotScheduleOwnerException
import team.comit.simtong.domain.schedule.exception.ScheduleNotFoundException
import team.comit.simtong.domain.schedule.model.Schedule
import team.comit.simtong.domain.schedule.model.Scope
Expand Down Expand Up @@ -88,7 +89,7 @@ class ChangeSpotScheduleUseCaseTests {
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
Authority.ROLE_ADMIN,
authority = Authority.ROLE_ADMIN,
spotId = spotId,
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
Expand All @@ -109,6 +110,48 @@ class ChangeSpotScheduleUseCaseTests {
}
}

@Test
fun `지점 일정이 아님`() {
// given
val userStub = User(
id = userId,
nickname = "test nickname",
name = "test name",
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
authority = Authority.ROLE_ADMIN,
spotId = spotId,
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
)

val individualScheduleStub = Schedule(
id = scheduleId,
userId = userId,
spotId = spotId,
title = "test title",
scope = Scope.INDIVIDUAL,
startAt = LocalDate.now(),
endAt = LocalDate.now(),
alarmTime = Schedule.DEFAULT_ALARM_TIME
)

given(securityPort.getCurrentUserId())
.willReturn(userId)

given(queryUserPort.queryUserById(userId))
.willReturn(userStub)

given(querySchedulePort.queryScheduleById(requestStub.scheduleId))
.willReturn(individualScheduleStub)

// when & then
assertThrows<NotScheduleOwnerException> {
changeSpotScheduleUseCase.execute(requestStub)
}
}

@Test
fun `권한이 부족함`() {
// given
Expand All @@ -119,7 +162,7 @@ class ChangeSpotScheduleUseCaseTests {
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
Authority.ROLE_ADMIN,
authority = Authority.ROLE_ADMIN,
spotId = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
Expand Down Expand Up @@ -150,7 +193,7 @@ class ChangeSpotScheduleUseCaseTests {
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
Authority.ROLE_SUPER,
authority = Authority.ROLE_SUPER,
spotId = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
Expand Down Expand Up @@ -181,7 +224,7 @@ class ChangeSpotScheduleUseCaseTests {
email = "[email protected]",
password = "test password",
employeeNumber = 1234567890,
Authority.ROLE_ADMIN,
authority = Authority.ROLE_ADMIN,
spotId = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
Expand Down
Loading