Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -6,6 +6,8 @@
import com.chooz.comment.presentation.dto.CommentRequest;
import com.chooz.comment.support.CommentValidator;
import com.chooz.commentLike.application.CommentLikeCommandService;
import com.chooz.common.event.DeleteEvent;
import com.chooz.common.event.EventPublisher;
import com.chooz.common.exception.BadRequestException;
import com.chooz.common.exception.ErrorCode;
import com.chooz.post.domain.PostRepository;
Expand All @@ -26,6 +28,7 @@ public class CommentCommandService {
private final UserRepository userRepository;
private final CommentValidator commentValidator;
private final CommentLikeCommandService commentLikeCommandService;
private final EventPublisher eventPublisher;

public CommentIdResponse createComment(Long postId, CommentRequest commentRequest, Long userId) {
commentValidator.validateContentLength(commentRequest.content());
Expand All @@ -51,9 +54,10 @@ public CommentIdResponse updateComment(Long postId, Long commentId, CommentReque

public void deleteComment(Long postId, Long commentId, Long userId) {
commentLikeCommandService.deleteCommentLikeByCommentId(commentId);
Comment commentForDelete = commentRepository.findById(commentId)
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new BadRequestException(ErrorCode.COMMENT_NOT_FOUND));
commentValidator.validateCommentAccess(commentForDelete, postId, userId);
commentRepository.delete(commentForDelete);
commentValidator.validateCommentAccess(comment, postId, userId);
commentRepository.delete(comment);
eventPublisher.publish(DeleteEvent.of(comment.getId(), comment.getClass().getSimpleName().toUpperCase()));
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/chooz/common/event/DeleteEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.chooz.common.event;

public record DeleteEvent(Long id, String domain) {
public static DeleteEvent of(Long id, String domain) {
return new DeleteEvent(id, domain);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.chooz.notification.application.service.NotificationCommandService;
import com.chooz.notification.application.service.NotificationQueryService;
import com.chooz.notification.domain.Notification;
import com.chooz.notification.domain.TargetType;
import com.chooz.notification.presentation.dto.NotificationPresentResponse;
import com.chooz.notification.presentation.dto.NotificationResponse;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -53,4 +54,7 @@ public void markRead(Long notificationId) {
public NotificationPresentResponse present(Long userId) {
return notificationQueryService.present(userId);
}
public List<Notification> findByTargetIdAndType(Long id, TargetType targetType){
return notificationQueryService.findByTargetIdAndType(id, targetType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.chooz.notification.application.listener;

import com.chooz.common.event.DeleteEvent;
import com.chooz.notification.application.NotificationService;
import com.chooz.notification.domain.Notification;
import com.chooz.notification.domain.TargetType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

@Component
@RequiredArgsConstructor
public class NotificationInvalidListener {

private final NotificationService notificationService;

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void inValid(DeleteEvent deleteEvent) {
notificationService.findByTargetIdAndType(deleteEvent.id(), TargetType.valueOf(deleteEvent.domain()))
.forEach(Notification::invalidate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import com.chooz.notification.application.dto.TargetPostDto;
import com.chooz.notification.application.dto.TargetUserDto;
import com.chooz.notification.application.web.dto.NotificationDto;
import com.chooz.notification.domain.Notification;
import com.chooz.notification.domain.NotificationQueryRepository;
import com.chooz.notification.domain.NotificationRepository;
import com.chooz.notification.domain.TargetType;
import com.chooz.notification.presentation.dto.NotificationPresentResponse;
import com.chooz.notification.presentation.dto.NotificationResponse;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -56,5 +58,7 @@ public List<TargetUserDto> findVoteUsersByPostId(Long postId) {
public NotificationPresentResponse present(Long userId) {
return NotificationPresentResponse.of(notificationRepository.existsByReceiverIdAndIsReadFalseAndDeletedFalse(userId));
}

public List<Notification> findByTargetIdAndType(Long id, TargetType targetType) {
return notificationRepository.findByTargetIdAndType(id, targetType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public interface NotificationRepository {
void saveAll(List<Notification> notifications);
Optional<Notification> findNotificationById(Long id);
boolean existsByReceiverIdAndIsReadFalseAndDeletedFalse(Long userId);
List<Notification> findByTargetIdAndType(Long targetId, TargetType targetType);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package com.chooz.notification.persistence;

import com.chooz.notification.domain.Notification;
import com.chooz.notification.domain.TargetType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface NotificationJpaRepository extends JpaRepository<Notification, Long> {
boolean existsByReceiverIdAndIsReadFalseAndDeletedFalse(Long userId);
@Query("""
SELECT distinct n
FROM Notification n
join n.targets t
where t.id = :targetId
and t.type = :targetType
and n.isValid = true
order by n.id desc
"""
)
List<Notification> findByTargetIdAndType(@Param("targetId") Long targetId, @Param("targetType") TargetType targetType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.chooz.notification.domain.Notification;
import com.chooz.notification.domain.NotificationRepository;
import com.chooz.notification.domain.TargetType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

Expand Down Expand Up @@ -35,4 +36,8 @@ public boolean existsByReceiverIdAndIsReadFalseAndDeletedFalse(Long userId) {
return notificationJpaRepository.existsByReceiverIdAndIsReadFalseAndDeletedFalse(userId);
}

@Override
public List<Notification> findByTargetIdAndType(Long targetId, TargetType targetType) {
return notificationJpaRepository.findByTargetIdAndType(targetId, targetType);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.chooz.post.application;

import com.chooz.common.event.DeleteEvent;
import com.chooz.common.event.EventPublisher;
import com.chooz.common.exception.BadRequestException;
import com.chooz.common.exception.ErrorCode;
Expand Down Expand Up @@ -84,6 +85,7 @@ public void delete(Long userId, Long postId) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new BadRequestException(ErrorCode.POST_NOT_FOUND));
post.delete(userId);
eventPublisher.publish(DeleteEvent.of(post.getId(), post.getClass().getSimpleName().toUpperCase()));
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.chooz.notification.domain.TargetType;
import com.chooz.post.domain.PollChoiceRepository;
import com.chooz.post.domain.Post;
import com.chooz.post.domain.PostRepository;
import com.chooz.post.persistence.PostJpaRepository;
import com.chooz.support.IntegrationTest;
import com.chooz.support.fixture.CommentFixture;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.chooz.post.domain.CloseType;
import com.chooz.post.domain.PollChoiceRepository;
import com.chooz.post.domain.Post;
import com.chooz.post.domain.PostRepository;
import com.chooz.post.persistence.PostJpaRepository;
import com.chooz.support.IntegrationTest;
import com.chooz.support.fixture.PostFixture;
Expand All @@ -19,7 +18,6 @@
import com.chooz.user.domain.User;
import com.chooz.user.domain.UserRepository;
import com.chooz.vote.application.VotedEvent;
import com.chooz.vote.domain.VoteRepository;
import com.chooz.vote.persistence.VoteJpaRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.chooz.notification.application;

import com.chooz.comment.application.CommentService;
import com.chooz.comment.domain.Comment;
import com.chooz.comment.domain.CommentRepository;
import com.chooz.commentLike.application.CommentLikeService;
import com.chooz.notification.application.web.dto.NotificationDto;
import com.chooz.notification.domain.NotificationQueryRepository;
import com.chooz.post.application.PostCommandService;
import com.chooz.post.domain.PollChoiceRepository;
import com.chooz.post.domain.Post;
import com.chooz.post.persistence.PostJpaRepository;
import com.chooz.support.IntegrationTest;
import com.chooz.support.fixture.CommentFixture;
import com.chooz.support.fixture.PostFixture;
import com.chooz.support.fixture.UserFixture;
import com.chooz.support.fixture.VoteFixture;
import com.chooz.user.domain.User;
import com.chooz.user.domain.UserRepository;
import com.chooz.vote.persistence.VoteJpaRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.transaction.TestTransaction;

import java.util.ArrayList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

class NotificationInvalidListenerTest extends IntegrationTest {

@Autowired
UserRepository userRepository;

@Autowired
PostJpaRepository postRepository;

@Autowired
VoteJpaRepository voteRepository;

@Autowired
PollChoiceRepository pollChoiceRepository;

@Autowired
CommentRepository commentRepository;

@Autowired
NotificationQueryRepository notificationQueryRepository;

@Autowired
CommentLikeService commentLikeService;

@Autowired
CommentService commentService;

@Autowired
PostCommandService postCommandService;

@AfterEach
void tearDown() {
voteRepository.deleteAllInBatch();
pollChoiceRepository.deleteAllInBatch();
postRepository.deleteAllInBatch();
userRepository.deleteAllInBatch();
}

private void commit(Runnable work) {
if(!TestTransaction.isActive()){
TestTransaction.start();
}
work.run();
TestTransaction.flagForCommit();
TestTransaction.end();
}

@Test
@DisplayName("댓글좋아요 원 댓글 삭제 시 알림 Invalid 처리")
void InvalidNotificationByDeleteComment() throws Exception {
//given
User receiver = userRepository.save(UserFixture.createDefaultUser());
User actor = userRepository.save(UserFixture.createDefaultUser());
Post post = postRepository.save(PostFixture.createPostBuilder().userId(receiver.getId()).build());
Comment comment = commentRepository.save(CommentFixture.createCommentBuilder()
.postId(post.getId())
.userId(receiver.getId())
.build());
commit(() -> commentLikeService.createCommentLike(comment.getId(), actor.getId()));

//when
commit(() -> commentService.deleteComment(post.getId(), comment.getId(), receiver.getId()));

//then
List<NotificationDto> notifications = notificationQueryRepository.findNotifications(
receiver.getId(),
null,
PageRequest.ofSize(10)
).getContent();
assertAll(
() -> assertThat(notifications.size()).isZero()
);
}
@Test
@DisplayName("원 게시물 삭제 시 알림 Invalid 처리")
void InvalidNotificationByDeletePost() throws Exception {
// given
User user = userRepository.save(UserFixture.createDefaultUser());
Post post = postRepository.save(PostFixture.createDefaultPost(user.getId()));

// when
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User voteUser = userRepository.save(UserFixture.createDefaultUser());
users.add(voteUser);
voteRepository.save(VoteFixture.createDefaultVote(voteUser.getId(), post.getId(), post.getPollChoices().get(0).getId()));
}
commit(() -> postCommandService.close(user.getId(), post.getId()));

//when
commit(() -> postCommandService.delete(user.getId(), post.getId()));

//then
List<NotificationDto> notifications = notificationQueryRepository.findNotifications(
users.get(0).getId(),
null,
PageRequest.ofSize(10)
).getContent();

assertAll(
() -> assertThat(notifications.size()).isZero()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.chooz.post.domain.CloseType;
import com.chooz.post.domain.PollChoiceRepository;
import com.chooz.post.domain.Post;
import com.chooz.post.domain.PostRepository;
import com.chooz.post.persistence.PostJpaRepository;
import com.chooz.support.IntegrationTest;
import com.chooz.support.fixture.PostFixture;
Expand All @@ -18,7 +17,6 @@
import com.chooz.user.domain.User;
import com.chooz.user.domain.UserRepository;
import com.chooz.vote.application.VotedEvent;
import com.chooz.vote.domain.VoteRepository;
import com.chooz.vote.persistence.VoteJpaRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.chooz.post.domain.PollChoice;
import com.chooz.post.domain.PollChoiceRepository;
import com.chooz.post.domain.Post;
import com.chooz.post.domain.PostRepository;
import com.chooz.post.persistence.PostJpaRepository;
import com.chooz.support.IntegrationTest;
import com.chooz.support.fixture.PostFixture;
Expand Down