Skip to content

Commit

Permalink
Merge pull request #109 from KUSITMS-29th-TEAM-B/feat/flight-107
Browse files Browse the repository at this point in the history
feat: 북마크 API 구현
  • Loading branch information
isprogrammingfun authored May 20, 2024
2 parents a85f71c + 02dea5f commit 1bb169b
Show file tree
Hide file tree
Showing 21 changed files with 503 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Api-Module/src/docs/asciidoc/BookMark.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[[Bookmark-API]]
== Bookmark-API

[[CREATE-BOOKMARK]]
=== 북마크 생성 API

operation::BookmarkControllerTest/createBookmark/[snippets='http-request,path-parameters,request-headers,http-response']
1 change: 1 addition & 0 deletions Api-Module/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ include::StrongPoint.adoc[]
include::Tag.adoc[]
include::JobDescription.adoc[]
include::Experience.adoc[]
include::BookMark.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.bamyanggang.apimodule.domain.bookmark.application

import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkAppender
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkModifier
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkReader
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class BookmarkService(
private val bookmarkReader: BookmarkReader,
private val bookmarkModifier: BookmarkModifier,
private val bookmarkAppender: BookmarkAppender
) {

@Transactional
fun bookmark(jobDescriptionId: UUID, experienceId: UUID) {
bookmarkReader.readBookmark(jobDescriptionId, experienceId)?.let {
bookmarkModifier.modifyBookmarkStatus(it)
} ?: bookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

object BookmarkApi {
const val BASE_URL = "/api/bookmark"
const val BOOKMARK = "$BASE_URL/{jobDescriptionId}/{experienceId}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

import com.bamyanggang.apimodule.domain.bookmark.application.BookmarkService
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import java.util.UUID

@RestController
class BookmarkController(
private val bookmarkService: BookmarkService
) {

@PatchMapping(BookmarkApi.BOOKMARK)
fun bookmark(
@PathVariable("jobDescriptionId") jobDescriptionId: UUID,
@PathVariable("experienceId") experienceId: UUID
) {
bookmarkService.bookmark(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.bamyanggang.apimodule.domain.bookmark.application

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkAppender
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkModifier
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkReader
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import java.util.*

class BookmarkServiceTest: BehaviorSpec({
val mockBookmarkReader = mockk<BookmarkReader>(relaxed = true)
val mockBookmarkModifier = mockk<BookmarkModifier>(relaxed = true)
val mockBookmarkAppender = mockk<BookmarkAppender>(relaxed = true)
val service = BookmarkService(mockBookmarkReader, mockBookmarkModifier, mockBookmarkAppender)

given("BookmarkService.bookmark") {
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

`when`("readBookmark가 null을 반환하면") {
every { mockBookmarkReader.readBookmark(jobDescriptionId, experienceId) } returns null
service.bookmark(jobDescriptionId, experienceId)
then("appendBookmark가 호출된다.") {
verify {
mockBookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
}
}
}

`when`("readBookmark가 null이 아닌 값을 반환하면") {
val bookmark = mockk<Bookmark>()
every { mockBookmarkReader.readBookmark(jobDescriptionId, experienceId) } returns bookmark
service.bookmark(jobDescriptionId, experienceId)
then("modifyBookmarkStatus가 호출된다.") {
verify {
mockBookmarkModifier.modifyBookmarkStatus(bookmark)
}
}
}
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

import com.bamyanggang.apimodule.BaseRestDocsTest
import com.bamyanggang.apimodule.domain.bookmark.application.BookmarkService
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.restdocs.headers.HeaderDocumentation.headerWithName
import org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders
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.util.*

@WebMvcTest(BookmarkController::class)
class BookmarkControllerTest: BaseRestDocsTest() {

@MockBean
private lateinit var bookmarkService: BookmarkService

@Test
@DisplayName("북마크 추가")
fun createBookmark() {
// given
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

val request = RestDocumentationRequestBuilders.patch(BookmarkApi.BOOKMARK, jobDescriptionId, experienceId)
.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("jobDescriptionId").description("jd 공고 ID"),
parameterWithName("experienceId").description("경험 ID")
)
)
)
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.bamyanggang.domainmodule.domain.bookmark.aggregate

import com.bamyanggang.domainmodule.common.entity.AggregateRoot
import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import java.util.UUID

data class Bookmark(
override val id: UUID = UUID.randomUUID(),
val jobDescriptionId: UUID,
val experienceId:UUID,
val bookmarkStatus: BookmarkStatus
): AggregateRoot {

fun changeBookmarkStatus(): Bookmark {
return when (bookmarkStatus) {
BookmarkStatus.ON -> copy(bookmarkStatus = BookmarkStatus.OFF)
BookmarkStatus.OFF -> copy(bookmarkStatus = BookmarkStatus.ON)
}
}

companion object {
fun create(
jobDescriptionId: UUID,
experienceId: UUID
): Bookmark {
return Bookmark(
jobDescriptionId = jobDescriptionId,
experienceId = experienceId,
bookmarkStatus = BookmarkStatus.ON
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.bamyanggang.domainmodule.domain.bookmark.enums

enum class BookmarkStatus {
ON,
OFF
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.bamyanggang.domainmodule.domain.bookmark.repository

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import java.util.*

interface BookmarkRepository {

fun findByIds(jobDescriptionId : UUID, experienceId : UUID) : Bookmark?

fun save(bookmark: Bookmark)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class BookmarkAppender(
private val bookmarkRepository: BookmarkRepository
) {
fun appendBookmark(jobDescriptionId: UUID, experienceId: UUID) {
Bookmark.create(jobDescriptionId, experienceId).also { bookmarkRepository.save(it) }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service

@Service
class BookmarkModifier(
private val bookmarkRepository: BookmarkRepository
) {
fun modifyBookmarkStatus(bookmark: Bookmark) {
bookmark.changeBookmarkStatus().also { bookmarkRepository.save(it) }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class BookmarkReader(
private val bookmarkRepository: BookmarkRepository
) {

fun readBookmark(jobDescriptionId: UUID, experienceId: UUID) : Bookmark? {
return bookmarkRepository.findByIds(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.bamyanggang.domainmodule.domain.bookmark.aggregate

import com.bamyanggang.commonmodule.fixture.generateFixture
import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import java.util.*

class BookmarkTest : FunSpec({
test("북마크 생성") {
// arrange
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

// act
val bookmark: Bookmark = generateFixture {
it.set("jobDescriptionId", jobDescriptionId)
it.set("experienceId", experienceId)
}

// assert
bookmark.jobDescriptionId shouldBe jobDescriptionId
bookmark.experienceId shouldBe experienceId
}

test("북마크 상태 변경") {
// arrange
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()
val bookmark: Bookmark = generateFixture {
it.set("jobDescriptionId", jobDescriptionId)
it.set("experienceId", experienceId)
it.set("bookmarkStatus", BookmarkStatus.ON)
}

// act
val changedBookmark = bookmark.changeBookmarkStatus()

// assert
changedBookmark.bookmarkStatus shouldBe BookmarkStatus.OFF
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.mockk
import io.mockk.verify
import java.util.*

class BookmarkAppenderTest: BehaviorSpec({
val mockBookmarkRepository = mockk<BookmarkRepository>(relaxed = true)
val bookmarkAppender = BookmarkAppender(mockBookmarkRepository)

given("BookmarkAppender의 appendBookmark 메소드를 테스트한다") {
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()
`when`("북마크를 추가하면") {
bookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
then("북마크가 저장된다") {
verify(exactly = 1) {
mockBookmarkRepository.save(any())
}
}
}
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify

class BookmarkModifierTest: BehaviorSpec({
val mockBookmarkRepository = mockk<BookmarkRepository>(relaxed = true)
val bookmarkModifier = BookmarkModifier(mockBookmarkRepository)

given("BookmarkModifier의 modifyBookmarkStatus 메소드를 테스트한다") {
val bookmark = mockk<Bookmark>()
every { bookmark.changeBookmarkStatus() } returns bookmark

`when`("북마크 상태를 변경하면") {
bookmarkModifier.modifyBookmarkStatus(bookmark)
then("북마크가 저장된다") {
verify(exactly = 1) {
mockBookmarkRepository.save(bookmark)
}
}
}
}

})
Loading

0 comments on commit 1bb169b

Please sign in to comment.