From 90dc41352ee7165bc7709d2841738955da7cc446 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:34:49 +0900 Subject: [PATCH 01/18] [feat] create debate vote request --- .../www/newsnackserver/dto/request/DebateVoteRequest.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java new file mode 100644 index 0000000..7b568b2 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java @@ -0,0 +1,7 @@ +package com.newsnack.www.newsnackserver.dto.request; + +import jakarta.validation.constraints.Max; +import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; + +public record DebateVoteRequest(boolean vote) { +} From d7bc9c27d622326759a2272d18d8b534b63e39da Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:35:10 +0900 Subject: [PATCH 02/18] [feat] create debate vote failure code --- .../common/code/failure/DebateFailureCode.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateFailureCode.java b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateFailureCode.java index a57e0c2..2c6ff81 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateFailureCode.java +++ b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateFailureCode.java @@ -11,7 +11,12 @@ public enum DebateFailureCode implements FailureCode { /** * 404 Not Found */ - DEBATE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 토론입니다."); + DEBATE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 토론입니다."), + + /** + * 409 Conflict + */ + ALREADY_VOTED_DEBATE(HttpStatus.NOT_FOUND, "이미 투표햤습니다"); private final HttpStatus httpStatus; private final String message; From 788675d2851b7bb1784e13e1997815063192ecd0 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:35:56 +0900 Subject: [PATCH 03/18] [feat] add functions for votecount in Debate --- .../www/newsnackserver/domain/debate/model/Debate.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debate/model/Debate.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debate/model/Debate.java index e66d627..8888abd 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debate/model/Debate.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debate/model/Debate.java @@ -27,4 +27,12 @@ public class Debate extends BaseTimeEntity { @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "article_id") private Article article; + + public void upVote() { + this.upVoteCount++; + } + + public void downVote() { + this.downVoteCount++; + } } From ccd6085de948530521137046a604da8eb2f1abed Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:37:03 +0900 Subject: [PATCH 04/18] [feat] create debate related success code --- .../common/code/success/DebateSuccessCode.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateSuccessCode.java b/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateSuccessCode.java index c786eff..e3ec992 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateSuccessCode.java +++ b/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateSuccessCode.java @@ -11,7 +11,11 @@ public enum DebateSuccessCode implements SuccessCode{ /** * 200 OK **/ - GET_DEBATES_SUCCESS(HttpStatus.OK, "토론 조회 성공"); + GET_DEBATES_SUCCESS(HttpStatus.OK, "토론 조회 성공"), + /** + * 201 CREATED + **/ + DEBATE_VOTE_SUCCESS(HttpStatus.CREATED, "투표 성공"); private final HttpStatus httpStatus; private final String message; From 5b18a1ed99cf05e5469d5dc7f6d7b81fd071fbb0 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:37:17 +0900 Subject: [PATCH 05/18] [feat] create logic for vote debate api --- .../model/DebateParticipation.java | 6 +++++ .../DebateParticipationJpaRepository.java | 4 +++- .../newsnackserver/service/DebateService.java | 24 ++++++++++++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java index 87482d1..c074cf3 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java @@ -28,4 +28,10 @@ public class DebateParticipation { private String comment; + public DebateParticipation(Debate debate, Member member, Boolean vote) { + this.debate = debate; + this.member = member; + this.vote = vote; + } + } diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java index 916409d..00d7d83 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java @@ -1,10 +1,12 @@ package com.newsnack.www.newsnackserver.domain.debateparticipation.repository; +import com.newsnack.www.newsnackserver.domain.debate.model.Debate; import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; +import com.newsnack.www.newsnackserver.domain.member.model.Member; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface DebateParticipationJpaRepository extends JpaRepository { - Optional findByDebateIdAndMemberId(Long debateId, Long memberId); + Optional findByDebateAndMember(Debate debate, Member member); } diff --git a/src/main/java/com/newsnack/www/newsnackserver/service/DebateService.java b/src/main/java/com/newsnack/www/newsnackserver/service/DebateService.java index 2a12efb..0637f0d 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/service/DebateService.java +++ b/src/main/java/com/newsnack/www/newsnackserver/service/DebateService.java @@ -2,10 +2,13 @@ import com.newsnack.www.newsnackserver.common.code.failure.DebateFailureCode; import com.newsnack.www.newsnackserver.common.exception.DebateException; +import com.newsnack.www.newsnackserver.common.exception.DebateParticipationException; import com.newsnack.www.newsnackserver.domain.debate.model.Debate; import com.newsnack.www.newsnackserver.domain.debate.repository.DebateJpaRepository; import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; import com.newsnack.www.newsnackserver.domain.debateparticipation.repository.DebateParticipationJpaRepository; +import com.newsnack.www.newsnackserver.domain.member.model.Member; +import com.newsnack.www.newsnackserver.domain.member.repository.MemberJpaRepository; import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import com.newsnack.www.newsnackserver.dto.response.DebateMainPageResponse; import lombok.RequiredArgsConstructor; @@ -22,6 +25,7 @@ public class DebateService { private final DebateJpaRepository debateJpaRepository; private final DebateParticipationJpaRepository debateParticipationJpaRepository; + private final MemberJpaRepository memberJpaRepository; public DebateMainPageResponse getMainDebate() { Debate debate = debateJpaRepository.findLatestDebateWithArticleJPQL().orElseThrow(() -> new DebateException(DebateFailureCode.DEBATE_NOT_FOUND)); @@ -30,12 +34,13 @@ public DebateMainPageResponse getMainDebate() { public DebateIndividualResponse getDebate(Long debateId, Long memberId) { Debate debate = debateJpaRepository.findDebateWithArticleJPQL(debateId).orElseThrow(() -> new DebateException(DebateFailureCode.DEBATE_NOT_FOUND)); + Member member = memberJpaRepository.getReferenceById(memberId); if (memberId == null) {//access 없다면 return DebateIndividualResponse.of(debate, null); } DebateParticipation debateParticipation; try { - debateParticipation = debateParticipationJpaRepository.findByDebateIdAndMemberId(debateId, memberId).get(); + debateParticipation = debateParticipationJpaRepository.findByDebateAndMember(debate, member).get(); } catch (NoSuchElementException e) { return DebateIndividualResponse.of(debate, null); } @@ -45,4 +50,21 @@ public DebateIndividualResponse getDebate(Long debateId, Long memberId) { public List getDebates() { return debateJpaRepository.findAllDebateWithArticleOrderByCreatedAtDescJPQL().stream().map(DebateMainPageResponse::from).collect(Collectors.toList()); } + + @Transactional + public void voteDebate(Long debateId, Long memberId, boolean vote) { + Debate debate = debateJpaRepository.findById(debateId).orElseThrow(() -> new DebateException(DebateFailureCode.DEBATE_NOT_FOUND)); + Member member = memberJpaRepository.getReferenceById(memberId); + debateParticipationJpaRepository.findByDebateAndMember(debate, member).ifPresentOrElse( + debateParticipation -> { + throw new DebateParticipationException(DebateFailureCode.ALREADY_VOTED_DEBATE); + }, + () -> debateParticipationJpaRepository.save(new DebateParticipation(debate, member, vote))); + if (vote) { + debate.upVote(); + } + if (!vote) { + debate.downVote(); + } + } } \ No newline at end of file From 23a24535d8ec8a105097db6d38b412c687288609 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:38:08 +0900 Subject: [PATCH 06/18] [feat] create vote debate api --- .../newsnackserver/controller/DebateController.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java index f0d13fd..c36bfca 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java +++ b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java @@ -3,14 +3,13 @@ import com.newsnack.www.newsnackserver.annotation.MemberId; import com.newsnack.www.newsnackserver.common.code.success.DebateSuccessCode; import com.newsnack.www.newsnackserver.common.response.NewSnackResponse; +import com.newsnack.www.newsnackserver.dto.request.DebateVoteRequest; import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import com.newsnack.www.newsnackserver.dto.response.DebateMainPageResponse; import com.newsnack.www.newsnackserver.service.DebateService; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; -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.*; import java.util.List; @@ -35,4 +34,10 @@ public NewSnackResponse getMainDebate() { public NewSnackResponse getDebate(@PathVariable Long debateId, @MemberId(isForSecuredApi = false) Long memberId) { return NewSnackResponse.success(DebateSuccessCode.GET_DEBATES_SUCCESS, debateService.getDebate(debateId, memberId)); } + + @PostMapping("/{debateId}/votes") + public NewSnackResponse voteDebate(@PathVariable Long debateId, @MemberId Long memberId, @RequestBody DebateVoteRequest debateVoteRequest) { + debateService.voteDebate(debateId, memberId, debateVoteRequest.vote()); + return NewSnackResponse.success(DebateSuccessCode.DEBATE_VOTE_SUCCESS); + } } From a9b94d22a154a4b6525123eb07338d9947edc259 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Wed, 20 Mar 2024 20:38:41 +0900 Subject: [PATCH 07/18] [feat] create DebateParticipationException --- .../DebateParticipationException.java | 18 ++++++++++++++++++ .../handler/NewSnackControllerAdvice.java | 7 +++++++ 2 files changed, 25 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/common/exception/DebateParticipationException.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/exception/DebateParticipationException.java b/src/main/java/com/newsnack/www/newsnackserver/common/exception/DebateParticipationException.java new file mode 100644 index 0000000..30c9e4e --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/common/exception/DebateParticipationException.java @@ -0,0 +1,18 @@ +package com.newsnack.www.newsnackserver.common.exception; + +import com.newsnack.www.newsnackserver.common.code.failure.FailureCode; +import lombok.Getter; + +@Getter +public class DebateParticipationException extends RuntimeException{ + private final FailureCode failureCode; + public DebateParticipationException(FailureCode failureCode) { + super("[DebateParticipationException] : " + failureCode.getMessage()); + this.failureCode = failureCode; + } + + public int getHttpStatusCode() { + return failureCode.getHttpStatus().value(); + } + +} diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/handler/NewSnackControllerAdvice.java b/src/main/java/com/newsnack/www/newsnackserver/common/handler/NewSnackControllerAdvice.java index e988fcb..c342dbf 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/common/handler/NewSnackControllerAdvice.java +++ b/src/main/java/com/newsnack/www/newsnackserver/common/handler/NewSnackControllerAdvice.java @@ -49,6 +49,13 @@ public ResponseEntity> handleDebateException(DebateException .body(NewSnackResponse.error(e.getFailureCode())); } + @ExceptionHandler(DebateParticipationException.class) + public ResponseEntity> handleDebateParticipationException(DebateParticipationException e) { + log.info("handleDebateParticipationException() in NewSnackControllerAdvice throw DebateParticipationException : {}", e.getMessage()); + return ResponseEntity.status(e.getHttpStatusCode()) + .body(NewSnackResponse.error(e.getFailureCode())); + } + @ExceptionHandler(MemberException.class) public ResponseEntity> handleMemberException(MemberException e) { log.info("handleMemberException() in NewSnackControllerAdvice throw MemberException : {}", e.getMessage()); From f8fb0c1080d460186337e036116edb1fa33c9724 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Thu, 21 Mar 2024 02:29:28 +0900 Subject: [PATCH 08/18] [feat] create debateparticipation codes --- .../DebateParticipationFailureCode.java | 22 +++++++++++++++++++ .../DebateParticipationSuccessCode.java | 17 ++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java create mode 100644 src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateParticipationSuccessCode.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java new file mode 100644 index 0000000..d0b87f2 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java @@ -0,0 +1,22 @@ +package com.newsnack.www.newsnackserver.common.code.failure; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum DebateParticipationFailureCode implements FailureCode { + /** + * 404 Not Found + */ + NOT_PARTICIPATED_DEBATE(HttpStatus.NOT_FOUND,"투표를 먼저 하셔야 합니다"), + /** + * 409 Conflict + */ + ALREADY_COMMENTED_DEBATE(HttpStatus.CONFLICT,"이미 작성한 댓글입니다"); + + + private final HttpStatus httpStatus; + private final String message; +} diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateParticipationSuccessCode.java b/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateParticipationSuccessCode.java new file mode 100644 index 0000000..25aa445 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/common/code/success/DebateParticipationSuccessCode.java @@ -0,0 +1,17 @@ +package com.newsnack.www.newsnackserver.common.code.success; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum DebateParticipationSuccessCode implements SuccessCode{ + /** + * 200 OK + **/ + DEBATE_PARTICIPATION_SUCCESS(HttpStatus.OK, "토론 댓글 작성 성공"); + + private final HttpStatus httpStatus; + private final String message; +} From 594760d14652988cdac893499206f0a95ee984ae Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Thu, 21 Mar 2024 02:30:06 +0900 Subject: [PATCH 09/18] [feat] create service logic for create debate participation comment --- .../service/DebateParticipationService.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java new file mode 100644 index 0000000..02fd8d5 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java @@ -0,0 +1,35 @@ +package com.newsnack.www.newsnackserver.service; + +import com.newsnack.www.newsnackserver.common.code.failure.DebateParticipationFailureCode; +import com.newsnack.www.newsnackserver.common.exception.DebateParticipationException; +import com.newsnack.www.newsnackserver.domain.debate.model.Debate; +import com.newsnack.www.newsnackserver.domain.debate.repository.DebateJpaRepository; +import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; +import com.newsnack.www.newsnackserver.domain.debateparticipation.repository.DebateParticipationJpaRepository; +import com.newsnack.www.newsnackserver.domain.member.model.Member; +import com.newsnack.www.newsnackserver.domain.member.repository.MemberJpaRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Transactional(readOnly = true) +@Service +@RequiredArgsConstructor +public class DebateParticipationService { + private final DebateParticipationJpaRepository debateParticipationJpaRepository; + private final DebateJpaRepository debateJpaRepository; + private final MemberJpaRepository memberJpaRepository; + + @Transactional + public void participateDebate(Long debateId, Long memberId, String content) { + Debate debate = debateJpaRepository.getReferenceById(debateId); + Member member = memberJpaRepository.getReferenceById(memberId); + + DebateParticipation debateParticipation = debateParticipationJpaRepository.findByDebateAndMember(debate, member) + .orElseThrow(() -> new DebateParticipationException(DebateParticipationFailureCode.NOT_PARTICIPATED_DEBATE)); + if (debateParticipation.getComment() != null) { + throw new DebateParticipationException(DebateParticipationFailureCode.ALREADY_COMMENTED_DEBATE); + } + debateParticipation.updateComment(content); + } +} From 64e924f11902879ab5a7743aba50076bbefde265 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Thu, 21 Mar 2024 02:30:33 +0900 Subject: [PATCH 10/18] [feat] create function for updating comment in DebateParticipation --- .../domain/debateparticipation/model/DebateParticipation.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java index c074cf3..a1f953a 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java @@ -28,6 +28,10 @@ public class DebateParticipation { private String comment; + public void updateComment(String comment) { + this.comment = comment; + } + public DebateParticipation(Debate debate, Member member, Boolean vote) { this.debate = debate; this.member = member; From 7b4e74f944e98fabbacbf84e9027581a8b772e5c Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Thu, 21 Mar 2024 02:30:53 +0900 Subject: [PATCH 11/18] [feat] create update comment of debate participation api --- .../newsnackserver/controller/DebateController.java | 12 ++++++++++++ .../dto/request/DebateParticipationRequest.java | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateParticipationRequest.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java index c36bfca..bf1a19a 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java +++ b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java @@ -1,12 +1,17 @@ package com.newsnack.www.newsnackserver.controller; import com.newsnack.www.newsnackserver.annotation.MemberId; +import com.newsnack.www.newsnackserver.common.code.success.DebateParticipationSuccessCode; import com.newsnack.www.newsnackserver.common.code.success.DebateSuccessCode; import com.newsnack.www.newsnackserver.common.response.NewSnackResponse; +import com.newsnack.www.newsnackserver.controller.parameter.SearchOrder; +import com.newsnack.www.newsnackserver.dto.request.DebateParticipationRequest; import com.newsnack.www.newsnackserver.dto.request.DebateVoteRequest; import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import com.newsnack.www.newsnackserver.dto.response.DebateMainPageResponse; +import com.newsnack.www.newsnackserver.service.DebateParticipationService; import com.newsnack.www.newsnackserver.service.DebateService; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -19,6 +24,7 @@ public class DebateController { private final DebateService debateService; + private final DebateParticipationService debateParticipationService; @GetMapping public NewSnackResponse> getDebates() { @@ -40,4 +46,10 @@ public NewSnackResponse voteDebate(@PathVariable Long debateId, @MemberId Lon debateService.voteDebate(debateId, memberId, debateVoteRequest.vote()); return NewSnackResponse.success(DebateSuccessCode.DEBATE_VOTE_SUCCESS); } + + @PostMapping("/{debateId}/comments") + public NewSnackResponse createDebateComment(@PathVariable Long debateId, @MemberId Long memberId, @RequestBody @Valid DebateParticipationRequest request) { + debateParticipationService.participateDebate(debateId, memberId, request.content()); + return NewSnackResponse.success(DebateParticipationSuccessCode.DEBATE_PARTICIPATION_SUCCESS); + } } diff --git a/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateParticipationRequest.java b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateParticipationRequest.java new file mode 100644 index 0000000..53d04e3 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateParticipationRequest.java @@ -0,0 +1,7 @@ +package com.newsnack.www.newsnackserver.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record DebateParticipationRequest(@Size(min = 1, max = 200) @NotBlank String content) { +} From ab2de08ba0858f330cb8f0a51870021b851ad7ca Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:28:57 +0900 Subject: [PATCH 12/18] [feat] add permitted path --- .../www/newsnackserver/security/config/SecurityConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java b/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java index afacb83..39a0d0e 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java +++ b/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java @@ -44,6 +44,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/v1/articles/{articleId}", "/v1/articles", "/v1/articles/main").permitAll() .requestMatchers("v1/debates/{debateId}", "/v1/debates", "/v1/debates/main").permitAll() .requestMatchers(HttpMethod.GET, "/v1/articles/{articleId}/comments").permitAll() + .requestMatchers(HttpMethod.GET, "/v1/debates/{debateId}/comments").permitAll() .anyRequest().authenticated())//인증 필요 .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); From 7d14c216c1604a279cb158a750db908808ed377d Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:29:19 +0900 Subject: [PATCH 13/18] [feat] add debateparticipation failureCode --- .../common/code/failure/DebateParticipationFailureCode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java index d0b87f2..e98d968 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java +++ b/src/main/java/com/newsnack/www/newsnackserver/common/code/failure/DebateParticipationFailureCode.java @@ -11,6 +11,7 @@ public enum DebateParticipationFailureCode implements FailureCode { * 404 Not Found */ NOT_PARTICIPATED_DEBATE(HttpStatus.NOT_FOUND,"투표를 먼저 하셔야 합니다"), + NOT_FOUND_DEBATE(HttpStatus.NOT_FOUND, "토론이 없습니다"), /** * 409 Conflict */ From ed4e15c2f66d653cc73ff9d3f793c3811d726837 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:29:46 +0900 Subject: [PATCH 14/18] [feat] create DebateCommentResponse --- .../dto/response/DebateCommentResponse.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java diff --git a/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java b/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java new file mode 100644 index 0000000..aac66c2 --- /dev/null +++ b/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java @@ -0,0 +1,13 @@ +package com.newsnack.www.newsnackserver.dto.response; + +import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; + +import java.time.LocalDateTime; + +public record DebateCommentResponse(Long id, String writerName, long memberId, boolean vote, String content, String createdAt, int likeCount, boolean isLikedByMe, boolean isMyComment) { + public static DebateCommentResponse of(DebateParticipation debateParticipation, boolean isLikedByMe, boolean isMyComment) { + return new DebateCommentResponse(debateParticipation.getId(), debateParticipation.getMember().getName(), debateParticipation.getMember().getId(), + debateParticipation.getVote(), debateParticipation.getComment(), + debateParticipation.getCreatedAt().toString(), debateParticipation.getHeartCount(), isLikedByMe, isMyComment); + } +} From 972876f1ce87c39b1ecdd47495999dc065ee789f Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:30:58 +0900 Subject: [PATCH 15/18] [feat] add field hearCount in debateParticipation --- .../model/DebateParticipation.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java index a1f953a..b863047 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/model/DebateParticipation.java @@ -1,16 +1,21 @@ package com.newsnack.www.newsnackserver.domain.debateparticipation.model; +import com.newsnack.www.newsnackserver.domain.commom.BaseTimeEntity; import com.newsnack.www.newsnackserver.domain.debate.model.Debate; +import com.newsnack.www.newsnackserver.domain.debateparticipationheart.model.DebateParticipationHeart; import com.newsnack.www.newsnackserver.domain.member.model.Member; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.ArrayList; +import java.util.List; + @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class DebateParticipation { +public class DebateParticipation extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -24,10 +29,15 @@ public class DebateParticipation { @JoinColumn(name = "member_id") private Member member; + @OneToMany(mappedBy = "debateParticipation", cascade = CascadeType.ALL, orphanRemoval = true)//둘다 부모 삭제시 자식 모두 삭제, orphanRemoval: debateParticipationHearts.remove만 해도 DB에서 삭제됨 + private List debateParticipationHearts = new ArrayList<>(); + private Boolean vote; private String comment; + private int heartCount; + public void updateComment(String comment) { this.comment = comment; } From 42f46d7a092e2f6bc4e8798d731ae503de743ccc Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:31:12 +0900 Subject: [PATCH 16/18] [feat] create logic for get debate comment list --- .../DebateParticipationJpaRepository.java | 13 +++++++ .../service/DebateParticipationService.java | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java index 00d7d83..876960f 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java +++ b/src/main/java/com/newsnack/www/newsnackserver/domain/debateparticipation/repository/DebateParticipationJpaRepository.java @@ -4,9 +4,22 @@ import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; import com.newsnack.www.newsnackserver.domain.member.model.Member; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import java.util.List; import java.util.Optional; public interface DebateParticipationJpaRepository extends JpaRepository { Optional findByDebateAndMember(Debate debate, Member member); + + @Query("select dp from DebateParticipation dp join fetch dp.member where dp.debate.id = :debateId order by dp.id desc") + List findAllWithMemberByDebateIdOrderByIdDescJPQL(Long debateId); + + @Query("select dp from DebateParticipation dp join fetch dp.member where dp.debate.id = :debateId order by dp.heartCount desc, dp.id desc") + List findAllWithMemberByDebateIdOrderByHeartCountDescJPQL(Long debateId); + + @Query("select distinct dp from DebateParticipation dp left join fetch dp.debateParticipationHearts join fetch dp.member where dp.debate.id = :debateId order by dp.id desc") + List findAllWithMemberAndDebateParticipationHeartByDebateIdOrderByIdDescJPQL(Long debateId); + @Query("select distinct dp from DebateParticipation dp left join fetch dp.debateParticipationHearts join fetch dp.member where dp.debate.id = :debateId order by dp.heartCount desc, dp.id desc") + List findAllWithMemberAndDebateParticipationHeartByDebateIdOrderByHeartCountDescJPQL(Long debateId); } diff --git a/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java index 02fd8d5..e22a979 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java +++ b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java @@ -1,16 +1,27 @@ package com.newsnack.www.newsnackserver.service; +import com.newsnack.www.newsnackserver.annotation.MemberId; import com.newsnack.www.newsnackserver.common.code.failure.DebateParticipationFailureCode; import com.newsnack.www.newsnackserver.common.exception.DebateParticipationException; +import com.newsnack.www.newsnackserver.controller.parameter.SearchOrder; +import com.newsnack.www.newsnackserver.domain.comment.model.Comment; import com.newsnack.www.newsnackserver.domain.debate.model.Debate; import com.newsnack.www.newsnackserver.domain.debate.repository.DebateJpaRepository; import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; import com.newsnack.www.newsnackserver.domain.debateparticipation.repository.DebateParticipationJpaRepository; import com.newsnack.www.newsnackserver.domain.member.model.Member; import com.newsnack.www.newsnackserver.domain.member.repository.MemberJpaRepository; +import com.newsnack.www.newsnackserver.dto.response.CommentResponse; +import com.newsnack.www.newsnackserver.dto.response.DebateCommentResponse; +import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +import static java.util.Arrays.stream; @Transactional(readOnly = true) @Service @@ -32,4 +43,32 @@ public void participateDebate(Long debateId, Long memberId, String content) { } debateParticipation.updateComment(content); } + + public List getDebateComments(Long debateId, Long memberId, SearchOrder searchOrder) { + Debate debate = debateJpaRepository.findById(debateId).orElseThrow(() -> new DebateParticipationException(DebateParticipationFailureCode.NOT_FOUND_DEBATE)); + if(memberId == null) { // 비회원일 경우 + if (searchOrder.getValue().equals(SearchOrder.RECENT.getValue()))// 최신순 정렬 + return debateParticipationJpaRepository.findAllWithMemberByDebateIdOrderByIdDescJPQL(debateId) + .stream().map(debateParticipation -> DebateCommentResponse.of(debateParticipation, false, false)).toList(); + if (searchOrder.getValue().equals(SearchOrder.POPULAR.getValue())) // 인기순 정렬 + return debateParticipationJpaRepository.findAllWithMemberByDebateIdOrderByHeartCountDescJPQL(debateId) + .stream().map(debateParticipation -> DebateCommentResponse.of(debateParticipation, false, false)).toList(); + } + //회원일 경우 1000 -> boolean 값 4개 변경 해야함 + if (searchOrder.getValue().equals(SearchOrder.RECENT.getValue())) {// 최신순 정렬 + return debateParticipationJpaRepository.findAllWithMemberAndDebateParticipationHeartByDebateIdOrderByIdDescJPQL(debateId) + .stream().map(debateParticipation -> DebateCommentResponse.of(debateParticipation, isLikedByMe(debateParticipation, memberId), isMyDebateParticipation(debateParticipation, memberId))).toList(); + } + //인기순 + return debateParticipationJpaRepository.findAllWithMemberAndDebateParticipationHeartByDebateIdOrderByHeartCountDescJPQL(debateId) + .stream().map(debateParticipation -> DebateCommentResponse.of(debateParticipation, isLikedByMe(debateParticipation, memberId), isMyDebateParticipation(debateParticipation, memberId))).toList(); + } + private boolean isLikedByMe(DebateParticipation debateParticipation, Long memberId) { + return debateParticipation.getDebateParticipationHearts().stream().anyMatch(commentHeart -> commentHeart.getMember().getId().equals(memberId)); + } + + private boolean isMyDebateParticipation(DebateParticipation debateParticipation, Long memberId) { + return debateParticipation.getMember().getId().equals(memberId); + } + } From df78c960431c30d3f27ebb096bd4baabfadf11a0 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:31:22 +0900 Subject: [PATCH 17/18] [feat] create get debate comment list api --- .../www/newsnackserver/controller/DebateController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java index bf1a19a..5d2f63e 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java +++ b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java @@ -7,6 +7,7 @@ import com.newsnack.www.newsnackserver.controller.parameter.SearchOrder; import com.newsnack.www.newsnackserver.dto.request.DebateParticipationRequest; import com.newsnack.www.newsnackserver.dto.request.DebateVoteRequest; +import com.newsnack.www.newsnackserver.dto.response.DebateCommentResponse; import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import com.newsnack.www.newsnackserver.dto.response.DebateMainPageResponse; import com.newsnack.www.newsnackserver.service.DebateParticipationService; @@ -52,4 +53,10 @@ public NewSnackResponse createDebateComment(@PathVariable Long debateId, @Mem debateParticipationService.participateDebate(debateId, memberId, request.content()); return NewSnackResponse.success(DebateParticipationSuccessCode.DEBATE_PARTICIPATION_SUCCESS); } + + @GetMapping("/{debateId}/comments") + public NewSnackResponse> getDebateComments(@PathVariable Long debateId, @MemberId(isForSecuredApi = false) Long memberId, + @RequestParam SearchOrder order) { + return NewSnackResponse.success(DebateSuccessCode.GET_DEBATES_SUCCESS, debateParticipationService.getDebateComments(debateId, memberId, order)); + } } From db49e618727ec490a600dfb2d41575ad3f588d55 Mon Sep 17 00:00:00 2001 From: Parkjyun Date: Fri, 22 Mar 2024 01:33:22 +0900 Subject: [PATCH 18/18] [refactor] delete unused import statement --- .../www/newsnackserver/controller/DebateController.java | 1 - .../www/newsnackserver/dto/request/DebateVoteRequest.java | 3 --- .../newsnackserver/dto/response/DebateCommentResponse.java | 2 -- .../www/newsnackserver/security/config/SecurityConfig.java | 2 -- .../newsnackserver/service/DebateParticipationService.java | 7 ------- 5 files changed, 15 deletions(-) diff --git a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java index 5d2f63e..bb2395a 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java +++ b/src/main/java/com/newsnack/www/newsnackserver/controller/DebateController.java @@ -13,7 +13,6 @@ import com.newsnack.www.newsnackserver.service.DebateParticipationService; import com.newsnack.www.newsnackserver.service.DebateService; import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java index 7b568b2..44ccaeb 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java +++ b/src/main/java/com/newsnack/www/newsnackserver/dto/request/DebateVoteRequest.java @@ -1,7 +1,4 @@ package com.newsnack.www.newsnackserver.dto.request; -import jakarta.validation.constraints.Max; -import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; - public record DebateVoteRequest(boolean vote) { } diff --git a/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java b/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java index aac66c2..fe25338 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java +++ b/src/main/java/com/newsnack/www/newsnackserver/dto/response/DebateCommentResponse.java @@ -2,8 +2,6 @@ import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; -import java.time.LocalDateTime; - public record DebateCommentResponse(Long id, String writerName, long memberId, boolean vote, String content, String createdAt, int likeCount, boolean isLikedByMe, boolean isMyComment) { public static DebateCommentResponse of(DebateParticipation debateParticipation, boolean isLikedByMe, boolean isMyComment) { return new DebateCommentResponse(debateParticipation.getId(), debateParticipation.getMember().getName(), debateParticipation.getMember().getId(), diff --git a/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java b/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java index 39a0d0e..701acaa 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java +++ b/src/main/java/com/newsnack/www/newsnackserver/security/config/SecurityConfig.java @@ -17,8 +17,6 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import java.util.List; - @Configuration @EnableWebSecurity @RequiredArgsConstructor diff --git a/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java index e22a979..ffb6031 100644 --- a/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java +++ b/src/main/java/com/newsnack/www/newsnackserver/service/DebateParticipationService.java @@ -1,28 +1,21 @@ package com.newsnack.www.newsnackserver.service; -import com.newsnack.www.newsnackserver.annotation.MemberId; import com.newsnack.www.newsnackserver.common.code.failure.DebateParticipationFailureCode; import com.newsnack.www.newsnackserver.common.exception.DebateParticipationException; import com.newsnack.www.newsnackserver.controller.parameter.SearchOrder; -import com.newsnack.www.newsnackserver.domain.comment.model.Comment; import com.newsnack.www.newsnackserver.domain.debate.model.Debate; import com.newsnack.www.newsnackserver.domain.debate.repository.DebateJpaRepository; import com.newsnack.www.newsnackserver.domain.debateparticipation.model.DebateParticipation; import com.newsnack.www.newsnackserver.domain.debateparticipation.repository.DebateParticipationJpaRepository; import com.newsnack.www.newsnackserver.domain.member.model.Member; import com.newsnack.www.newsnackserver.domain.member.repository.MemberJpaRepository; -import com.newsnack.www.newsnackserver.dto.response.CommentResponse; import com.newsnack.www.newsnackserver.dto.response.DebateCommentResponse; -import com.newsnack.www.newsnackserver.dto.response.DebateIndividualResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.RequestParam; import java.util.List; -import static java.util.Arrays.stream; - @Transactional(readOnly = true) @Service @RequiredArgsConstructor