Skip to content

Commit

Permalink
[YS-178] feat: 실험자가 작성한 공고 게시글 삭제 API 구현 (#52)
Browse files Browse the repository at this point in the history
* feat: add DefaultResponse

* feat: add delete repository method

* feat: add DeleteExperimentPost API

* test: add DeleteExperimentPostUseCase test code

* refact: refactor delete method in repository impl

* refact: add `@Transactional` to delete method
  • Loading branch information
Ji-soo708 authored Jan 23, 2025
1 parent cd6e011 commit 64df291
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class ExperimentPostService(
private val getExperimentPostApplyMethodUseCase: GetExperimentPostApplyMethodUseCase,
private val generateExperimentPostPreSignedUrlUseCase: GenerateExperimentPostPreSignedUrlUseCase,
private val updateExpiredExperimentPostUseCase: UpdateExpiredExperimentPostUseCase,
private val getExperimentPostTotalCountByCustomFilterUseCase: GetExperimentPostTotalCountByCustomFilterUseCase
private val getExperimentPostTotalCountByCustomFilterUseCase: GetExperimentPostTotalCountByCustomFilterUseCase,
private val deleteExperimentPostUseCase: DeleteExperimentPostUseCase
) {
@Transactional
fun createNewExperimentPost(input: CreateExperimentPostUseCase.Input): CreateExperimentPostUseCase.Output {
Expand Down Expand Up @@ -89,4 +90,9 @@ class ExperimentPostService(
fun getExperimentPostTotalCount(input: GetExperimentPostTotalCountByCustomFilterUseCase.Input): Int {
return getExperimentPostTotalCountByCustomFilterUseCase.execute(input)
}

@Transactional
fun deleteExperimentPost(input: DeleteExperimentPostUseCase.Input) {
deleteExperimentPostUseCase.execute(input)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dobby.backend.application.usecase.experiment

import com.dobby.backend.application.usecase.UseCase
import com.dobby.backend.domain.exception.ExperimentPostNotFoundException
import com.dobby.backend.domain.gateway.experiment.ExperimentPostGateway

class DeleteExperimentPostUseCase(
private val experimentPostGateway: ExperimentPostGateway
): UseCase<DeleteExperimentPostUseCase.Input, Unit> {
data class Input(
val memberId: Long,
val postId: Long
)

override fun execute(input: Input) {
val post = experimentPostGateway.findExperimentPostByMemberIdAndPostId(
memberId = input.memberId,
postId = input.postId
) ?: throw ExperimentPostNotFoundException()

experimentPostGateway.delete(post)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ interface ExperimentPostGateway {
fun countExperimentPostsByMemberId(memberId: Long): Int
fun findExperimentPostByMemberIdAndPostId(memberId: Long, postId: Long): ExperimentPost?
fun countExperimentPostsByCustomFilter(customFilter: CustomFilter): Int
fun delete(post: ExperimentPost)
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,8 @@ class ExperimentPostGatewayImpl(
override fun countExperimentPostsByCustomFilter(customFilter: CustomFilter): Int {
return experimentPostCustomRepository.countExperimentPostsByCustomFilter(customFilter)
}

override fun delete(post: ExperimentPost) {
experimentPostRepository.delete(ExperimentPostEntity.fromDomain(post))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.dobby.backend.presentation.api.dto.response.experiment.CreateExperime
import com.dobby.backend.presentation.api.dto.response.experiment.ExperimentPostApplyMethodResponse
import com.dobby.backend.presentation.api.dto.response.experiment.ExperimentPostCountsResponse
import com.dobby.backend.presentation.api.dto.response.experiment.ExperimentPostDetailResponse
import com.dobby.backend.presentation.api.dto.response.member.DefaultResponse
import com.dobby.backend.presentation.api.mapper.ExperimentPostMapper
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
Expand Down Expand Up @@ -45,6 +46,20 @@ class ExperimentPostController (
return ExperimentPostMapper.toCreateExperimentPostResponse(output)
}

@PreAuthorize("hasRole('RESEARCHER')")
@DeleteMapping("/{postId}")
@Operation(
summary = "공고 삭제 API- 연구자 공고 삭제",
description = "연구자가 자신이 등록한 실험 공고를 삭제합니다."
)
fun deleteExperimentPost(
@PathVariable postId: Long
): DefaultResponse {
val input = ExperimentPostMapper.toDeleteExperimentPostUseCaseInput(postId)
experimentPostService.deleteExperimentPost(input)
return DefaultResponse.ok()
}

@PreAuthorize("hasRole('RESEARCHER')")
@PutMapping("/{postId}")
@Operation(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.dobby.backend.presentation.api.dto.response.member

import io.swagger.v3.oas.annotations.media.Schema

@Schema(description = "기본 Operation 응답")
data class DefaultResponse(
@Schema(description = "성공 유무", example = "true")
val success: Boolean
) {
companion object {
fun ok(): DefaultResponse = DefaultResponse(true)
fun fail(): DefaultResponse = DefaultResponse(false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ object ExperimentPostMapper {
}


fun toGetExperimentPostsResponse(
fun toGetExperimentPostsResponse(
output: List<GetExperimentPostsUseCase.Output>,
page: Int,
totalCount: Int,
Expand Down Expand Up @@ -332,4 +332,11 @@ object ExperimentPostMapper {
recruitStatus = customFilter.recruitStatus
)
}

fun toDeleteExperimentPostUseCaseInput(postId: Long): DeleteExperimentPostUseCase.Input {
return DeleteExperimentPostUseCase.Input(
memberId = getCurrentMemberId(),
postId = postId
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.dobby.backend.application.usecase.experiment

import com.dobby.backend.domain.exception.ExperimentPostNotFoundException
import com.dobby.backend.domain.gateway.experiment.ExperimentPostGateway
import com.dobby.backend.domain.model.experiment.ExperimentPost
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify

class DeleteExperimentPostUseCaseTest : BehaviorSpec({

val experimentPostGateway = mockk<ExperimentPostGateway>()
val deleteExperimentPostUseCase = DeleteExperimentPostUseCase(experimentPostGateway)

given("게시글을 삭제할 때") {
val memberId = 1L
val postId = 2L
val input = DeleteExperimentPostUseCase.Input(memberId, postId)

val existingPost = mockk<ExperimentPost>()
every { experimentPostGateway.findExperimentPostByMemberIdAndPostId(memberId, postId) } returns existingPost

`when`("게시글이 존재하면") {
every { experimentPostGateway.delete(existingPost) } returns Unit

then("게시글을 삭제하고 아무 값도 반환하지 않아야 한다") {
deleteExperimentPostUseCase.execute(input)
verify(exactly = 1) { experimentPostGateway.findExperimentPostByMemberIdAndPostId(memberId, postId) }
verify(exactly = 1) { experimentPostGateway.delete(existingPost) }
}
}
}

given("게시글을 삭제하려는데 게시글이 존재하지 않는 경우") {
val memberId = 1L
val postId = 999L
val input = DeleteExperimentPostUseCase.Input(memberId, postId)

every { experimentPostGateway.findExperimentPostByMemberIdAndPostId(memberId, postId) } returns null

`when`("게시글을 찾지 못하면") {
then("ExperimentPostNotFoundException 예외가 발생해야 한다") {
shouldThrow<ExperimentPostNotFoundException> {
deleteExperimentPostUseCase.execute(input)
}
verify(exactly = 1) { experimentPostGateway.findExperimentPostByMemberIdAndPostId(memberId, postId) }
}
}
}
})

0 comments on commit 64df291

Please sign in to comment.