Skip to content

Commit 635a7e6

Browse files
authored
fix(notify): 대댓글 알림 비밀 처리 및 차단 관계 수신자 오류 수정 (#170)
비밀 대댓글 내용이 열람 권한 없는 참여자에게 알림으로 노출되는 문제를 해결하기 위해 SubCommentCreatedEvent에 isSecret, parentSecret 필드 추가 후 CommentNotificationEventListener에서 부모 댓글 작성자 알림에 차단 관계 체크 추가, isSecret && !parentSecret이면 skip, 리포트 당사자가 참여자인 경우는 별도 발송
1 parent 49607e4 commit 635a7e6

3 files changed

Lines changed: 56 additions & 16 deletions

File tree

src/main/java/com/devkor/ifive/nadab/domain/comment/application/CommentCommandService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ public Long createSubComment(Long parentCommentId, Long authorId, String content
8787
parentCommentId,
8888
parentComment.getAuthor().getId(),
8989
reportOwnerId,
90-
content
90+
content,
91+
finalIsSecret,
92+
parentComment.isSecret()
9193
));
9294

9395
return subComment.getId();

src/main/java/com/devkor/ifive/nadab/domain/comment/application/event/SubCommentCreatedEvent.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public class SubCommentCreatedEvent {
1414
private final Long parentCommentAuthorId;
1515
private final Long reportOwnerId;
1616
private final String content;
17+
private final boolean secret;
18+
private final boolean parentSecret;
1719
}

src/main/java/com/devkor/ifive/nadab/domain/notification/application/event/social/CommentNotificationEventListener.java

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.devkor.ifive.nadab.domain.comment.application.event.CommentCreatedEvent;
44
import com.devkor.ifive.nadab.domain.comment.application.event.SubCommentCreatedEvent;
55
import com.devkor.ifive.nadab.domain.comment.core.repository.CommentRepository;
6+
import com.devkor.ifive.nadab.domain.moderation.core.repository.UserBlockRepository;
67
import com.devkor.ifive.nadab.domain.notification.application.NotificationCommandService;
78
import com.devkor.ifive.nadab.domain.notification.core.entity.NotificationType;
89
import com.devkor.ifive.nadab.domain.user.core.entity.User;
@@ -17,6 +18,7 @@
1718

1819
import java.util.List;
1920
import java.util.Map;
21+
import java.util.Set;
2022

2123
@Component
2224
@RequiredArgsConstructor
@@ -25,6 +27,7 @@ public class CommentNotificationEventListener {
2527

2628
private final UserRepository userRepository;
2729
private final CommentRepository commentRepository;
30+
private final UserBlockRepository userBlockRepository;
2831
private final NotificationMessageFactory messageFactory;
2932
private final NotificationCommandService notificationCommandService;
3033

@@ -87,8 +90,12 @@ public void handleSubCommentCreated(SubCommentCreatedEvent event) {
8790
"commentContent", truncate(event.getContent())
8891
);
8992

90-
// 1. 부모 댓글 작성자 알림 (author 제외, 역할 무관 최우선)
91-
if (!event.getAuthorId().equals(event.getParentCommentAuthorId())) {
93+
Set<Long> blockedByAuthor = Set.copyOf(
94+
userBlockRepository.findBlockedUserIdsBidirectional(event.getAuthorId()));
95+
96+
// 1. 부모 댓글 작성자 알림 (author 제외, 역할 무관 최우선,차단 관계이면 skip)
97+
if (!event.getAuthorId().equals(event.getParentCommentAuthorId())
98+
&& !blockedByAuthor.contains(event.getParentCommentAuthorId())) {
9299
User parentCommentAuthor = userRepository.findById(event.getParentCommentAuthorId()).orElse(null);
93100
if (parentCommentAuthor == null || parentCommentAuthor.getDeletedAt() != null) {
94101
log.debug("Parent comment author not found or deleted, skip notification: parentCommentAuthorId={}", event.getParentCommentAuthorId());
@@ -141,20 +148,49 @@ public void handleSubCommentCreated(SubCommentCreatedEvent event) {
141148
}
142149
}
143150

144-
NotificationContent participantContent = messageFactory.createMessage(
145-
NotificationType.REPLY_ON_PARTICIPATED_COMMENT, params);
146-
for (Long participantId : participantIds) {
147-
notificationCommandService.sendNotification(
148-
participantId,
149-
NotificationType.REPLY_ON_PARTICIPATED_COMMENT,
150-
participantContent.title(),
151-
participantContent.body(),
152-
participantContent.inboxMessage(),
153-
event.getDailyReportId().toString(),
154-
String.format("COMMENT_%d_PARTICIPANT_%d", event.getSubCommentId(), participantId)
155-
);
151+
// 4. 참여자 알림
152+
if (!participantIds.isEmpty()) {
153+
if (!event.isSecret() || event.isParentSecret()) {
154+
// 공개 대댓글 or 비밀 부모 아래 대댓글: 참여자들 열람 가능 — 차단 관계 제외
155+
List<Long> notifiableParticipantIds = participantIds.stream()
156+
.filter(id -> !blockedByAuthor.contains(id))
157+
.toList();
158+
if (!notifiableParticipantIds.isEmpty()) {
159+
NotificationContent participantContent = messageFactory.createMessage(
160+
NotificationType.REPLY_ON_PARTICIPATED_COMMENT, params);
161+
for (Long participantId : notifiableParticipantIds) {
162+
notificationCommandService.sendNotification(
163+
participantId,
164+
NotificationType.REPLY_ON_PARTICIPATED_COMMENT,
165+
participantContent.title(),
166+
participantContent.body(),
167+
participantContent.inboxMessage(),
168+
event.getDailyReportId().toString(),
169+
String.format("COMMENT_%d_PARTICIPANT_%d", event.getSubCommentId(), participantId)
170+
);
171+
}
172+
log.debug("Sub-comment notifications sent: subCommentId={}, participantCount={}", event.getSubCommentId(), notifiableParticipantIds.size());
173+
}
174+
} else if (reportOwnerIsParticipant && !reportOwnerIsAuthor
175+
&& !blockedByAuthor.contains(event.getReportOwnerId())) {
176+
// 공개 부모 댓글에 달린 비밀 대댓글 : 일반 참여자는 열람 불가하지만 리포트 당사자는 가능
177+
User reportOwner = userRepository.findById(event.getReportOwnerId()).orElse(null);
178+
if (reportOwner != null && reportOwner.getDeletedAt() == null) {
179+
NotificationContent participantContent = messageFactory.createMessage(
180+
NotificationType.REPLY_ON_PARTICIPATED_COMMENT, params);
181+
notificationCommandService.sendNotification(
182+
event.getReportOwnerId(),
183+
NotificationType.REPLY_ON_PARTICIPATED_COMMENT,
184+
participantContent.title(),
185+
participantContent.body(),
186+
participantContent.inboxMessage(),
187+
event.getDailyReportId().toString(),
188+
String.format("COMMENT_%d_PARTICIPANT_%d", event.getSubCommentId(), event.getReportOwnerId())
189+
);
190+
log.debug("Sub-comment notification sent to report owner (participant): subCommentId={}", event.getSubCommentId());
191+
}
192+
}
156193
}
157-
log.debug("Sub-comment notifications sent: subCommentId={}, participantCount={}", event.getSubCommentId(), participantIds.size());
158194
} catch (Exception e) {
159195
log.error("Failed to handle SubCommentCreatedEvent: subCommentId={}, error={}",
160196
event.getSubCommentId(), e.getMessage(), e);

0 commit comments

Comments
 (0)