Skip to content

Commit

Permalink
[feat] : 내 Gallery 등록 기능 추가 (#379)
Browse files Browse the repository at this point in the history
Co-authored-by: dojin <[email protected]>
  • Loading branch information
devxb and dojinyou authored Feb 28, 2024
1 parent 6c8a6ee commit ee4accf
Show file tree
Hide file tree
Showing 22 changed files with 616 additions and 17 deletions.
1 change: 1 addition & 0 deletions api/acceptance-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
testImplementation project(':user:user-application')
testImplementation project(':user:user-jpa-adapter')
testImplementation project(':user:user-web-adaptor')
testImplementation project(':gallery')

testImplementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/me/nalab/api/NalabApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
@ComponentScan("me.nalab")
@EnableJpaRepositories(basePackages = {"me.nalab"})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE gallery ADD `version` BIGINT;

CREATE UNIQUE INDEX galley_idx_target_id ON gallery(target_id)
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class JwtDecryptInterceptorConfigurer implements WebMvcConfigurer {
"/v1/users",
"/v1/gallerys/previews",
"/v1/surveys/*/bookmarks",
"/v1/gallerys",
};

@Override
Expand Down
2 changes: 2 additions & 0 deletions gallery/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ repositories {

dependencies {
implementation project(":core:data")
implementation project(":core:id-generator:id-core")
implementation project(":core:time")
implementation project(":survey:survey-application")

implementation "org.springframework.boot:spring-boot-starter-web"
Expand Down
24 changes: 14 additions & 10 deletions gallery/src/main/kotlin/me/nalab/gallery/app/GalleryDtoMapper.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.nalab.gallery.app

import me.nalab.gallery.domain.response.GalleryPreviewDto
import me.nalab.gallery.domain.Gallery
import me.nalab.gallery.domain.response.GalleryDto
import me.nalab.survey.application.common.feedback.dto.BookmarkDto
import me.nalab.survey.application.common.feedback.dto.ChoiceFormQuestionFeedbackDto
import me.nalab.survey.application.common.feedback.dto.FeedbackDto
Expand All @@ -10,21 +11,24 @@ import me.nalab.survey.application.common.survey.dto.ChoiceFormQuestionDtoType
import me.nalab.survey.application.common.survey.dto.SurveyDto
import me.nalab.survey.application.common.survey.dto.TargetDto

fun toGalleryPreviewDto(
fun toGalleryDto(
gallery: Gallery,
target: TargetDto,
survey: SurveyDto,
feedbacks: List<FeedbackDto>,
): GalleryPreviewDto {
return GalleryPreviewDto(
target = GalleryPreviewDto.Target(
targetId = target.id.toString(),
): GalleryDto {
return GalleryDto(
galleryId = gallery.id,
target = GalleryDto.Target(
targetId = gallery.getTargetId().toString(),
nickname = target.nickname,
job = gallery.getJob(),
position = target.position,
),
survey = GalleryPreviewDto.Survey(
survey = GalleryDto.Survey(
surveyId = survey.id.toString(),
feedbackCount = feedbacks.size,
bookmarkedCount = 0,
bookmarkedCount = gallery.getBookmarkedCount(),
feedbacks = findLatestBookmarkedReply(feedbacks),
tendencies = findTendencies(survey, feedbacks),
)
Expand Down Expand Up @@ -58,7 +62,7 @@ private fun List<FeedbackDto>.mapBookmarkedWithReply(): List<Pair<BookmarkDto, L
private fun findTendencies(
survey: SurveyDto,
feedbacks: List<FeedbackDto>,
): List<GalleryPreviewDto.Survey.Tendency> {
): List<GalleryDto.Survey.Tendency> {
val tendencyQuestion = survey.formQuestionDtoableList
.filterIsInstance<ChoiceFormQuestionDto>()
.find { it.choiceFormQuestionDtoType == ChoiceFormQuestionDtoType.TENDENCY }
Expand All @@ -80,7 +84,7 @@ private fun findTendencies(
}

return countPerTendency.map { (name, count) ->
GalleryPreviewDto.Survey.Tendency(name, count)
GalleryDto.Survey.Tendency(name, count)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package me.nalab.gallery.app

import me.nalab.gallery.domain.response.GalleryPreviewDto
import me.nalab.survey.application.common.feedback.dto.BookmarkDto
import me.nalab.survey.application.common.feedback.dto.ChoiceFormQuestionFeedbackDto
import me.nalab.survey.application.common.feedback.dto.FeedbackDto
import me.nalab.survey.application.common.feedback.dto.ShortFormQuestionFeedbackDto
import me.nalab.survey.application.common.survey.dto.ChoiceFormQuestionDto
import me.nalab.survey.application.common.survey.dto.ChoiceFormQuestionDtoType
import me.nalab.survey.application.common.survey.dto.SurveyDto
import me.nalab.survey.application.common.survey.dto.TargetDto

fun toGalleryPreviewDto(
target: TargetDto,
survey: SurveyDto,
feedbacks: List<FeedbackDto>,
): GalleryPreviewDto {
return GalleryPreviewDto(
target = GalleryPreviewDto.Target(
targetId = target.id.toString(),
nickname = target.nickname,
position = target.position,
),
survey = GalleryPreviewDto.Survey(
surveyId = survey.id.toString(),
feedbackCount = feedbacks.size,
bookmarkedCount = 0,
feedbacks = findLatestBookmarkedReply(feedbacks),
tendencies = findTendencies(survey, feedbacks),
)
)
}

private fun findLatestBookmarkedReply(feedbacks: List<FeedbackDto>): List<String> {
return feedbacks.filterBookmarkedFeedback()
.mapBookmarkedWithReply()
.sortedByDescending { (bookmark, _) -> bookmark.bookmarkedAt }
.firstOrNull()
?.second ?: emptyList()
}

private fun List<FeedbackDto>.filterBookmarkedFeedback(): List<FeedbackDto> {
return this.filter { feedback ->
feedback.formQuestionFeedbackDtoableList.any { formQuestionFeedback ->
formQuestionFeedback.bookmarkDto.isBookmarked
}
}
}

private fun List<FeedbackDto>.mapBookmarkedWithReply(): List<Pair<BookmarkDto, List<String>>> {
return this.flatMap { bookmarkedFeedback ->
bookmarkedFeedback.formQuestionFeedbackDtoableList
.filterIsInstance<ShortFormQuestionFeedbackDto>()
.map { shortQuestionFeedback -> shortQuestionFeedback.bookmarkDto to shortQuestionFeedback.replyList }
}
}

private fun findTendencies(
survey: SurveyDto,
feedbacks: List<FeedbackDto>,
): List<GalleryPreviewDto.Survey.Tendency> {
val tendencyQuestion = survey.formQuestionDtoableList
.filterIsInstance<ChoiceFormQuestionDto>()
.find { it.choiceFormQuestionDtoType == ChoiceFormQuestionDtoType.TENDENCY }
?: error("필수 유형 Tendency 를 찾을 수 없습니다.")

val countPerTendency = mutableMapOf<String, Int>()

feedbacks.mapTendencyFeedbacks(tendencyQuestion)
.forEach { tendencyFeedback ->
tendencyQuestion.choiceDtoList
.filter { choice ->
tendencyFeedback.selectedChoiceIdSet.contains(choice.id)
}
.map { it.content }
.forEach { tendencyContent ->
countPerTendency[tendencyContent] =
countPerTendency.getOrDefault(tendencyContent, 0) + 1
}
}

return countPerTendency.map { (name, count) ->
GalleryPreviewDto.Survey.Tendency(name, count)
}
}

private fun List<FeedbackDto>.mapTendencyFeedbacks(
tendencyQuestion: ChoiceFormQuestionDto,
): List<ChoiceFormQuestionFeedbackDto> {
return this.flatMap {
it.formQuestionFeedbackDtoableList
.filterIsInstance<ChoiceFormQuestionFeedbackDto>()
.filter { choiceQuestionFeedback ->
choiceQuestionFeedback.questionId == tendencyQuestion.id
}
}
}
51 changes: 51 additions & 0 deletions gallery/src/main/kotlin/me/nalab/gallery/app/GalleryRegisterApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package me.nalab.gallery.app

import me.nalab.core.idgenerator.idcore.IdGenerator
import me.nalab.core.time.TimeUtil
import me.nalab.gallery.domain.Gallery
import me.nalab.gallery.domain.GalleryService
import me.nalab.gallery.domain.Job
import me.nalab.gallery.domain.response.GalleryDto
import me.nalab.survey.application.common.survey.dto.SurveyDto
import me.nalab.survey.application.common.survey.dto.TargetDto
import me.nalab.survey.application.port.`in`.web.findfeedback.FeedbackFindUseCase
import me.nalab.survey.application.port.`in`.web.survey.find.SurveyFindUseCase
import me.nalab.survey.application.port.`in`.web.target.find.TargetFindUseCase
import org.springframework.stereotype.Service

@Service
class GalleryRegisterApp(
private val idGenerator: IdGenerator,
private val targetFindUseCase: TargetFindUseCase,
private val surveyFindUseCase: SurveyFindUseCase,
private val feedbackFindUseCase: FeedbackFindUseCase,
private val galleryService: GalleryService,
) {

fun registerGalleryByTargetId(targetId: Long, job: String): GalleryDto {
val target = targetFindUseCase.findTarget(targetId)
val survey = surveyFindUseCase.getSurveyByTargetId(targetId)

val gallery = galleryService.registerGallery(toGallery(job, target, survey))

val feedbacks = feedbackFindUseCase.findAllFeedbackDtoBySurveyId(survey.id)

return toGalleryDto(gallery, target, survey, feedbacks)
}

private fun toGallery(
job: String,
target: TargetDto,
survey: SurveyDto,
): Gallery {
return Gallery(
id = idGenerator.generate(),
targetId = target.id,
job = Job.valueOf(job.uppercase()),
surveyId = survey.id,
bookmarkedCount = target.bookmarkedSurveys.size,
updateOrder = TimeUtil.toInstant(),
)
}

}
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package me.nalab.gallery.controller

import me.nalab.gallery.app.GalleryPreviewApp
import me.nalab.gallery.app.GalleryRegisterApp
import me.nalab.gallery.controller.request.GalleryRegisterRequest
import me.nalab.gallery.domain.response.GalleryDto
import me.nalab.gallery.domain.response.GalleryPreviewDto
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestAttribute
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/v1/gallerys")
class GalleryController(
private val galleryPreviewApp: GalleryPreviewApp,
private val galleryRegisterApp: GalleryRegisterApp,
) {

@GetMapping("/previews")
@ResponseStatus(HttpStatus.OK)
fun getGalleryPreview(@RequestAttribute("logined") targetId: Long): GalleryPreviewDto =
galleryPreviewApp.findGalleryPreview(targetId)

@PostMapping
@ResponseStatus(HttpStatus.OK)
fun registerGallery(
@RequestAttribute("logined") targetId: Long,
@RequestBody request: GalleryRegisterRequest,
): GalleryDto {
return galleryRegisterApp.registerGalleryByTargetId(targetId, request.job)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package me.nalab.gallery.controller.request

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

data class GalleryRegisterRequest @JsonCreator constructor(
@JsonProperty("job")
val job: String,
)
26 changes: 25 additions & 1 deletion gallery/src/main/kotlin/me/nalab/gallery/domain/Gallery.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.nalab.gallery.domain

import me.nalab.core.data.common.TimeBaseEntity
import me.nalab.core.time.TimeUtil
import java.time.Instant
import javax.persistence.*

Expand All @@ -19,4 +20,27 @@ class Gallery(

@Column(name = "update_order", columnDefinition = "TIMESTAMP(6)", nullable = false)
private var updateOrder: Instant,
) : TimeBaseEntity()

@Version
private var version: Long? = null,
) : TimeBaseEntity() {

constructor(
id: Long,
targetId: Long,
job: Job,
surveyId: Long,
bookmarkedCount: Int = 0,
updateOrder: Instant = TimeUtil.toInstant(),
): this(id, Target(targetId, job), Survey(surveyId, bookmarkedCount), updateOrder)

fun getTargetId(): Long = target.targetId

fun getJob(): Job = target.job

fun getBookmarkedCount(): Int = survey.bookmarkedCount

fun increaseBookmarkedCount() {
survey.bookmarkedCount++
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package me.nalab.gallery.domain

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Lock
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import javax.persistence.LockModeType

interface GalleryRepository : JpaRepository<Gallery, Long> {

@Lock(LockModeType.OPTIMISTIC)
@Query("select g from Gallery as g where g.target.targetId = :targetId")
fun findByTargetIdOrNull(@Param("targetId") targetId: Long): Gallery?
}
24 changes: 24 additions & 0 deletions gallery/src/main/kotlin/me/nalab/gallery/domain/GalleryService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package me.nalab.gallery.domain

import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class GalleryService(
private val galleryRepository: GalleryRepository,
) {

@Transactional
fun registerGallery(gallery: Gallery): Gallery {
require(galleryRepository.findByTargetIdOrNull(gallery.getTargetId()) == null) {
"target \"${gallery.getTargetId()}\" 이 이미 Gallery에 등록되어있습니다."
}

return galleryRepository.save(gallery)
}

@Transactional
fun increaseBookmarkCount(targetId: Long) {
galleryRepository.findByTargetIdOrNull(targetId)?.increaseBookmarkedCount()
}
}
Loading

0 comments on commit ee4accf

Please sign in to comment.