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 구현 #136

Merged
merged 25 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f3118af
chore: 트랜잭션 추가 및 API 명세 누락 추가(#115)
whereami2048 May 20, 2024
15e6a7c
feat: 경험 id 리스트 조회 기능 구현(#115)
whereami2048 May 20, 2024
253c09b
feat: 북마크 조회 기능 구현(직무 공고, 상태 기준)(#115)
whereami2048 May 20, 2024
7f033e4
feat: 북마크한 경험 조회 APi 구현(#115)
whereami2048 May 20, 2024
e211d19
feat: JD id & 상태 별 북마크 조회 기능 구현(#115)
whereami2048 May 21, 2024
3709f5c
feat: 북마크 Boolean 상태 값 추가(#115)
whereami2048 May 21, 2024
20d0956
feat: 북마크 경험 전체 조회 API 구현(#115)
whereami2048 May 21, 2024
7671660
feat: 경험 검색 API 정의
whereami2048 May 21, 2024
e4759a6
feat: 북마크 경험 아이디로 조회 기능 정의(#115)
whereami2048 May 21, 2024
cd6bbdb
feat: 경험 검색 기능 정의(#115)
whereami2048 May 21, 2024
1437a15
feat: 태그 이름 검색 기능 구현(#115)
whereami2048 May 21, 2024
36734b1
feat: 역량 키워드 이름 검색 기능 구현(#115)
whereami2048 May 21, 2024
8e7c404
feat: 경험 제목 & 내용 검색 기능 구현체 추가 및 북마크 경험 id 배열 조회 기능 구현(#115)
whereami2048 May 21, 2024
1f1dc61
feat: 경험 검색 기능 API 구현(#115)
whereami2048 May 21, 2024
bd22466
feat: 북마크 경험 id 배열 조회 기능 구현(#115)
whereami2048 May 21, 2024
48858c8
Merge branch 'develop' into feat/flight-115
whereami2048 May 21, 2024
6b24765
feat: 북마크 상태 Boolean 값 제거(#115)
whereami2048 May 21, 2024
036e217
Merge branch 'feat/flight-115' of github.com:KUSITMS-29th-TEAM-B/Back…
whereami2048 May 21, 2024
96aafc9
chore: 깃 충돌 문제 해결(#115)
whereami2048 May 21, 2024
544058f
fix: 엔티티 오타 수정(#115)
whereami2048 May 21, 2024
f63d98e
fix: @Modifying 제거(#115)
whereami2048 May 21, 2024
7581227
fix: 하위 태그 관련 조회 연도 기준 활동 시작일로 변경(#115)
whereami2048 May 21, 2024
1ce8466
feat: 태그로 경험 조회 기능 구현(#115)
whereami2048 May 21, 2024
9f7c022
feat: 태그 삭제 시 관련 경험 삭제 로직 추가(#115)
whereami2048 May 21, 2024
8a4c29d
fix: @Modifying 누락 추가(#115)
whereami2048 May 21, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ class BookmarkService(
bookmarkModifier.modifyBookmarkStatus(it)
} ?: bookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bamyanggang.apimodule.domain.experience.application.dto

import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import java.time.LocalDateTime
import java.util.*

Expand All @@ -19,6 +20,23 @@ class GetExperience {
val endedAt: LocalDateTime,
)

data class BookmarkResponse(
val experience: List<BookmarkDetailExperience>
)

data class BookmarkDetailExperience(
val id: UUID,
val title: String,
val parentTag: DetailTag,
val childTag: DetailTag,
val strongPoints: List<DetailStrongPoint>,
val contents: List<DetailExperienceContent>,
val startedAt: LocalDateTime,
val endedAt: LocalDateTime,
val bookmarked: BookmarkStatus,
)


data class DetailExperienceContent(
val question: String,
val answer: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,32 @@ package com.bamyanggang.apimodule.domain.experience.application.service
import com.bamyanggang.apimodule.common.getAuthenticationPrincipal
import com.bamyanggang.apimodule.domain.experience.application.dto.ExperienceYear
import com.bamyanggang.apimodule.domain.experience.application.dto.GetExperience
import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkReader
import com.bamyanggang.domainmodule.domain.experience.aggregate.Experience
import com.bamyanggang.domainmodule.domain.experience.aggregate.ExperienceContent
import com.bamyanggang.domainmodule.domain.experience.aggregate.ExperienceStrongPoint
import com.bamyanggang.domainmodule.domain.experience.service.ExperienceReader
import com.bamyanggang.domainmodule.domain.strongpoint.service.StrongPointReader
import com.bamyanggang.domainmodule.domain.tag.service.TagReader
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class ExperienceGetService(
private val experienceReader: ExperienceReader,
private val strongPointReader: StrongPointReader,
private val tagReader: TagReader,
private val bookMarkReader: BookmarkReader,
) {
@Transactional(readOnly = true)
fun getExperienceDetailById(experienceId: UUID) : GetExperience.DetailExperience {
val oneExperience = experienceReader.readExperience(experienceId)
return createExperienceDetailResponse(oneExperience)
}

@Transactional(readOnly = true)
fun getAllYearsByExistExperience(): ExperienceYear.Response {
val currentUserId = getAuthenticationPrincipal()

Expand Down Expand Up @@ -49,6 +57,7 @@ class ExperienceGetService(
)
}

@Transactional(readOnly = true)
fun getExperienceByYearAndParentTag(year: Int, parentTagId: UUID): GetExperience.Response {
val experiences = experienceReader.readByYearAndParentTagId(year, parentTagId).map {
createExperienceDetailResponse(it)
Expand All @@ -57,6 +66,7 @@ class ExperienceGetService(
return GetExperience.Response(experiences)
}

@Transactional(readOnly = true)
fun getExperienceByYearAndChildTag(year: Int, childTagId: UUID): GetExperience.Response {
val experiences = experienceReader.readByChildTagIdAndYear(year, childTagId).map {
createExperienceDetailResponse(it)
Expand All @@ -65,11 +75,49 @@ class ExperienceGetService(
return GetExperience.Response(experiences)
}

@Transactional(readOnly = true)
fun getAllBookmarkExperiences(jobDescriptionId: UUID): GetExperience.BookmarkResponse {
val experienceIds = bookMarkReader.readByStatusAndJobDescriptionId(jobDescriptionId, BookmarkStatus.ON).map { it.experienceId }

val userExperiences = experienceReader.readAllByUserId(getAuthenticationPrincipal())

val bookmarkExperienceDetails = userExperiences.map {
when {
it.id in experienceIds -> createBookmarkExperienceDetailResponse(it, BookmarkStatus.ON)
else -> createBookmarkExperienceDetailResponse(it, BookmarkStatus.OFF)
}
}

return GetExperience.BookmarkResponse(bookmarkExperienceDetails)
}

@Transactional(readOnly = true)
fun getBookmarkExperienceBySearch(jobDescriptionId: UUID, search: String): GetExperience.BookmarkResponse {
val currentUserId = getAuthenticationPrincipal()

val experiencesIds = experienceReader.readByTitleContains(search) +
experienceReader.readByContentsContains(currentUserId, search) +
tagReader.readIdsByNameContains(search) +
strongPointReader.readIdsByNameContains(search)

val searchExperiences = experienceReader.readByIds(experiencesIds)
val bookmarkExperienceIds = bookMarkReader.readByExperienceIds(experiencesIds).map { it.experienceId }

val bookmarkExperienceDetails = searchExperiences.map {
when {
it.id in bookmarkExperienceIds -> createBookmarkExperienceDetailResponse(it, BookmarkStatus.ON)
else -> createBookmarkExperienceDetailResponse(it, BookmarkStatus.OFF)
}
}

return GetExperience.BookmarkResponse(bookmarkExperienceDetails)
}

private fun createExperienceDetailResponse(experience: Experience): GetExperience.DetailExperience {
val detailExperienceContents = convertDetailExperienceContent(experience)
val strongPointDetails = convertStrongPoints(experience)
val detailParentTag = convertParentTag(experience)
val detailChildTag = convertChildTag(experience)
val detailExperienceContents = convertExperienceContent(experience.contents)
val strongPointDetails = convertStrongPoints(experience.strongPoints)
val detailParentTag = convertParentTag(experience.parentTagId)
val detailChildTag = convertChildTag(experience.childTagId)

return GetExperience.DetailExperience(
id = experience.id,
Expand All @@ -83,31 +131,50 @@ class ExperienceGetService(
)
}

private fun convertChildTag(oneExperience: Experience) =
tagReader.readById(oneExperience.childTagId).let {
private fun createBookmarkExperienceDetailResponse(experience: Experience, bookmarkStatus: BookmarkStatus): GetExperience.BookmarkDetailExperience {
val detailExperienceContents = convertExperienceContent(experience.contents)
val strongPointDetails = convertStrongPoints(experience.strongPoints)
val detailParentTag = convertParentTag(experience.parentTagId)
val detailChildTag = convertChildTag(experience.childTagId)

return GetExperience.BookmarkDetailExperience(
id = experience.id,
title = experience.title,
parentTag = detailParentTag,
childTag = detailChildTag,
strongPoints = strongPointDetails,
contents = detailExperienceContents,
startedAt = experience.startedAt,
endedAt = experience.endedAt,
bookmarked = bookmarkStatus
)
}

private fun convertChildTag(childTagId: UUID) =
tagReader.readById(childTagId).let {
GetExperience.DetailTag(
it.id,
it.name
)
}

private fun convertParentTag(oneExperience: Experience) =
tagReader.readById(oneExperience.parentTagId).let {
private fun convertParentTag(parentTagId: UUID) =
tagReader.readById(parentTagId).let {
GetExperience.DetailTag(
it.id,
it.name
)
}

private fun convertDetailExperienceContent(experience: Experience) =
experience.contents.map { GetExperience.DetailExperienceContent(
private fun convertExperienceContent(contents: List<ExperienceContent>) =
contents.map { GetExperience.DetailExperienceContent(
it.question,
it.answer
)
}

private fun convertStrongPoints(experience: Experience) =
experience.strongPoints.map { it.strongPointId }.let {
private fun convertStrongPoints(strongPoints: List<ExperienceStrongPoint>) =
strongPoints.map { it.strongPointId }.let {
strongPointReader.readByIds(it).map { strongPoint ->
GetExperience.DetailStrongPoint(
strongPoint.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ object ExperienceApi {
const val BASE_URL = "/api/experiences"
const val EXPERIENCE_PATH_VARIABLE_URL = "$BASE_URL/{experienceId}"
const val ALL_YEARS = "$BASE_URL/all-years"
const val BOOKMARK_EXPERIENCE_URL = "$BASE_URL/bookmark/{jobDescriptionId}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ class ExperienceController(
private val experienceEditService: ExperienceEditService,
private val experienceGetService: ExperienceGetService
) {
@GetMapping(ExperienceApi.BOOKMARK_EXPERIENCE_URL)
fun getBookMarkExperiences(
@PathVariable("jobDescriptionId") jobDescriptionId: UUID,
@RequestParam("search", required = false) search: String?,
) : GetExperience.BookmarkResponse =
when (search) {
null -> experienceGetService.getAllBookmarkExperiences(jobDescriptionId)
else -> experienceGetService.getBookmarkExperienceBySearch(jobDescriptionId, search.trim())
}

@GetMapping(ExperienceApi.BASE_URL)
fun getExperienceByFilter(@RequestParam("year") year: Int,
@RequestParam("parent-tag", required = false) parentTagId: UUID?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.bamyanggang.apimodule.domain.strongpoint.application.service

import ch.qos.logback.core.rolling.helper.ArchiveRemover
import com.bamyanggang.domainmodule.domain.strongpoint.service.StrongPointRemover
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class StrongPointDeleteService(
private val strongPointRemover: StrongPointRemover
) {
@Transactional
fun deleteStrongPoint(strongPointId: UUID) {
strongPointRemover.removeStrongPoint(strongPointId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import com.bamyanggang.apimodule.common.getAuthenticationPrincipal
import com.bamyanggang.apimodule.domain.strongpoint.application.dto.GetStrongPoint
import com.bamyanggang.domainmodule.domain.strongpoint.service.StrongPointReader
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class StrongPointGetService(
private val strongPointReader: StrongPointReader,
) {
@Transactional(readOnly = true)
fun getAllStrongPoints(): GetStrongPoint.Response {
return getAuthenticationPrincipal().let {
val detailStrongPoints = strongPointReader.readAllByUserId(it).map { strongPoint ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
package com.bamyanggang.apimodule.domain.tag.application.service

import com.bamyanggang.apimodule.common.getAuthenticationPrincipal
import com.bamyanggang.domainmodule.domain.experience.service.ExperienceReader
import com.bamyanggang.domainmodule.domain.experience.service.ExperienceRemover
import com.bamyanggang.domainmodule.domain.tag.service.TagReader
import com.bamyanggang.domainmodule.domain.tag.service.TagRemover
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class TagDeleteService(
private val tagRemover: TagRemover
private val tagRemover: TagRemover,
private val tagReader: TagReader,
private val experienceReader: ExperienceReader,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거는 추후에 이벤트로 처리해도 좋을 듯 합니당

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서로 다른 애그리거트니까!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 좋아요오~~

private val experienceRemover: ExperienceRemover
) {
@Transactional
fun deleteTag(tagId: UUID) {
val deleteTag = tagReader.readById(tagId)

if (deleteTag.parentTagId == null) {
experienceReader.readByUserIdAndParentTagId(getAuthenticationPrincipal(), deleteTag.id)
.forEach { experienceRemover.remove(it.id) }
}else {
experienceReader.readByChildTag(tagId).forEach {
experienceRemover.remove(it.id)
}
}

tagRemover.removeTag(tagId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ class TagController(
}

@DeleteMapping(TagApi.TAG_PATH_VARIABLE_URL)
fun deleteTag( @PathVariable("tagId", required = false) tagId: UUID) {
fun deleteTag( @PathVariable("tagId") tagId: UUID) {

tagDeleteService.deleteTag(tagId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,91 @@ class ExperienceControllerTest : BaseRestDocsTest() {
)
}

// @Test
// @DisplayName("북마크 경험을 전체 조회한다.")
// fun getAllBookmarkExperienceYearTest() {
// val content1 = GetExperience.DetailExperienceContent("질문1", "답변1")
// val content2 = GetExperience.DetailExperienceContent("질문2", "답변2")
// val strongPoint1 = GetExperience.DetailStrongPoint(UUID.randomUUID(), "역량 키워드 이름 1")
// val strongPoint2 = GetExperience.DetailStrongPoint(UUID.randomUUID(), "역량 키워드 이름 2")
// val parentTag = GetExperience.DetailTag(UUID.randomUUID(), "상위 태그 이름")
// val childTag = GetExperience.DetailTag(UUID.randomUUID(), "하위 태그 이름")
// val startedAt = LocalDateTime.now()
// val endedAt = LocalDateTime.now().plusDays(1)
//
// val contentResponse = arrayListOf(content1, content2)
// val strongPointResponse = arrayListOf(strongPoint1, strongPoint2)
//
// val experienceResponses =
// GetExperience.BookmarkResponse(
// arrayListOf(
// GetExperience.BookmarkDetailExperience(
// id = UUID.randomUUID(),
// title = "경험 제목1 ",
// contents = contentResponse,
// strongPoints = strongPointResponse,
// parentTag = parentTag,
// childTag = childTag,
// startedAt = startedAt,
// endedAt = endedAt,
// bookmarked = BookmarkStatus.ON
// ),
// GetExperience.BookmarkDetailExperience(
// id = UUID.randomUUID(),
// title = "경험 제목 2",
// contents = contentResponse,
// strongPoints = strongPointResponse,
// parentTag = parentTag,
// childTag = childTag,
// startedAt = startedAt.minusYears(1),
// endedAt = endedAt,
// bookmarked = BookmarkStatus.OFF
// )
// )
// )
//
// val year = 2024
// given(experienceGetService.getAllBookmarkExperiences(UUID.randomUUID())).willReturn(experienceResponses)
//
// //given
// val request = RestDocumentationRequestBuilders.get(ExperienceApi.BOOKMARK_EXPERIENCE_URL, UUID.randomUUID())
// .header("Authorization", "Bearer Access Token")
// .contentType(MediaType.APPLICATION_JSON_VALUE)
// .queryParam("year", year.toString())
// .queryParam("parent-tag", parentTag.id.toString())
//
// //when
// val result = mockMvc.perform(request)
//
// //then
// result.andExpect(status().isOk).andDo(
// resultHandler.document(
// requestHeaders(
// headerWithName("Authorization").description("엑세스 토큰")
// ),
// responseFields(
// fieldWithPath("experiences[].id").description("경험 id"),
// fieldWithPath("experiences[].title").description("경험 제목"),
// fieldWithPath("experiences[].contents").description("경험 내용"),
// fieldWithPath("experiences[].contents[].question").description("경험 내용 질문"),
// fieldWithPath("experiences[].contents[].answer").description("경험 내용 답변"),
// fieldWithPath("experiences[].strongPoints").description("관련된 역량 키워드"),
// fieldWithPath("experiences[].strongPoints[].id").description("역량 키워드 id"),
// fieldWithPath("experiences[].strongPoints[].name").description("역량 키워드 이름"),
// fieldWithPath("experiences[].parentTag").description("속한 상위 태그"),
// fieldWithPath("experiences[].parentTag.id").description("상위 태그 id"),
// fieldWithPath("experiences[].parentTag.name").description("상위 태그 이름"),
// fieldWithPath("experiences[].childTag").description("속한 하위 태그"),
// fieldWithPath("experiences[].childTag.id").description("하위 태그 id"),
// fieldWithPath("experiences[].childTag.name").description("하위 태그 이름"),
// fieldWithPath("experiences[].startedAt").description("경험 시작 날짜"),
// fieldWithPath("experiences[].endedAt").description("경험 종료 날짜"),
// fieldWithPath("experiences[].bookmarked").description("북마크 여부"),
// ),
// )
// )
// }

@Test
@DisplayName("경험 목록을 하위 태그 id를 기준으로 조회한다.")
fun getExperienceYearAndChildTagTest() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ class TagControllerTest : BaseRestDocsTest() {
fieldWithPath("tags[].name").description("태그 이름"),
)
)
)
)
}

@Test
Expand Down
Loading
Loading