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

feat: 경험 삭제 API 구현(#40) #73

Merged
merged 10 commits into from
May 18, 2024
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 .github/workflows/CD-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,4 @@ jobs:
docker compose stop ${{secrets.DOCKER_REPOSITORY}}
docker compose rm -f ${{secrets.DOCKER_REPOSITORY}}
docker compose -f docker-compose-dev.yml up -d
docker image prune -f
docker image prune -f
5 changes: 5 additions & 0 deletions Api-Module/src/docs/asciidoc/Experience.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ operation::ExperienceControllerTest/createOverTitleLengthTest/[snippets='http-re
=== 역량 키워드 제한(5개) 초과 예외

operation::ExperienceControllerTest/createOverStrongPointCountTest/[snippets='http-request,request-headers,request-body,http-response,response-body,response-fields']

[[DeleteExperienceTest]]
=== 경험 삭제 API

operation::ExperienceControllerTest/deleteExperienceTest/[snippets='http-request,path-parameters,request-headers,request-body,http-response,response-body']
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,23 @@ import org.springframework.transaction.annotation.Transactional
@Service
class ExperienceCreateService(
val experienceAppender: ExperienceAppender,
val experienceContentAppender: ExperienceContentAppender
val experienceContentAppender: ExperienceContentAppender,
) {
@Transactional
fun createExperience(request: CreateExperience.Request):CreateExperience.Response {
val currentUserId = getAuthenticationPrincipal()

return request.contents.map {
experienceContentAppender.appendExperienceContent(it.question, it.answer).id
}.let {
experienceAppender.appendExperience(
title = request.title,
userId = currentUserId,
parentTagId = request.parentTagId,
childTagId = request.childTagId,
strongPointIds = request.strongPointIds,
contentIds = it,
startedAt = request.startedAt,
endedAt = request.endedAt
)
}.let {
CreateExperience.Response(it.id)
}
val newExperience = experienceAppender.appendExperience(
title = request.title,
userId = currentUserId,
startedAt = request.startedAt,
endedAt = request.endedAt
)

request.contents.forEach {
experienceContentAppender.appendExperienceContent(it.question, it.answer, newExperience.id)
}

return CreateExperience.Response(newExperience.id)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.bamyanggang.apimodule.domain.experience.application.service

import com.bamyanggang.domainmodule.domain.experience.service.ExperienceRemover
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class ExperienceDeleteService(
val experienceRemover: ExperienceRemover
) {
@Transactional
fun deleteExperienceById(experienceId: UUID) {
experienceRemover.remove(experienceId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ package com.bamyanggang.apimodule.domain.experience.presentation

object ExperienceApi {
const val BASE_URL = "/api/experiences"
const val EXPERIENCE_PATH_VARIABLE_URL = "$BASE_URL/{experienceId}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ package com.bamyanggang.apimodule.domain.experience.presentation

import com.bamyanggang.apimodule.domain.experience.application.dto.CreateExperience
import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceCreateService
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceDeleteService
import org.springframework.web.bind.annotation.*
import java.util.*

@RestController
class ExperienceController(
private val experienceCreateService: ExperienceCreateService
private val experienceCreateService: ExperienceCreateService,
private val experienceDeleteService: ExperienceDeleteService
) {
@PostMapping(ExperienceApi.BASE_URL)
fun createExperience(@RequestBody request: CreateExperience.Request): CreateExperience.Response {
return experienceCreateService.createExperience(request)
}

@DeleteMapping(ExperienceApi.EXPERIENCE_PATH_VARIABLE_URL)
fun deleteExperience(@PathVariable("experienceId") experienceId: UUID) {
experienceDeleteService.deleteExperienceById(experienceId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//package com.bamyanggang.apimodule.domain.experience.application
//
//import com.bamyanggang.apimodule.domain.experience.application.dto.CreateExperience
//import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceCreateService
//import com.bamyanggang.commonmodule.fixture.generateFixture
//import com.bamyanggang.domainmodule.domain.experience.service.ExperienceAppender
//import com.bamyanggang.domainmodule.domain.experience.service.ExperienceContentAppender
//import io.kotest.core.spec.style.BehaviorSpec
//import io.mockk.every
//import io.mockk.mockk
//import io.mockk.verify
//import java.util.*
//
//class ExperienceCreateServiceTest : BehaviorSpec({
//
// val experienceAppender: ExperienceAppender = mockk()
// val experienceContentAppender: ExperienceContentAppender = mockk()
// val createExperienceService = ExperienceCreateService(experienceAppender, experienceContentAppender)
//
// Given("등록할 경험 Request과 응답이 주어지면") {
// val request : CreateExperience.Request = generateFixture()
// val response : CreateExperience.Response = generateFixture()
//
// When("ExperienceCreateService.createExperience가 호출 되었을 때" ) {
// every { createExperienceService.createExperience(request) } returns response
//
// Then("experienceAppender.appendExperience가 호출된다.") {
// verify {
// experienceAppender.appendExperience(
// request.title,
// generateFixture<UUID>(),
// request.startedAt,
// request.endedAt
// )
// }
// }
//
// Then("experienceContentAppender.appendExperienceContent가 호출된다.") {
// verify {
// experienceContentAppender.appendExperienceContent(
// generateFixture(),
// generateFixture(),
// generateFixture(),
// )
// }
// }
// }
// }
//})
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.bamyanggang.apimodule.domain.experience.application

import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceDeleteService
import com.bamyanggang.domainmodule.domain.experience.service.ExperienceRemover
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import java.util.*

class ExperienceDeleteServiceTest : BehaviorSpec({
val experienceRemover = mockk<ExperienceRemover>()
val experienceDeleteService = ExperienceDeleteService(experienceRemover)

Given("ExperienceDeleteService 테스트") {
When("삭제할 UUID가 주어지면") {
val deleteId = UUID.randomUUID()
every { experienceDeleteService.deleteExperienceById(deleteId) } returns Unit

experienceDeleteService.deleteExperienceById(deleteId)

Then("ExperienceRemover.remove가 호출된다.") {
verify { experienceRemover.remove(deleteId) }
}
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.bamyanggang.apimodule.domain.experience.presentation
import com.bamyanggang.apimodule.BaseRestDocsTest
import com.bamyanggang.apimodule.domain.experience.application.dto.CreateExperience
import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceCreateService
import com.bamyanggang.apimodule.domain.experience.application.service.ExperienceDeleteService
import com.bamyanggang.commonmodule.exception.ExceptionHandler
import com.bamyanggang.commonmodule.fixture.generateFixture
import org.junit.jupiter.api.DisplayName
Expand All @@ -17,6 +18,8 @@ import org.springframework.restdocs.headers.HeaderDocumentation.headerWithName
import org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders
import org.springframework.restdocs.payload.PayloadDocumentation.*
import org.springframework.restdocs.request.RequestDocumentation.parameterWithName
import org.springframework.restdocs.request.RequestDocumentation.pathParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.time.LocalDateTime
import java.util.*
Expand All @@ -28,6 +31,9 @@ class ExperienceControllerTest : BaseRestDocsTest() {
@MockBean
private lateinit var experienceCreateService: ExperienceCreateService

@MockBean
private lateinit var experienceDeleteService: ExperienceDeleteService

@Test
@DisplayName("경험을 등록한다.")
fun createExperienceTest() {
Expand Down Expand Up @@ -190,5 +196,29 @@ class ExperienceControllerTest : BaseRestDocsTest() {
)
)
}

@Test
@DisplayName("경험을 삭제한다.")
fun deleteExperienceTest() {
//given
val request = RestDocumentationRequestBuilders.delete(ExperienceApi.EXPERIENCE_PATH_VARIABLE_URL, generateFixture<UUID>())
.header("Authorization", "Bearer Access Token")
.contentType(MediaType.APPLICATION_JSON_VALUE)

//when
val result = mockMvc.perform(request)

//then
result.andExpect(status().isOk).andDo(
resultHandler.document(
requestHeaders(
headerWithName("Authorization").description("엑세스 토큰")
),
pathParameters(
parameterWithName("experienceId").description("경험 id")
)
)
)
}
}

Binary file added Domain-Module/.jqwik-database
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,25 @@ import java.util.*
data class Experience(
override val id: UUID = UuidCreator.create(),
val userId : UUID,
val parentTagId : UUID,
val childTagId : UUID,
val strongPointIds : List<UUID> = emptyList(),
val title : String,
val contentIds : List<UUID> = emptyList(),
val startedAt : LocalDateTime,
val endedAt : LocalDateTime,
val createdAt : LocalDateTime,
val updatedAt : LocalDateTime,
) : AggregateRoot {
init {
require(title.length < 50) { "제목의 글자 수는 50자 제한입니다." }
require(strongPointIds.size <= 5) { "역량 키워드는 최대 5개까지 붙일 수 있습니다."}
}
companion object {
fun create(
title: String,
userId: UUID,
parentTagId: UUID,
childTagId: UUID,
strongPointIds: List<UUID>,
contentIds: List<UUID> = emptyList(),
startedAt: LocalDateTime,
endedAt: LocalDateTime,
): Experience {
return Experience(
userId = userId,
parentTagId = parentTagId,
childTagId = childTagId,
strongPointIds = strongPointIds,
title = title,
contentIds = contentIds,
startedAt = startedAt,
endedAt = endedAt,
createdAt = LocalDateTime.now(),
Expand All @@ -50,11 +37,7 @@ data class Experience(
fun toDomain(
id: UUID,
userId: UUID,
parentTagId: UUID,
childTagId: UUID,
strongPointIds: List<UUID>,
title: String,
contentIds: List<UUID> = emptyList(),
startedAt: LocalDateTime,
endedAt: LocalDateTime,
createdAt: LocalDateTime,
Expand All @@ -63,11 +46,7 @@ data class Experience(
return Experience(
id = id,
userId = userId,
parentTagId = parentTagId,
childTagId = childTagId,
strongPointIds = strongPointIds,
title = title,
contentIds = contentIds,
startedAt = startedAt,
endedAt = endedAt,
createdAt = createdAt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ data class ExperienceContent(
override val id: UUID = UuidCreator.create(),
val question: String,
val answer: String,
val experienceId: UUID
) : DomainEntity {

companion object {
fun create(question: String, answer: String): ExperienceContent {
return ExperienceContent(question = question, answer = answer)
fun create(question: String, answer: String, experienceId: UUID): ExperienceContent {
return ExperienceContent(question = question, answer = answer, experienceId = experienceId)
}

fun toDomain(id: UUID, question: String, answer: String): ExperienceContent {
return ExperienceContent(id, question, answer)
fun toDomain(id: UUID, question: String, answer: String, experienceId: UUID): ExperienceContent {
return ExperienceContent(id, question, answer, experienceId)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ import java.util.*

interface ExperienceContentRepository {
fun save(experienceContent: ExperienceContent)
fun findByExperienceId(experienceId: UUID) : List<ExperienceContent>
fun deleteAllByIds(experienceContents: List<ExperienceContent>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ import java.util.*

interface ExperienceRepository {
fun save(experience: Experience)
fun deleteByExperienceId(experienceId: UUID)
fun findByExperienceId(id: UUID): Experience
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,12 @@ class ExperienceAppender(
) {
fun appendExperience(title: String,
userId: UUID,
parentTagId: UUID,
childTagId: UUID,
strongPointIds: List<UUID>,
contentIds: List<UUID>,
startedAt: LocalDateTime,
endedAt: LocalDateTime,
): Experience {
return Experience.create(
title = title,
userId = userId,
parentTagId = parentTagId,
childTagId = childTagId,
strongPointIds = strongPointIds,
contentIds = contentIds,
startedAt = startedAt,
endedAt = endedAt
).also {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package com.bamyanggang.domainmodule.domain.experience.service
import com.bamyanggang.domainmodule.domain.experience.aggregate.ExperienceContent
import com.bamyanggang.domainmodule.domain.experience.repository.ExperienceContentRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class ExperienceContentAppender(
private val experienceContentRepository: ExperienceContentRepository
) {
fun appendExperienceContent(question: String, answer: String): ExperienceContent {
return ExperienceContent.create(question, answer).also {
fun appendExperienceContent(question: String, answer: String, experienceId: UUID): ExperienceContent {
return ExperienceContent.create(question, answer, experienceId).also {
experienceContentRepository.save(it)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.bamyanggang.domainmodule.domain.experience.service

import com.bamyanggang.domainmodule.domain.experience.aggregate.ExperienceContent
import com.bamyanggang.domainmodule.domain.experience.repository.ExperienceContentRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class ExperienceContentReader(
private val experienceRepository: ExperienceContentRepository
) {
fun readByExperienceId(experienceId: UUID): List<ExperienceContent> {
return experienceRepository.findByExperienceId(experienceId)
}
}
Loading
Loading