Skip to content

Commit

Permalink
merge: (#156) 개인 일정 변경 기능 설계 (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
khcho0125 authored Nov 27, 2022
2 parents 6bf03bf + 12df0a4 commit b7c200d
Show file tree
Hide file tree
Showing 15 changed files with 404 additions and 16 deletions.
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

0 comments on commit b7c200d

Please sign in to comment.