From 8412aeb3b2fefe9193fc6309716f22e0da6da7d1 Mon Sep 17 00:00:00 2001 From: Hong0329 Date: Mon, 18 Nov 2024 02:22:29 +0900 Subject: [PATCH 1/3] feat : get comment by member with blind --- .../comment/controller/CommentController.java | 7 ++++ .../CommentAllByMemberResponseDtoVer3.java | 42 +++++++++++++++++++ .../comment/service/CommentQueryService.java | 29 ++++++++++--- 3 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllByMemberResponseDtoVer3.java diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java index acc3c17..c7f9999 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java @@ -115,4 +115,11 @@ public ResponseEntity> postCommentWithParentChildComment(Pri commentCommendService.postCommentWithParentChildComment(MemberUtil.getMemberId(principal),contentId, commentPostRequestDtoVer2); return ApiResponse.success(POST_COMMENT_SUCCESS); } + + @Operation(summary = "멤버에 해당하는 답글 리스트 조회 API(+블라인드) 입니다.", description = "Comments By Member With Blind") + @GetMapping("v3/member/{memberId}/comments") + public ResponseEntity> getCommentAllByMemberWithBlind(Principal principal, @PathVariable Long memberId, @RequestParam(value = "cursor") Long cursor){ + Long usingMemberId = MemberUtil.getMemberId(principal); + return ApiResponse.success(GET_MEMBER_COMMENT_SECCESS, commentQueryService.getCommentAllByMemberWithBlind(usingMemberId,memberId,cursor)); + } } \ No newline at end of file diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllByMemberResponseDtoVer3.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllByMemberResponseDtoVer3.java new file mode 100644 index 0000000..fd04fad --- /dev/null +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllByMemberResponseDtoVer3.java @@ -0,0 +1,42 @@ +package com.wable.www.WableServer.api.comment.dto.response; + +import com.wable.www.WableServer.api.comment.domain.Comment; +import com.wable.www.WableServer.api.member.domain.Member; +import com.wable.www.WableServer.common.util.TimeUtilCustom; + +public record CommentAllByMemberResponseDtoVer3( + long memberId, // 답글 작성자 Id + String memberProfileUrl, // 작성자 프로필 사진url + String memberNickname, // 답글 작성자 닉네임 + Boolean isLiked, // 유저가 답글에 대해 좋아요를 눌렀는지 + Boolean isGhost, //답글 작성자를 투명도 처리 했는지 + int memberGhost, // 답글 작성자의 전체 투명도 + int commentLikedNumber, // 답글 좋아요 개수 + String commentText, // 답글 내용 + String time, //답글이 작성된 시간 (년-월-일 시:분:초) + long commentId, //댓글 Id + long contentId , // 해당 댓글이 적힌 게시물 Id + String commentImageUrl, + String memberFanTeam, + Boolean isBlind +) { + public static CommentAllByMemberResponseDtoVer3 of(Member writerMember, boolean isLiked, boolean isGhost, + int memberGhost, int commentLikedNumber, Comment comment){ + return new CommentAllByMemberResponseDtoVer3( + writerMember.getId() , + writerMember.getProfileUrl(), + writerMember.getNickname(), + isLiked, + isGhost, + memberGhost, + commentLikedNumber, + comment.getCommentText(), + TimeUtilCustom.refineTime(comment.getCreatedAt()), + comment.getId(), + comment.getContent().getId(), + comment.getCommentImage(), + writerMember.getMemberFanTeam(), + comment.isBlind() + ); + } +} diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java index eb6d0f7..db87b46 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java @@ -1,11 +1,7 @@ package com.wable.www.WableServer.api.comment.service; import com.wable.www.WableServer.api.comment.domain.Comment; -import com.wable.www.WableServer.api.comment.dto.response.CommentAllByMemberResponseDto; -import com.wable.www.WableServer.api.comment.dto.response.CommentAllByMemberResponseDtoVer2; -import com.wable.www.WableServer.api.comment.dto.response.CommentAllResponseDto; -import com.wable.www.WableServer.api.comment.dto.response.CommentAllResponseDtoVer2; -import com.wable.www.WableServer.api.comment.dto.response.CommentAllResponseDtoVer3; +import com.wable.www.WableServer.api.comment.dto.response.*; import com.wable.www.WableServer.api.comment.repository.CommentLikedRepository; import com.wable.www.WableServer.api.comment.repository.CommentRepository; import com.wable.www.WableServer.api.content.repository.ContentRepository; @@ -154,6 +150,29 @@ public List getCommentAllByMemberWithImage(Lo ).collect(Collectors.toList()); } + public List getCommentAllByMemberWithBlind(Long principalId, Long memberId, Long cursor) { + memberRepository.findMemberByIdOrThrow(memberId); + + PageRequest pageRequest = PageRequest.of(0, 10); + Slice commentList; + + if (cursor==-1) { + commentList = commentRepository.findCommentsTop15ByMemberIdOrderByCreatedAtDesc(memberId, pageRequest); + } else { + commentList = commentRepository.findCommentsByMemberNextPage(cursor, memberId, pageRequest); + } + + return commentList.stream() + .map(oneComment -> CommentAllByMemberResponseDtoVer3.of( + memberRepository.findMemberByIdOrThrow(memberId), + checkLikedComment(principalId, oneComment.getId()), + checkGhost(principalId, oneComment.getId()), + checkMemberGhost(oneComment.getId()), + likedNumber(oneComment.getId()), + oneComment) + ).collect(Collectors.toList()); + } + private boolean checkGhost(Long usingMemberId, Long commentId) { Member writerMember = commentRepository.findCommentByIdOrThrow(commentId).getMember(); return ghostRepository.existsByGhostTargetMemberIdAndGhostTriggerMemberId(writerMember.getId(), usingMemberId); From 9fb6c95118c08841f51d667074f563314ed9a9af Mon Sep 17 00:00:00 2001 From: Hong0329 Date: Mon, 18 Nov 2024 03:47:08 +0900 Subject: [PATCH 2/3] feat : get comment with hierarchy --- .../comment/controller/CommentController.java | 7 +++ .../response/CommentAllResponseDtoVer4.java | 50 ++++++++++++++++++ .../comment/repository/CommentRepository.java | 16 ++++++ .../comment/service/CommentQueryService.java | 51 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllResponseDtoVer4.java diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java index c7f9999..e799206 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/controller/CommentController.java @@ -122,4 +122,11 @@ public ResponseEntity> getCommentAllByMemberWithBlind(Princi Long usingMemberId = MemberUtil.getMemberId(principal); return ApiResponse.success(GET_MEMBER_COMMENT_SECCESS, commentQueryService.getCommentAllByMemberWithBlind(usingMemberId,memberId,cursor)); } + + @Operation(summary = "게시물에 해당하는 답글 리스트 조회 API(대댓글) 입니다.", description = "Comments By Content With hierarchy") + @GetMapping("v3/content/{contentId}/comments") + public ResponseEntity> getCommentAllWithHierarchy(Principal principal, @PathVariable Long contentId, @RequestParam(value = "cursor") Long cursor){ + Long memberId = MemberUtil.getMemberId(principal); + return ApiResponse.success(GET_COMMENT_ALL_SUCCESS, commentQueryService.getCommentsWithHierarchy(memberId, contentId, cursor)); + } } \ No newline at end of file diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllResponseDtoVer4.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllResponseDtoVer4.java new file mode 100644 index 0000000..3ae0f7e --- /dev/null +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/dto/response/CommentAllResponseDtoVer4.java @@ -0,0 +1,50 @@ +package com.wable.www.WableServer.api.comment.dto.response; + +import com.wable.www.WableServer.api.member.domain.Member; + +import java.util.List; + +public record CommentAllResponseDtoVer4( + Long commentId, //답글 고유 id + Long memberId, // 댓글 작성자 Id + String memberProfileUrl, //작성자 프로필 사진url + String memberNickname, //댓글 작성자 닉네임 + Boolean isGhost, //현재 유저가 작성자에 대해 투명도 처리를 했는지 + int memberGhost, //작성자의 전체 투명도 + Boolean isLiked, //유저가 게시물에 대해 좋아요를 눌렀는지 + int commentLikedNumber, //댓글의 좋아요 개수 + String commentText, //댓글 내용 + String time, //답글이 작성된 시간을 (년-월-일 시:분:초) + Boolean isDeleted, // 댓글 작성자가 탈퇴한 회원인지 아닌지 + String commentImageUrl, + String memberFanTeam, + Long parentCommentId, + Boolean isBlind, + List childComments // 대댓글 리스트 추가 + +) { + public static CommentAllResponseDtoVer4 of( + Long commentId, Member writerMember, boolean isGhost, int memberGhost, + boolean isLiked, String time, int likedNumber, String commentText, + String commentImageUrl,Long parentCommentId, Boolean isBlind, List childComments + ) { + return new CommentAllResponseDtoVer4( + commentId, + writerMember.getId(), + writerMember.getProfileUrl(), + writerMember.getNickname(), + isGhost, + memberGhost, + isLiked, + likedNumber, + commentText, + time, + writerMember.isDeleted(), + commentImageUrl, + writerMember.getMemberFanTeam(), + parentCommentId, + isBlind, + childComments + ); + } +} diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/repository/CommentRepository.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/repository/CommentRepository.java index b3c6c7b..eb5b753 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/repository/CommentRepository.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/repository/CommentRepository.java @@ -46,6 +46,22 @@ default Comment findCommentByIdOrThrow(Long commentId) { List findAllByMember(Member member); + @Query(""" + SELECT c + FROM Comment c + WHERE c.parentCommentId = -1 AND c.content.id = :contentId AND (:cursor = -1 OR c.id > :cursor) + ORDER BY c.createdAt ASC + """) + Slice findParentCommentsWithPaginationAfterCursor(Long cursor, Long contentId, PageRequest pageRequest); + + @Query(""" + SELECT c + FROM Comment c + WHERE c.parentCommentId = :parentId + ORDER BY c.createdAt ASC + """) + List findChildComments(Long parentId); + @Transactional @Modifying @Query("DELETE FROM Comment c WHERE c.isDeleted = true AND c.deleteAt < :currentDate") diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java index db87b46..d330ca8 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentQueryService.java @@ -15,6 +15,8 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -173,6 +175,55 @@ public List getCommentAllByMemberWithBlind(Lo ).collect(Collectors.toList()); } + public List getCommentsWithHierarchy(Long memberId, Long contentId, Long cursor) { + PageRequest pageRequest = PageRequest.of(0, COMMENT_DEFAULT_PAGE_SIZE); + Slice parentComments = commentRepository.findParentCommentsWithPaginationAfterCursor(cursor, contentId, pageRequest); + + // 결과 리스트 초기화 + List result = new ArrayList<>(); + + for (Comment parent : parentComments) { + // 대댓글 조회 및 변환 + List childComments = commentRepository.findChildComments(parent.getId()); + + List childDtos = childComments.stream() + .map(child -> CommentAllResponseDtoVer4.of( + child.getId(), + memberRepository.findMemberByIdOrThrow(child.getMember().getId()), + checkGhost(memberId, child.getId()), + checkMemberGhost(child.getId()), + checkLikedComment(memberId, child.getId()), + TimeUtilCustom.refineTime(child.getCreatedAt()), + likedNumber(child.getId()), + child.getCommentText(), + child.getCommentImage(), + child.getParentCommentId(), + child.isBlind(), + null // 대댓글의 대댓글은 없으므로 null로 설정 + )) + .collect(Collectors.toList()); + + // 부모 댓글 DTO 변환 (대댓글 포함) + CommentAllResponseDtoVer4 parentDto = CommentAllResponseDtoVer4.of( + parent.getId(), + memberRepository.findMemberByIdOrThrow(parent.getMember().getId()), + checkGhost(memberId, parent.getId()), + checkMemberGhost(parent.getId()), + checkLikedComment(memberId, parent.getId()), + TimeUtilCustom.refineTime(parent.getCreatedAt()), + likedNumber(parent.getId()), + parent.getCommentText(), + parent.getCommentImage(), + parent.getParentCommentId(), + parent.isBlind(), + childDtos // 대댓글 추가 + ); + + result.add(parentDto); + } + return result; + } + private boolean checkGhost(Long usingMemberId, Long commentId) { Member writerMember = commentRepository.findCommentByIdOrThrow(commentId).getMember(); return ghostRepository.existsByGhostTargetMemberIdAndGhostTriggerMemberId(writerMember.getId(), usingMemberId); From d38ed905d2718e846c24e66718b57c6b41a75642 Mon Sep 17 00:00:00 2001 From: Hong0329 Date: Mon, 18 Nov 2024 03:59:45 +0900 Subject: [PATCH 3/3] feat : delete comment with hierarchy --- .../service/CommentCommendService.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentCommendService.java b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentCommendService.java index 407e429..f49c9ed 100644 --- a/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentCommendService.java +++ b/WableServer/src/main/java/com/wable/www/WableServer/api/comment/service/CommentCommendService.java @@ -20,6 +20,8 @@ import com.wable.www.WableServer.external.fcm.service.FcmService; import com.wable.www.WableServer.external.s3.service.S3Service; import java.io.IOException; +import java.util.List; + import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -163,11 +165,27 @@ public void postCommentVer2(Long memberId, Long contentId, MultipartFile comment public void deleteComment(Long memberId, Long commentId) { deleteValidate(memberId, commentId); - notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentLiked",commentId); - notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("comment",commentId); - notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentGhost", commentId); - Comment deleteComment = commentRepository.findCommentByIdOrThrow(commentId); + if(deleteComment.getParentCommentId().equals(-1L)) { + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentLiked", commentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("comment", commentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentGhost", commentId); + + List childComment = commentRepository.findChildComments(commentId); + + for (Comment comment : childComment) { + Long childCommentId = comment.getId(); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("childCommentLiked", childCommentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("childComment", childCommentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentGhost", childCommentId); + comment.softDelete(); + } + } else { + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("childCommentLiked", commentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("childComment", commentId); + notificationRepository.deleteByNotificationTriggerTypeAndNotificationTriggerId("commentGhost", commentId); + } + deleteComment.softDelete(); }