diff --git a/src/main/kotlin/land/leets/domain/application/presentation/ApplicationController.kt b/src/main/kotlin/land/leets/domain/application/presentation/ApplicationController.kt index d7d8c71..8173b96 100644 --- a/src/main/kotlin/land/leets/domain/application/presentation/ApplicationController.kt +++ b/src/main/kotlin/land/leets/domain/application/presentation/ApplicationController.kt @@ -45,7 +45,7 @@ class ApplicationController( return createApplication.execute(authDetails, request) } - @Operation(summary = "(유저) 지원서 수정", description = "지원서를 수정합니다.") + @Operation(summary = "(유저) 지원서 수정 (미사용)", description = "지원서를 수정합니다. (미사용)") @ApiResponses( ApiResponse(responseCode = "200"), ApiResponse(responseCode = "400", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), diff --git a/src/main/kotlin/land/leets/domain/application/type/Position.kt b/src/main/kotlin/land/leets/domain/application/type/Position.kt index 676640a..0405e42 100644 --- a/src/main/kotlin/land/leets/domain/application/type/Position.kt +++ b/src/main/kotlin/land/leets/domain/application/type/Position.kt @@ -2,6 +2,8 @@ package land.leets.domain.application.type enum class Position(val statusKo: String) { DEV("개발"), + FRONTEND("프론트엔드"), + BACKEND("백엔드"), DESIGN("디자인"), BX_BI("BX/BI"), UX_UI("UX/UI"), diff --git a/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt b/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt index c55248e..92a66e2 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/CreateApplicationImpl.kt @@ -6,6 +6,7 @@ import land.leets.domain.application.exception.ApplicationAlreadyExistsException import land.leets.domain.application.presentation.dto.ApplicationRequest import land.leets.domain.application.type.SubmitStatus import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository import land.leets.domain.user.domain.User import land.leets.domain.user.domain.repository.UserRepository import land.leets.domain.user.exception.UserNotFoundException @@ -15,7 +16,8 @@ import java.time.LocalDateTime @Service class CreateApplicationImpl( private val applicationRepository: ApplicationRepository, - private val userRepository: UserRepository + private val userRepository: UserRepository, + private val temporaryApplicationRepository: TemporaryApplicationRepository ) : CreateApplication { override fun execute(authDetails: AuthDetails, request: ApplicationRequest): Application { @@ -48,6 +50,12 @@ class CreateApplicationImpl( submitStatus = request.submitStatus, appliedAt = if (request.submitStatus == SubmitStatus.SUBMIT) LocalDateTime.now() else null ) - return applicationRepository.save(application) + val savedApplication = applicationRepository.save(application) + + temporaryApplicationRepository.findByUser_Id(user.id)?.let { + temporaryApplicationRepository.delete(it) + } + + return savedApplication } } diff --git a/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplication.kt b/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplication.kt index f26783d..ae0e394 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplication.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplication.kt @@ -4,6 +4,7 @@ import land.leets.domain.application.domain.Application import land.leets.domain.application.presentation.dto.ApplicationRequest import land.leets.domain.auth.AuthDetails +@Deprecated("임시 저장 테이블 분리에 따른 미사용") interface UpdateApplication { fun execute(authDetails: AuthDetails, request: ApplicationRequest): Application } diff --git a/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplicationImpl.kt b/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplicationImpl.kt index a40e7e1..95c521b 100644 --- a/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplicationImpl.kt +++ b/src/main/kotlin/land/leets/domain/application/usecase/UpdateApplicationImpl.kt @@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional import java.time.LocalDateTime @Service +@Deprecated("임시 저장 테이블 분리에 따른 미사용") class UpdateApplicationImpl( private val applicationRepository: ApplicationRepository, private val updateUser: UpdateUser diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/domain/TemporaryApplication.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/domain/TemporaryApplication.kt new file mode 100644 index 0000000..e0147ff --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/domain/TemporaryApplication.kt @@ -0,0 +1,112 @@ +package land.leets.domain.temporaryApplication.domain + +import jakarta.persistence.* +import land.leets.domain.application.type.Position +import land.leets.domain.shared.BaseTimeEntity +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationRequest +import land.leets.domain.user.domain.User + +@Entity(name = "temporary_applications") +class TemporaryApplication( + + @OneToOne + @JoinColumn(name = "user_id") + var user: User, + + @Column + var name: String? = null, + + @Column + var phone: String? = null, + + @Column + var major: String? = null, + + @Column + var grade: String? = null, + + @Column + var project: String? = null, + + @Column + var algorithm: String? = null, + + @Column + var portfolio: String? = null, + + @Column(columnDefinition = "char(10)") + @Enumerated(EnumType.STRING) + var position: Position, + + @Column + var career: String? = null, + + @Column + var interviewDay: String? = null, + + @Column + var interviewTime: String? = null, + + @Column(columnDefinition = "text(600)") + var motive: String? = null, + + @Column(columnDefinition = "text(600)") + var expectation: String? = null, + + @Column(columnDefinition = "text(600)") + var capability: String? = null, + + @Column(columnDefinition = "text(600)") + var conflict: String? = null, + + @Column(columnDefinition = "text(600)") + var passion: String? = null, + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null +) : BaseTimeEntity() { + + fun updateContent(request: TemporaryApplicationRequest) { + name = request.name + phone = request.phone + major = request.major + grade = request.grade + project = request.project + algorithm = request.algorithm + portfolio = request.portfolio + position = request.position + career = request.career + interviewDay = request.interviewDay + interviewTime = request.interviewTime + motive = request.motive + expectation = request.expectation + capability = request.capability + conflict = request.conflict + passion = request.passion + } + + companion object { + fun of(user: User, request: TemporaryApplicationRequest): TemporaryApplication { + return TemporaryApplication( + user = user, + name = request.name, + phone = request.phone, + major = request.major, + grade = request.grade, + project = request.project, + algorithm = request.algorithm, + portfolio = request.portfolio, + position = request.position, + career = request.career, + interviewDay = request.interviewDay, + interviewTime = request.interviewTime, + motive = request.motive, + expectation = request.expectation, + capability = request.capability, + conflict = request.conflict, + passion = request.passion + ) + } + } +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/domain/repository/TemporaryApplicationRepository.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/domain/repository/TemporaryApplicationRepository.kt new file mode 100644 index 0000000..cc39c88 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/domain/repository/TemporaryApplicationRepository.kt @@ -0,0 +1,9 @@ +package land.leets.domain.temporaryApplication.domain.repository + +import land.leets.domain.temporaryApplication.domain.TemporaryApplication +import org.springframework.data.jpa.repository.JpaRepository +import java.util.* + +interface TemporaryApplicationRepository : JpaRepository { + fun findByUser_Id(id: UUID): TemporaryApplication? +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/TemporaryApplicationController.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/TemporaryApplicationController.kt new file mode 100644 index 0000000..03716aa --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/TemporaryApplicationController.kt @@ -0,0 +1,52 @@ +package land.leets.domain.temporaryApplication.presentation + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationRequest +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationResponse +import land.leets.domain.temporaryApplication.usecase.GetTemporaryApplication +import land.leets.domain.temporaryApplication.usecase.SaveTemporaryApplication +import land.leets.global.error.ErrorResponse +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/temporary-application") +class TemporaryApplicationController( + private val getTemporaryApplication: GetTemporaryApplication, + private val saveTemporaryApplication: SaveTemporaryApplication +) { + + @Operation(summary = "(유저) 임시저장 지원서 조회", description = "임시 저장한 지원서를 호출합니다.") + @ApiResponses( + ApiResponse(responseCode = "200"), + ApiResponse(responseCode = "400", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "403", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "404", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "500", content = [Content(schema = Schema(implementation = ErrorResponse::class))]) + ) + @GetMapping + fun get( + @AuthenticationPrincipal authDetails: AuthDetails + ): TemporaryApplicationResponse? = + getTemporaryApplication.execute(authDetails) + + @Operation(summary = "(유저) 지원서 임시 저장", description = "지원서를 작성합니다.") + @ApiResponses( + ApiResponse(responseCode = "200"), + ApiResponse(responseCode = "400", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "403", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "404", content = [Content(schema = Schema(implementation = ErrorResponse::class))]), + ApiResponse(responseCode = "500", content = [Content(schema = Schema(implementation = ErrorResponse::class))]) + ) + @PutMapping + fun save( + @AuthenticationPrincipal authDetails: AuthDetails, + @RequestBody request: TemporaryApplicationRequest + ): TemporaryApplicationResponse = + saveTemporaryApplication.execute(authDetails, request) +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationRequest.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationRequest.kt new file mode 100644 index 0000000..8a28692 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationRequest.kt @@ -0,0 +1,23 @@ +package land.leets.domain.temporaryApplication.presentation.dto + +import land.leets.domain.application.type.Position + +data class TemporaryApplicationRequest( + val name: String?, + val sid: String?, + val phone: String?, + val major: String?, + val grade: String?, + val project: String?, + val algorithm: String?, + val portfolio: String?, + val position: Position, + val career: String?, + val interviewDay: String?, + val interviewTime: String?, + val motive: String?, + val expectation: String?, + val capability: String?, + val conflict: String?, + val passion: String? +) diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationResponse.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationResponse.kt new file mode 100644 index 0000000..c61351b --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/presentation/dto/TemporaryApplicationResponse.kt @@ -0,0 +1,46 @@ +package land.leets.domain.temporaryApplication.presentation.dto + +import land.leets.domain.application.type.Position +import land.leets.domain.temporaryApplication.domain.TemporaryApplication + +data class TemporaryApplicationResponse( + val name: String?, + val phone: String?, + val major: String?, + val grade: String?, + val project: String?, + val algorithm: String?, + val portfolio: String?, + val position: Position, + val career: String?, + val interviewDay: String?, + val interviewTime: String?, + val motive: String?, + val expectation: String?, + val capability: String?, + val conflict: String?, + val passion: String? +) { + companion object { + fun from(temporaryApplication: TemporaryApplication): TemporaryApplicationResponse { + return TemporaryApplicationResponse( + name = temporaryApplication.name, + phone = temporaryApplication.phone, + major = temporaryApplication.major, + grade = temporaryApplication.grade, + project = temporaryApplication.project, + algorithm = temporaryApplication.algorithm, + portfolio = temporaryApplication.portfolio, + position = temporaryApplication.position, + career = temporaryApplication.career, + interviewDay = temporaryApplication.interviewDay, + interviewTime = temporaryApplication.interviewTime, + motive = temporaryApplication.motive, + expectation = temporaryApplication.expectation, + capability = temporaryApplication.capability, + conflict = temporaryApplication.conflict, + passion = temporaryApplication.passion + ) + } + } +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplication.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplication.kt new file mode 100644 index 0000000..fe78841 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplication.kt @@ -0,0 +1,8 @@ +package land.leets.domain.temporaryApplication.usecase + +import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationResponse + +interface GetTemporaryApplication { + fun execute(authDetails: AuthDetails): TemporaryApplicationResponse? +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImpl.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImpl.kt new file mode 100644 index 0000000..2b857a0 --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImpl.kt @@ -0,0 +1,17 @@ +package land.leets.domain.temporaryApplication.usecase + +import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationResponse +import org.springframework.stereotype.Service + +@Service +class GetTemporaryApplicationImpl( + private val temporaryApplicationRepository: TemporaryApplicationRepository +) : GetTemporaryApplication { + + override fun execute(authDetails: AuthDetails): TemporaryApplicationResponse? { + return temporaryApplicationRepository.findByUser_Id(authDetails.uid) + ?.let { TemporaryApplicationResponse.from(it) } + } +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplication.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplication.kt new file mode 100644 index 0000000..a6941de --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplication.kt @@ -0,0 +1,9 @@ +package land.leets.domain.temporaryApplication.usecase + +import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationRequest +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationResponse + +interface SaveTemporaryApplication { + fun execute(authDetails: AuthDetails, request: TemporaryApplicationRequest): TemporaryApplicationResponse +} diff --git a/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImpl.kt b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImpl.kt new file mode 100644 index 0000000..1d34a2a --- /dev/null +++ b/src/main/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImpl.kt @@ -0,0 +1,34 @@ +package land.leets.domain.temporaryApplication.usecase + +import land.leets.domain.auth.AuthDetails +import land.leets.domain.temporaryApplication.domain.TemporaryApplication +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationRequest +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationResponse +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import org.springframework.stereotype.Service + +@Service +class SaveTemporaryApplicationImpl( + private val temporaryApplicationRepository: TemporaryApplicationRepository, + private val userRepository: UserRepository, +) : SaveTemporaryApplication { + + override fun execute(authDetails: AuthDetails, request: TemporaryApplicationRequest): TemporaryApplicationResponse { + val user = userRepository.findById(authDetails.uid).orElseThrow { UserNotFoundException() } + + val temporaryApplication = temporaryApplicationRepository.findByUser_Id(user.id!!) + ?.also { it.updateContent(request) } + ?: TemporaryApplication.of(user, request) + + request.phone?.let { phone -> + user.updateUserInfo(request.sid, phone) + userRepository.save(user) + } + + return TemporaryApplicationResponse.from( + temporaryApplicationRepository.save(temporaryApplication) + ) + } +} diff --git a/src/main/kotlin/land/leets/global/config/SecurityConfig.kt b/src/main/kotlin/land/leets/global/config/SecurityConfig.kt index cca7061..34e454a 100644 --- a/src/main/kotlin/land/leets/global/config/SecurityConfig.kt +++ b/src/main/kotlin/land/leets/global/config/SecurityConfig.kt @@ -82,6 +82,10 @@ class SecurityConfig( authorize(HttpMethod.GET, "/application/{id}", hasAuthority(AuthRole.ROLE_ADMIN.role)) authorize(HttpMethod.PATCH, "/application/{id}", hasAuthority(AuthRole.ROLE_ADMIN.role)) + // temporary applications + authorize(HttpMethod.GET, "/temporary-application", hasAuthority(AuthRole.ROLE_USER.role)) + authorize(HttpMethod.PUT, "/temporary-application", hasAuthority(AuthRole.ROLE_USER.role)) + // interviews authorize(HttpMethod.PATCH, "/interview", hasAuthority(AuthRole.ROLE_USER.role)) authorize(HttpMethod.POST, "/interview/{id}", hasAuthority(AuthRole.ROLE_ADMIN.role)) diff --git a/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt b/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt index 86665b1..d2e48a5 100644 --- a/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt +++ b/src/test/kotlin/land/leets/domain/application/usecase/CreateApplicationImplTest.kt @@ -14,6 +14,8 @@ import land.leets.domain.application.type.Position import land.leets.domain.application.type.SubmitStatus import land.leets.domain.auth.AuthDetails import land.leets.domain.shared.AuthRole +import land.leets.domain.temporaryApplication.domain.TemporaryApplication +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository import land.leets.domain.user.domain.User import land.leets.domain.user.domain.repository.UserRepository import java.util.* @@ -21,8 +23,9 @@ import java.util.* class CreateApplicationImplTest : DescribeSpec({ val applicationRepository = mockk() + val temporaryApplicationRepository = mockk() val userRepository = mockk() - val createApplication = CreateApplicationImpl(applicationRepository, userRepository) + val createApplication = CreateApplicationImpl(applicationRepository, userRepository, temporaryApplicationRepository) describe("CreateApplicationImpl 유스케이스는") { context("지원서 생성을 요청할 때") { @@ -62,6 +65,7 @@ class CreateApplicationImplTest : DescribeSpec({ every { applicationRepository.findByUser_Id(uid) } returns null every { userRepository.save(any()) } returns user every { applicationRepository.save(any()) } returnsArgument 0 + every { temporaryApplicationRepository.findByUser_Id(uid) } returns null val result = createApplication.execute(authDetails, request) @@ -70,6 +74,21 @@ class CreateApplicationImplTest : DescribeSpec({ verify { applicationRepository.save(any()) } } + it("임시 저장 지원서가 있으면 삭제한다") { + val temporaryApplication = mockk() + every { userRepository.findById(uid) } returns Optional.of(user) + every { applicationRepository.findByUser_Id(uid) } returns null + every { userRepository.save(any()) } returns user + every { applicationRepository.save(any()) } returnsArgument 0 + every { temporaryApplicationRepository.findByUser_Id(uid) } returns temporaryApplication + every { temporaryApplicationRepository.delete(temporaryApplication) } returns Unit + + val result = createApplication.execute(authDetails, request) + + result.name shouldBe request.name + verify { temporaryApplicationRepository.delete(temporaryApplication) } + } + it("이미 지원서가 존재하면 ApplicationAlreadyExistsException을 던진다") { val application = mockk() diff --git a/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImplTest.kt b/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImplTest.kt new file mode 100644 index 0000000..60dba9d --- /dev/null +++ b/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/GetTemporaryApplicationImplTest.kt @@ -0,0 +1,42 @@ +package land.leets.domain.temporaryApplication.usecase + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import land.leets.domain.auth.AuthDetails +import land.leets.domain.shared.AuthRole +import land.leets.domain.temporaryApplication.domain.TemporaryApplication +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository +import java.util.* + +class GetTemporaryApplicationImplTest : DescribeSpec({ + + val temporaryApplicationRepository = mockk() + val getTemporaryApplication = GetTemporaryApplicationImpl(temporaryApplicationRepository) + + describe("GetTemporaryApplicationImpl") { + context("임시 저장된 지원서를 조회할 때") { + val uid = UUID.randomUUID() + val authDetails = AuthDetails(uid, "test@test.com", AuthRole.ROLE_USER) + val temporaryApplication = mockk(relaxed = true) + + it("지원서가 존재하면 Response를 반환한다") { + every { temporaryApplicationRepository.findByUser_Id(uid) } returns temporaryApplication + every { temporaryApplication.name } returns "Test" + + val response = getTemporaryApplication.execute(authDetails) + + response?.name shouldBe "Test" + } + + it("지원서가 존재하지 않으면 null을 반환한다") { + every { temporaryApplicationRepository.findByUser_Id(uid) } returns null + + val response = getTemporaryApplication.execute(authDetails) + + response shouldBe null + } + } + } +}) diff --git a/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImplTest.kt b/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImplTest.kt new file mode 100644 index 0000000..e78ed9c --- /dev/null +++ b/src/test/kotlin/land/leets/domain/temporaryApplication/usecase/SaveTemporaryApplicationImplTest.kt @@ -0,0 +1,104 @@ +package land.leets.domain.temporaryApplication.usecase + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import land.leets.domain.application.type.Position +import land.leets.domain.auth.AuthDetails +import land.leets.domain.shared.AuthRole +import land.leets.domain.temporaryApplication.domain.TemporaryApplication +import land.leets.domain.temporaryApplication.domain.repository.TemporaryApplicationRepository +import land.leets.domain.temporaryApplication.presentation.dto.TemporaryApplicationRequest +import land.leets.domain.user.domain.User +import land.leets.domain.user.domain.repository.UserRepository +import land.leets.domain.user.exception.UserNotFoundException +import java.util.* + +class SaveTemporaryApplicationImplTest : DescribeSpec({ + + val temporaryApplicationRepository = mockk() + val userRepository = mockk() + val saveTemporaryApplication = SaveTemporaryApplicationImpl(temporaryApplicationRepository, userRepository) + + describe("SaveTemporaryApplicationImpl") { + context("지원서를 임시 저장할 때") { + val uid = UUID.randomUUID() + val authDetails = AuthDetails(uid, "test@test.com", AuthRole.ROLE_USER) + val request = TemporaryApplicationRequest( + name = "Test", + sid = "20202020", + phone = "010-1234-5678", + major = "CS", + grade = "4", + project = "Project", + algorithm = "Algo", + portfolio = "Port", + position = Position.DEV, + career = "Career", + interviewDay = "Monday", + interviewTime = "10:00", + motive = "Motive", + expectation = "Expectation", + capability = "Capability", + conflict = "Conflict", + passion = "Passion" + ) + val user = User( + sid = "20202020", + name = "Test", + phone = "010-1234-5678", + email = "test@test.com", + sub = "google-oauth2|123456", + id = uid + ) + + it("기존 지원서가 없으면 새로 생성한다") { + every { userRepository.findById(uid) } returns Optional.of(user) + every { temporaryApplicationRepository.findByUser_Id(uid) } returns null + every { temporaryApplicationRepository.save(any()) } returnsArgument 0 + every { userRepository.save(any()) } returns user + + val response = saveTemporaryApplication.execute(authDetails, request) + + response.name shouldBe request.name + verify { temporaryApplicationRepository.save(any()) } + } + + it("기존 지원서가 있으면 수정한다") { + val existingApplication = mockk(relaxed = true) + every { userRepository.findById(uid) } returns Optional.of(user) + every { temporaryApplicationRepository.findByUser_Id(uid) } returns existingApplication + every { temporaryApplicationRepository.save(any()) } returnsArgument 0 + every { userRepository.save(any()) } returns user + every { existingApplication.name } returns "Updated Name" + + saveTemporaryApplication.execute(authDetails, request) + + verify { existingApplication.updateContent(request) } + verify { temporaryApplicationRepository.save(existingApplication) } + } + + it("전화번호가 있으면 유저 정보를 업데이트한다") { + every { userRepository.findById(uid) } returns Optional.of(user) + every { temporaryApplicationRepository.findByUser_Id(uid) } returns null + every { temporaryApplicationRepository.save(any()) } returnsArgument 0 + every { userRepository.save(any()) } returns user + + saveTemporaryApplication.execute(authDetails, request) + + verify { userRepository.save(user) } + } + + it("유저를 찾을 수 없으면 UserNotFoundException을 던진다") { + every { userRepository.findById(uid) } returns Optional.empty() + + shouldThrow { + saveTemporaryApplication.execute(authDetails, request) + } + } + } + } +})