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

인기 댓글 조회 기능 구현 #206

Merged
merged 4 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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 @@ -32,7 +32,7 @@ public class SecurityConfig {
// swagger
"/swagger-ui/**", "/v3/api-docs/**",
"/members/duplicate",
"/posts", "/posts/{postId}", "/posts/{postId}/vote", "/posts/{postId}/comments",
"/posts", "/posts/{postId}", "/posts/{postId}/vote", "/posts/{postId}/comments/**",
"/notices", "/notices/{noticeId}"
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import balancetalk.global.exception.BalanceTalkException;
import balancetalk.global.exception.ErrorCode;
import balancetalk.global.utils.SecurityUtils;
import balancetalk.module.comment.domain.Comment;
import balancetalk.module.comment.domain.CommentLike;
import balancetalk.module.comment.domain.CommentLikeRepository;
Expand All @@ -16,9 +17,12 @@
import balancetalk.module.post.domain.PostRepository;
import balancetalk.module.vote.domain.Vote;
import balancetalk.module.vote.domain.VoteRepository;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -32,6 +36,9 @@
@RequiredArgsConstructor
public class CommentService {

private static final int BEST_COMMENTS_SIZE = 3;
private static final int MIN_COUNT_FOR_BEST_COMMENT = 15;

private final CommentRepository commentRepository;
private final MemberRepository memberRepository;
private final PostRepository postRepository;
Expand All @@ -53,7 +60,7 @@ public Comment createComment(CommentRequest request, Long postId) {
}

@Transactional(readOnly = true)
public Page<CommentResponse> findAllComments(Long postId, Pageable pageable) {
public Page<CommentResponse> findAllComments(Long postId, String token, Pageable pageable) {
validatePostId(postId);

Page<Comment> comments = commentRepository.findAllByPostId(postId, pageable);
Expand All @@ -65,7 +72,12 @@ public Page<CommentResponse> findAllComments(Long postId, Pageable pageable) {
Long balanceOptionId = voteForComment.map(Vote::getBalanceOption).map(BalanceOption::getId)
.orElseThrow(() -> new BalanceTalkException(NOT_FOUND_BALANCE_OPTION));

return CommentResponse.fromEntity(comment, balanceOptionId);
if (token == null) {
return CommentResponse.fromEntity(comment, balanceOptionId, false);
} else {
Member member = getCurrentMember(memberRepository);
return CommentResponse.fromEntity(comment, balanceOptionId, member.hasLikedComment(comment));
}
});
}

Expand Down Expand Up @@ -180,4 +192,32 @@ public void cancelLikeComment(Long commentId) {

commentLikeRepository.deleteByMemberAndComment(member, comment);
}

@Transactional(readOnly = true)
public List<CommentResponse> findBestComments(Long postId, String token) {
Post post = validatePostId(postId);
List<BalanceOption> options = post.getOptions();

List<CommentResponse> responses = new ArrayList<>();
for (BalanceOption option : options) {
List<Long> memberIdsBySelectedOptionId =
memberRepository.findMemberIdsBySelectedOptionId(option.getId());

List<Comment> bestComments = commentRepository.findBestCommentsByPostId(postId,
memberIdsBySelectedOptionId, 2, PageRequest.of(0, BEST_COMMENTS_SIZE));
Copy link
Contributor

Choose a reason for hiding this comment

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

2에 해당하는 파라미터가 minCountForBest 아닌가요? 그렇다면 최소 추천수가 15가 되어야 하지 않나요?


if (token == null) {
responses.addAll(bestComments.stream()
.map(comment -> CommentResponse.fromEntity(comment, option.getId(), false)).toList());
} else {
Member member = getCurrentMember(memberRepository);
responses.addAll(bestComments.stream()
.map(comment ->
CommentResponse.fromEntity(comment, option.getId(), member.hasLikedComment(comment)))
.toList());
}
}

return responses;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
package balancetalk.module.comment.domain;

import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface CommentRepository extends JpaRepository<Comment, Long> {
Page<Comment> findAllByPostId(Long postId, Pageable pageable);

@Query("select c from Comment c left join c.likes l "
+ "where c.post.id = :postId and c.member.id in :memberIds "
+ "group by c.id "
+ "having count(l) >= :minCountForBest "
+ "order by count(l) desc")
List<Comment> findBestCommentsByPostId(@Param("postId") Long postId,
@Param("memberIds") List<Long> memberIds,
@Param("minCountForBest") int minCountForBest,
Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,24 @@ public class CommentResponse {
@Schema(description = "댓글 추천 수", example = "24")
private int likesCount;

@Schema(description = "추천 여부", example = "true")
private boolean myLike;

@Schema(description = "댓글 생성 날짜")
private LocalDateTime createdAt;

@Schema(description = "댓글 수정 날짜")
private LocalDateTime lastModifiedAt;

public static CommentResponse fromEntity(Comment comment, Long balanceOptionId) {
public static CommentResponse fromEntity(Comment comment, Long balanceOptionId, boolean myLike) {
return CommentResponse.builder()
.id(comment.getId())
.content(comment.getContent())
.memberName(comment.getMember().getNickname())
.postId(comment.getPost().getId())
.selectedOptionId(balanceOptionId)
.likesCount(comment.getLikes().size())
.myLike(myLike)
.createdAt(comment.getCreatedAt())
.lastModifiedAt(comment.getLastModifiedAt())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import balancetalk.module.comment.dto.ReplyCreateRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -31,8 +32,17 @@ public String createComment(@PathVariable Long postId, @RequestBody CommentReque
@ResponseStatus(HttpStatus.OK)
@GetMapping
@Operation(summary = "댓글 목록 조회", description = "post-id에 해당하는 게시글에 있는 모든 댓글을 조회한다.")
public Page<CommentResponse> findAllCommentsByPostId(@PathVariable Long postId, Pageable pageable) {
return commentService.findAllComments(postId, pageable);
public Page<CommentResponse> findAllCommentsByPostId(@PathVariable Long postId, Pageable pageable,
@RequestHeader(value = "Authorization", required = false) String token) {
return commentService.findAllComments(postId, token, pageable);
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/best")
@Operation(summary = "인기 댓글 조회", description = "추천 수가 가장 많은 댓글을 각 선택지별로 3개씩 조회한다.")
public List<CommentResponse> findBestComments(@PathVariable Long postId,
@RequestHeader(value = "Authorization", required = false) String token) {
return commentService.findBestComments(postId, token);
}

@ResponseStatus(HttpStatus.OK)
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/balancetalk/module/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,9 @@ public boolean hasLiked(Post post) {
return postLikes.stream()
.anyMatch(like -> like.getPost().equals(post));
}

public boolean hasLikedComment(Comment comment) {
return commentLikes.stream()
.anyMatch(like -> like.getComment().equals(comment));
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package balancetalk.module.member.domain;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
import org.springframework.data.jpa.repository.Query;

public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByEmail(String username);
boolean existsByNickname(String nickname);
boolean existsByEmail(String email);
void deleteByEmail(String email);

@Query("select m.id from Member m JOIN m.votes v WHERE v.balanceOption.id = :balanceOptionId")
List<Long> findMemberIdsBySelectedOptionId(Long balanceOptionId);
}