5
5
import nova .mjs .comment .DTO .CommentResponseDto ;
6
6
import nova .mjs .comment .entity .Comment ;
7
7
import nova .mjs .comment .exception .CommentNotFoundException ;
8
+ import nova .mjs .comment .exception .CommentReplyDepthException ;
8
9
import nova .mjs .comment .likes .repository .CommentLikeRepository ;
9
10
import nova .mjs .comment .repository .CommentRepository ;
10
11
import nova .mjs .community .entity .CommunityBoard ;
16
17
import nova .mjs .community .exception .CommunityNotFoundException ;
17
18
import nova .mjs .member .exception .MemberNotFoundException ;
18
19
20
+ import java .util .HashSet ;
19
21
import java .util .List ;
20
22
import java .util .Set ;
21
23
import java .util .UUID ;
@@ -33,52 +35,42 @@ public class CommentService {
33
35
private final CommentLikeRepository commentLikeRepository ;
34
36
35
37
36
-
37
38
// 1. GEt 댓글 목록 (게시글 ID 기반, 페이지네이션 제거)
38
39
public List <CommentResponseDto .CommentSummaryDto > getCommentsByBoard (UUID communityBoardUuid , String email ) {
39
40
// 1) 게시글 존재 여부 확인
40
41
CommunityBoard board = getExistingBoard (communityBoardUuid );
41
- // 2) 댓글 목록 조회
42
- List <Comment > comments = commentRepository .findByCommunityBoard (board );
43
42
44
- // 댓글이 없다면 바로 빈 리스트 리턴
45
- if (comments .isEmpty ()) {
43
+ // 2) 전체 댓글 목록 조회
44
+ List <Comment > allComments = commentRepository .findByCommunityBoard (board );
45
+ if (allComments .isEmpty ()) {
46
46
return List .of ();
47
47
}
48
48
49
- // 3) 비로그인 사용자면 -> isLiked = false로
50
- if (email == null ) {
51
- return comments .stream ()
52
- .map (c -> CommentResponseDto .CommentSummaryDto .fromEntity (c , false ))
53
- .toList ();
54
- }
55
-
56
- // 4) 로그인된 사용자 조회
57
- Member member = memberRepository .findByEmail (email )
58
- .orElse (null );
59
- // 만약 email이 있는데 회원 정보가 없으면 -> isLiked = false
60
- if (member == null ) {
61
- return comments .stream ()
62
- .map (c -> CommentResponseDto .CommentSummaryDto .fromEntity (c , false ))
63
- .toList ();
64
- }
65
-
66
- // 5) 댓글 UUID 목록 추출
67
- List <UUID > commentUuids = comments .stream ()
68
- .map (Comment ::getUuid )
49
+ // 3) 최상위 댓글(부모가 null)만 필터링
50
+ List <Comment > topLevelComments = allComments .stream ()
51
+ .filter (c -> c .getParent () == null )
69
52
.toList ();
70
53
71
- // 6) 사용자가 좋아요한 댓글의 UUID들을 가져오기
72
- List <UUID > likedUuids = commentLikeRepository .findCommentUuidsLikedByMember (member , commentUuids );
73
-
74
- // 7) 조회된 UUID를 Set으로 변환(contains()용)
75
- Set <UUID > likedSet = new java .util .HashSet <>(likedUuids );
54
+ // 4) 비로그인 사용자면 -> isLiked = false (likedSet=null)
55
+ Set <UUID > likedSet = null ;
56
+ if (email != null ) {
57
+ Member member = memberRepository .findByEmail (email ).orElse (null );
58
+ if (member != null ) {
59
+ List <UUID > allUuids = allComments .stream ()
60
+ .map (Comment ::getUuid )
61
+ .toList ();
62
+ List <UUID > likedUuids = commentLikeRepository .findCommentUuidsLikedByMember (member , allUuids );
63
+ likedSet = new HashSet <>(likedUuids );
64
+ }
65
+ }
66
+ // ★ 여기가 핵심
67
+ final Set <UUID > finalLikedSet = likedSet ;
76
68
77
- // 8) 각 댓글마다 isLiked 여부 매핑
78
- return comments .stream ()
69
+ // 5) 부모 + 자식(대댓글)까지 트리 구조로 DTO 변환
70
+ return topLevelComments .stream ()
79
71
.map (comment -> {
80
- boolean isLiked = likedSet .contains (comment .getUuid ());
81
- return CommentResponseDto .CommentSummaryDto .fromEntity (comment , isLiked );
72
+ boolean isLiked = ( finalLikedSet != null && finalLikedSet .contains (comment .getUuid () ));
73
+ return CommentResponseDto .CommentSummaryDto .fromEntityWithReplies (comment , isLiked , finalLikedSet );
82
74
})
83
75
.toList ();
84
76
}
@@ -96,7 +88,7 @@ public CommentResponseDto.CommentSummaryDto createComment(UUID communityBoardUui
96
88
Comment savedComment = commentRepository .save (comment );
97
89
98
90
log .debug ("댓글 작성 성공. UUID = {}, 작성자 : {}" , savedComment .getUuid (), email );
99
- return CommentResponseDto .CommentSummaryDto .fromEntity (savedComment , false );
91
+ return CommentResponseDto .CommentSummaryDto .fromEntity (savedComment );
100
92
}
101
93
102
94
// 3. DELETE 댓글 삭제, 로그인 연동 추가
@@ -124,6 +116,38 @@ private Member getExistingMember(UUID uuid) {
124
116
.orElseThrow (MemberNotFoundException ::new );
125
117
}
126
118
119
+ // 6. 대댓글 작성
120
+ @ Transactional
121
+ public CommentResponseDto .CommentSummaryDto createReply (UUID parentCommentUuid , String content , String email ) {
122
+ // 1) 부모 댓글 조회
123
+ Comment parentComment = commentRepository .findByUuid (parentCommentUuid )
124
+ .orElseThrow (CommentNotFoundException ::new );
125
+
126
+ // 2) parentComment가 이미 "자식 댓글"(= 대댓글)인지 확인
127
+ if (parentComment .getParent () != null ) {
128
+ // 로그 남기기
129
+ log .error ("[MJS] 대댓글 생성 실패: 이미 대댓글인 댓글에는 다시 대댓글을 달 수 없습니다. parentCommentUuid={}" , parentCommentUuid );
130
+
131
+ // 커스텀 예외 던지기
132
+ throw new CommentReplyDepthException ();
133
+ }
134
+
135
+
136
+ // 3) 작성자 조회
137
+ Member member = memberRepository .findByEmail (email )
138
+ .orElseThrow (MemberNotFoundException ::new );
139
+
140
+ // 4) 대댓글 생성
141
+ Comment reply = Comment .createReply (parentComment , member , content );
142
+
143
+ // 5) DB 저장
144
+ Comment savedReply = commentRepository .save (reply );
145
+
146
+ // 6) DTO 변환 (isLiked=false 초기값)
147
+ return CommentResponseDto .CommentSummaryDto .fromEntity (savedReply );
148
+ }
149
+
150
+
127
151
private Comment getExistingCommentByUuid (UUID commentUuid ) {
128
152
return commentRepository .findByUuid (commentUuid )
129
153
.orElseThrow (() -> {
0 commit comments