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: (#143) 지점 일정 삭제 기능 #146

Merged
merged 6 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM eclipse-temurin:17-jre-focal
FROM openjdk:17-jre-alpine

EXPOSE 8080
ENV TZ=Asia/Seoul
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ interface CommandSchedulePort {

fun save(schedule: Schedule): Schedule

fun delete(schedule: Schedule)

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

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.NotEnoughPermissionException
import team.comit.simtong.domain.user.exception.UserNotFoundException
import team.comit.simtong.domain.user.model.Authority
import team.comit.simtong.global.annotation.UseCase
import java.util.UUID

/**
*
* 지점 일정 삭제를 담당하는 RemoveSpotScheduleUseCase
*
* @author Chokyunghyeon
* @date 2022/11/22
* @version 1.0.0
**/
@UseCase
class RemoveSpotScheduleUseCase(
private val queryUserPort: ScheduleQueryUserPort,
private val querySchedulePort: QuerySchedulePort,
private val commandSchedulePort: CommandSchedulePort,
private val securityPort: ScheduleSecurityPort
) {

fun execute(scheduleId: UUID) {
val currentUserId = securityPort.getCurrentUserId()

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

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

if (user.spotId != schedule.spotId && user.authority != Authority.ROLE_SUPER) {
throw NotEnoughPermissionException.EXCEPTION
}

commandSchedulePort.delete(schedule)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
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.kotlin.given
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension
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.NotEnoughPermissionException
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.util.UUID

@ExtendWith(SpringExtension::class)
class RemoveSpotScheduleUseCaseTests {

@MockBean
private lateinit var queryUserPort: ScheduleQueryUserPort

@MockBean
private lateinit var querySchedulePort: QuerySchedulePort

@MockBean
private lateinit var commandSchedulePort: CommandSchedulePort

@MockBean
private lateinit var securityPort: ScheduleSecurityPort

private lateinit var removeSpotScheduleUseCase: RemoveSpotScheduleUseCase

private val userId = UUID.randomUUID()

private val spotId = UUID.randomUUID()

private val scheduleId = UUID.randomUUID()

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

@BeforeEach
fun setUp() {
removeSpotScheduleUseCase = RemoveSpotScheduleUseCase(
queryUserPort = queryUserPort,
querySchedulePort = querySchedulePort,
commandSchedulePort = commandSchedulePort,
securityPort = securityPort
)
}

@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"
)

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

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

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

// when & then
assertDoesNotThrow {
removeSpotScheduleUseCase.execute(scheduleId)
}
}

@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_SUPER,
spotId = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
)

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

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

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

// when & then
assertDoesNotThrow {
removeSpotScheduleUseCase.execute(scheduleId)
}
}

@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 = UUID.randomUUID(),
teamId = UUID.randomUUID(),
profileImagePath = "test profile image"
)

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

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

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

// when & then
assertThrows<NotEnoughPermissionException> {
removeSpotScheduleUseCase.execute(scheduleId)
}
}

@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"
)

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

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

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

// when & then
assertThrows<ScheduleNotFoundException> {
removeSpotScheduleUseCase.execute(scheduleId)
}
}

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

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

// when & then
assertThrows<UserNotFoundException> {
removeSpotScheduleUseCase.execute(scheduleId)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class SecurityConfig(
// schedules
.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)

// admins
.antMatchers(HttpMethod.POST, "/admins/tokens").permitAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ class SchedulePersistenceAdapter(
)
)!!

override fun delete(schedule: Schedule) {
scheduleJpaRepository.delete(
scheduleMapper.toEntity(schedule)
)
}

override fun queryScheduleById(id: UUID): Schedule? {
return scheduleMapper.toDomain(
scheduleJpaRepository.findByIdOrNull(id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package team.comit.simtong.schedule

import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
Expand All @@ -12,6 +13,7 @@ import team.comit.simtong.domain.schedule.dto.AddSpotScheduleRequest
import team.comit.simtong.domain.schedule.dto.ChangeSpotScheduleRequest
import team.comit.simtong.domain.schedule.usecase.AddSpotScheduleUseCase
import team.comit.simtong.domain.schedule.usecase.ChangeSpotScheduleUseCase
import team.comit.simtong.domain.schedule.usecase.RemoveSpotScheduleUseCase
import team.comit.simtong.schedule.dto.request.AddSpotScheduleWebRequest
import team.comit.simtong.schedule.dto.request.ChangeSpotScheduleWebRequest
import java.util.UUID
Expand All @@ -29,7 +31,8 @@ import javax.validation.Valid
@RequestMapping("/schedules")
class WebScheduleAdapter(
private val addSpotScheduleUseCase: AddSpotScheduleUseCase,
private val changeSpotScheduleUseCase: ChangeSpotScheduleUseCase
private val changeSpotScheduleUseCase: ChangeSpotScheduleUseCase,
private val removeSpotScheduleUseCase: RemoveSpotScheduleUseCase
) {

@PostMapping("/spots/{spot-id}")
Expand Down Expand Up @@ -59,4 +62,10 @@ class WebScheduleAdapter(
)
)
}

@DeleteMapping("/spots/{schedule-id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun removeSpotSchedule(@PathVariable("schedule-id") scheduleId: UUID) {
removeSpotScheduleUseCase.execute(scheduleId)
}
}