Skip to content

Commit

Permalink
Merge pull request #31 from Team-Plu/feat/#29
Browse files Browse the repository at this point in the history
[FEAT] 답변 공감 기능
  • Loading branch information
PgmJun authored Mar 18, 2024
2 parents ae446d3 + 30e4021 commit 12cdc0d
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import com.th.plu.api.service.answer.AnswerService
import com.th.plu.common.dto.response.ApiResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*

@Tag(name = "Answer")
@RestController
Expand All @@ -19,9 +16,25 @@ class AnswerController(
private val answerService: AnswerService
) {
@Auth
@Operation(summary = "답변 조회")
@Operation(summary = "[인증] 질문 답변 조회")
@GetMapping("/v1/answer/{answerId}")
fun findAnswerById(@PathVariable answerId: Long, @MemberId memberId: Long): ApiResponse<AnswerInfoResponse> {
return ApiResponse.success(answerService.findAnswerInfoById(answerId, memberId))
fun findAnswerInfoById(@PathVariable answerId: Long): ApiResponse<AnswerInfoResponse> {
return ApiResponse.success(answerService.findAnswerInfoById(answerId))
}

@Auth
@Operation(summary = "[인증] 질문 답변 공감")
@PostMapping("/v1/answer/like/{answerId}")
fun likeAnswer(@PathVariable answerId: Long, @MemberId memberId: Long): ApiResponse<Any> {
answerService.createLike(memberId, answerId)
return ApiResponse.success()
}

@Auth
@Operation(summary = "[인증] 질문 답변 공감 취소")
@DeleteMapping("/v1/answer/like/{answerId}")
fun dislikeAnswer(@PathVariable answerId: Long, @MemberId memberId: Long): ApiResponse<Any> {
answerService.deleteLike(memberId, answerId)
return ApiResponse.success()
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package com.th.plu.api.service.answer

import com.th.plu.api.controller.answer.dto.response.AnswerInfoResponse
import com.th.plu.api.service.like.LikeValidator
import com.th.plu.domain.domain.answer.explorer.AnswerExplorer
import com.th.plu.domain.domain.answer.explorer.QuestionExplorer
import com.th.plu.domain.domain.like.Like
import com.th.plu.domain.domain.like.explorer.LikeExplorer
import com.th.plu.domain.domain.like.repository.LikeRepository
import com.th.plu.domain.domain.member.explorer.MemberExplorer
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class AnswerService(
private val questionExplorer: QuestionExplorer,
private val answerExplorer: AnswerExplorer,
private val answerValidator: AnswerValidator
private val likeRepository: LikeRepository,
private val likeExplorer: LikeExplorer,
private val likeValidator: LikeValidator,
private val memberExplorer: MemberExplorer
) {
@Transactional(readOnly = true)
fun findAnswerInfoById(answerId: Long, memberId: Long): AnswerInfoResponse {
Expand All @@ -22,4 +28,22 @@ class AnswerService(

return AnswerInfoResponse.of(question, answer)
}

@Transactional
fun createLike(memberId: Long, answerId: Long) {
val member = memberExplorer.findMemberById(memberId)
val answer = answerExplorer.findAnswerById(answerId)

likeValidator.validateNotExistLike(member = member, answer = answer, question = answer.question)
likeRepository.save(Like.newInstance(answer = answer, member = member, question = answer.question))
}

@Transactional
fun deleteLike(memberId: Long, answerId: Long) {
val member = memberExplorer.findMemberById(memberId)
val answer = answerExplorer.findAnswerById(answerId)

val like = likeExplorer.findLikeByMemberAndAnswerAndQuestion(member = member, answer = answer, question = answer.question)
likeRepository.delete(like)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.th.plu.api.service.like

import com.th.plu.common.exception.code.ErrorCode
import com.th.plu.common.exception.model.ConflictException
import com.th.plu.domain.domain.answer.Answer
import com.th.plu.domain.domain.like.repository.LikeRepository
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.question.Question
import org.springframework.stereotype.Component

@Component
class LikeValidator(
private val likeRepository: LikeRepository
) {
fun validateNotExistLike(member: Member, answer: Answer, question: Question) {
if (likeRepository.existByMemberAndAnswerAndQuestion(member = member, answer = answer, question = question)) {
throw ConflictException(ErrorCode.CONFLICT_LIKE_EXCEPTION, "이미 회원(ID: ${member.id}은 해당 답변(ID: ${answer.id})에 대한 공감이 되어있습니다.")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class ErrorCode(val code: String, val message: String) {
NOT_FOUND_MEMBER_EXCEPTION("N002", "탈퇴했거나 존재하지 않는 회원입니다."),
NOT_FOUND_ANSWER_EXCEPTION("N003", "존재하지 않는 답변입니다."),
NOT_FOUND_QUESTION_EXCEPTION("N004", "존재하지 않는 질문입니다."),
NOT_FOUND_LIKE_EXCEPTION("N005", "존재하지 않는 공감 정보입니다."),
NOT_FOUND_ARTICLE_CONTENT_EXCEPTION("N003", "아티클의 컨텐츠가 존재하지 않습니다."),
NOT_FOUND_CHALLENGE_EXCEPTION("N004", "존재하지 않는 챌린지입니다."),
NOT_FOUND_ARTICLE_EXCEPTION("N005", "삭제되었거나 존재하지 않는 아티클입니다."),
Expand All @@ -34,6 +35,7 @@ enum class ErrorCode(val code: String, val message: String) {
// Conflict Exception
CONFLICT_EXCEPTION("C001", "이미 존재합니다."),
CONFLICT_MEMBER_EXCEPTION("C002", "이미 해당 계정으로 회원가입하셨습니다.\n로그인 해주세요."),
CONFLICT_LIKE_EXCEPTION("C003", "이미 해당 답변에 대한 공감이 되어있습니다."),
CONFLICT_BOOKMARK_EXCEPTION("C003", "요청과 동일한 북마크 상태 입니다."),
CONFLICT_NICKNAME_EXCEPTION("C004", "이미 사용 중인 닉네임 입니다."),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,4 @@ class Answer(
fun getLikeCount(): Int {
return likes.size
}

fun getQuestionId(): Long {
return question.id!!
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class Like(
@Column(name = "like_id")
var id: Long? = null,

@ManyToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
var member: Member,

@ManyToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "answer_id", nullable = false)
var answer: Answer,

@ManyToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "question_id", nullable = false)
var question: Question

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.th.plu.domain.domain.like.explorer

import com.th.plu.common.exception.code.ErrorCode
import com.th.plu.common.exception.model.NotFoundException
import com.th.plu.domain.domain.answer.Answer
import com.th.plu.domain.domain.like.Like
import com.th.plu.domain.domain.like.repository.LikeRepository
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.question.Question
import org.springframework.stereotype.Component

@Component
class LikeExplorer(
private val likeRepository: LikeRepository
) {
fun findLikeByMemberAndAnswerAndQuestion(member: Member, answer: Answer, question: Question): Like {
return likeRepository.findLikeByMemberAndAnswerAndQuestion(member = member, answer = answer, question = question)
?: throw NotFoundException(ErrorCode.NOT_FOUND_LIKE_EXCEPTION, "존재하지 않는 공감 입니다")
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.th.plu.domain.domain.like.repository

import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.like.Like
import org.springframework.data.jpa.repository.JpaRepository

interface LikeRepository : JpaRepository<Member, Long>, LikeRepositoryCustom {
interface LikeRepository : JpaRepository<Like, Long>, LikeRepositoryCustom {
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package com.th.plu.domain.domain.like.repository

import com.th.plu.domain.domain.answer.Answer
import com.th.plu.domain.domain.like.Like
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.question.Question

interface LikeRepositoryCustom {

fun findLikeById(id: Long): Like?

fun existByMemberAndAnswerAndQuestion(member: Member, answer: Answer, question: Question): Boolean

fun findLikeByMemberAndAnswerAndQuestion(member: Member, answer: Answer, question: Question): Like?
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.th.plu.domain.domain.like.repository

import com.querydsl.jpa.impl.JPAQueryFactory
import com.th.plu.domain.domain.answer.Answer
import com.th.plu.domain.domain.like.Like
import com.th.plu.domain.domain.like.QLike.like
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.question.Question
import org.springframework.stereotype.Repository

@Repository
Expand All @@ -11,6 +14,26 @@ class LikeRepositoryImpl(private val queryFactory: JPAQueryFactory) : LikeReposi
return queryFactory
.selectFrom(like)
.where(like.id.eq(id))
.fetchOne();
.fetchOne()
}

override fun existByMemberAndAnswerAndQuestion(member: Member, answer: Answer, question: Question): Boolean {
return queryFactory
.selectFrom(like)
.where(
like.member.eq(member),
like.answer.eq(answer),
like.question.eq(question)
).fetchOne() != null
}

override fun findLikeByMemberAndAnswerAndQuestion(member: Member, answer: Answer, question: Question): Like? {
return queryFactory
.selectFrom(like)
.where(
like.member.eq(member),
like.answer.eq(answer),
like.question.eq(question)
).fetchOne()
}
}

0 comments on commit 12cdc0d

Please sign in to comment.