Skip to content

Commit

Permalink
Merge pull request #186 from team-offonoff/notification
Browse files Browse the repository at this point in the history
댓글 좋아요 알림 생성 && VoteResult 엔티티 삭제
  • Loading branch information
60jong authored Feb 29, 2024
2 parents 1d6bea3 + 496fc79 commit 85425bd
Show file tree
Hide file tree
Showing 25 changed files with 354 additions and 170 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package life.offonoff.ab.application.event.topic;

import life.offonoff.ab.domain.comment.Comment;
import life.offonoff.ab.domain.comment.LikedComment;
import life.offonoff.ab.domain.member.Member;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEvent;

@Getter
@RequiredArgsConstructor
public class CommentLikedEvent {

private final LikedComment likedComment;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import life.offonoff.ab.application.notification.NotificationService;
import life.offonoff.ab.application.service.vote.VotingTopicService;
import life.offonoff.ab.application.service.vote.votingtopic.container.VotingTopic;
import life.offonoff.ab.domain.comment.Comment;
import life.offonoff.ab.domain.comment.LikedComment;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.domain.topic.Topic;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -42,7 +45,7 @@ public void addTopic(TopicCreateEvent event) {
public void voteClosed(VoteClosedEvent event) {
log.info("# Topic Vote Closed / topic-id : {}, deadline : {}", event.topic().getId(), event.topic().getDeadline());

notificationService.notifyVoteResult(event.result());
notificationService.notifyVoteResult(event.topic());
}

/**
Expand All @@ -63,4 +66,16 @@ public void voted(VotedEvent event) {
public void commented(CommentedEvent event) {
notificationService.notifyCommentOnTopic(event.getComment());
}

/**
* 댓글 좋아요 이벤트
*/
@EventListener
public void commentLiked(CommentLikedEvent event) {
LikedComment likedComment = event.getLikedComment();

notificationService.notifyLikeInComment(likedComment);
}


}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package life.offonoff.ab.application.event.topic;

import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.vote.VoteResult;

public record VoteClosedEvent(
Topic topic,
VoteResult result
Topic topic
) {
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package life.offonoff.ab.application.notification;

import life.offonoff.ab.domain.comment.Comment;
import life.offonoff.ab.domain.comment.LikedComment;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.domain.notification.CommentOnTopicNotification;
import life.offonoff.ab.domain.notification.LikeInCommentNotification;
import life.offonoff.ab.domain.notification.VoteCountOnTopicNotification;
import life.offonoff.ab.domain.notification.VoteResultNotification;
import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.vote.VoteResult;
import life.offonoff.ab.repository.member.MemberRepository;
import life.offonoff.ab.repository.notfication.NotificationRepository;
import life.offonoff.ab.web.response.notification.NotificationResponse;
Expand All @@ -32,41 +33,56 @@ public class NotificationService {
private final NotificationRepository notificationRepository;

@Transactional
public void notifyVoteResult(VoteResult result) {
public void notifyVoteResult(Topic topic) {
// voters' notifications
List<Member> voters = memberRepository.findAllListeningVoteResultAndVotedTopicId(result.getTopicId());
List<VoteResultNotification> notifications = createVotersNotifications(result, voters);
List<Member> voters = memberRepository.findAllListeningVoteResultAndVotedTopicId(topic.getId());
List<VoteResultNotification> notifications = createVotersNotifications(topic, voters);

// author's notification
addAuthorsNotificationIfAuthorListeningVoteResult(result, notifications);
addAuthorsNotificationIfAuthorListeningVoteResult(topic, notifications);

notificationRepository.saveVoteResultNotificationsInBatch(notifications);
}

private List<VoteResultNotification> createVotersNotifications(VoteResult result, List<Member> voters) {
private List<VoteResultNotification> createVotersNotifications(Topic topic, List<Member> voters) {
return voters.stream()
.filter(Member::listenVoteResult)
.map(receiver -> {
log.info("# Notification send / Topic(id = {}, total_vote_count = {}) Member(id = {})",
result.getTopicId(), result.getTotalVoteCount(), receiver.getId());
return new VoteResultNotification(receiver, result);
topic.getId(), topic.getVoteCount(), receiver.getId());
return new VoteResultNotification(receiver, topic);
}
).collect(Collectors.toList());
}

private void addAuthorsNotificationIfAuthorListeningVoteResult(VoteResult result, List<VoteResultNotification> notifications) {
Member author = result.getTopic()
.getAuthor();
private void addAuthorsNotificationIfAuthorListeningVoteResult(Topic topic, List<VoteResultNotification> notifications) {
Member author = topic.getAuthor();

if (author.listenVoteResult()) {
VoteResultNotification authorsNotification = new VoteResultNotification(result.getTopic().getAuthor(), result);
VoteResultNotification authorsNotification = new VoteResultNotification(author, topic);
notifications.add(authorsNotification);
}
}

@Transactional
public void notifyLikeInComment() {
public void notifyLikeInComment(LikedComment likedComment) {
if (shouldNotifyLikeInComment(likedComment)) {
LikeInCommentNotification notification = new LikeInCommentNotification(likedComment.getComment());

notificationRepository.save(notification);
}
}

private boolean shouldNotifyLikeInComment(LikedComment likedComment) {
Member liker = likedComment.getLiker();

Comment comment = likedComment.getComment();
Member writer = comment.getWriter();

boolean likerIsWriter = comment.isWrittenBy(liker);
boolean writerListenLikeInComment = writer.listenLikeInComment();

return !likerIsWriter && writerListenLikeInComment;
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package life.offonoff.ab.application.service;

import life.offonoff.ab.application.event.topic.CommentLikedEvent;
import life.offonoff.ab.application.event.topic.CommentedEvent;
import life.offonoff.ab.application.service.common.TextUtils;
import life.offonoff.ab.application.service.request.CommentRequest;
import life.offonoff.ab.domain.comment.Comment;
import life.offonoff.ab.domain.comment.LikedComment;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.vote.Vote;
Expand All @@ -22,6 +24,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

import static life.offonoff.ab.application.service.common.LengthInfo.COMMENT_CONTENT;

@RequiredArgsConstructor
Expand Down Expand Up @@ -136,10 +140,21 @@ public CommentReactionResponse likeCommentForMember(final Long memberId, final L
private CommentReactionResponse doLike(Member liker, Comment comment) {

liker.cancelHateIfExists(comment);
liker.likeCommentIfNew(comment);
Optional<LikedComment> optionalLikedComment = liker.likeCommentIfNew(comment);

publishCommentLikedEventIfPresent(optionalLikedComment);

return new CommentReactionResponse(comment.getLikeCount(), comment.getHateCount(), true, false);
}

private void publishCommentLikedEventIfPresent(Optional<LikedComment> optional) {
if (optional.isPresent()) {
LikedComment likedComment = optional.get();

eventPublisher.publishEvent(new CommentLikedEvent(likedComment));
}
}

private CommentReactionResponse cancelLike(Member liker, Comment comment) {

liker.cancelLikeIfExists(comment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import life.offonoff.ab.application.service.vote.votingtopic.container.VotingTopic;
import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.topic.TopicStatus;
import life.offonoff.ab.domain.vote.VoteResult;
import life.offonoff.ab.repository.topic.TopicRepository;
import life.offonoff.ab.repository.topic.TopicSearchCond;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -40,10 +39,9 @@ public void endVote(VoteClosingCriteria criteria) {
ended.forEach(
topic -> {
topic.closeVote();
VoteResult result = aggregateVote(topic);

// 투표 종료 이벤트 발행
eventPublisher.publishEvent(new VoteClosedEvent(topic, result));
eventPublisher.publishEvent(new VoteClosedEvent(topic));
}
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@
import life.offonoff.ab.application.service.vote.criteria.VoteClosingCriteria;
import life.offonoff.ab.application.service.vote.votingtopic.container.VotingTopic;
import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.vote.VoteResult;

public interface VotingTopicService {

default VoteResult aggregateVote(Topic topic) {
VoteResult result = new VoteResult();
result.setTopic(topic);
return result;
}

void startVote(VotingTopic votingTopic);

void endVote(VoteClosingCriteria criteria);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import life.offonoff.ab.application.service.vote.criteria.VoteClosingCriteria;
import life.offonoff.ab.domain.topic.Topic;
import life.offonoff.ab.domain.topic.TopicStatus;
import life.offonoff.ab.domain.vote.VoteResult;
import life.offonoff.ab.repository.topic.TopicRepository;
import life.offonoff.ab.repository.topic.TopicSearchCond;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -56,10 +55,8 @@ public void endVote(VoteClosingCriteria criteria) {
Topic topic = vt.getTopic();
topic.closeVote();

VoteResult result = aggregateVote(topic);

// 투표 종료 이벤트 발행
eventPublisher.publishEvent(new VoteClosedEvent(topic, result));
eventPublisher.publishEvent(new VoteClosedEvent(topic));
});
}
}
7 changes: 5 additions & 2 deletions src/main/java/life/offonoff/ab/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

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

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down Expand Up @@ -113,15 +114,17 @@ public void addComment(Comment comment) {
comments.add(comment);
}

public void likeCommentIfNew(Comment comment) {
public Optional<LikedComment> likeCommentIfNew(Comment comment) {
if (likeAlready(comment)) {
return;
return Optional.empty();
}

LikedComment likedComment = new LikedComment(this, comment);
comment.increaseLikeCount();

likedComments.add(likedComment);

return Optional.of(likedComment);
}

public void hateCommentIfNew(Comment comment) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package life.offonoff.ab.domain.notification;

import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.*;
import life.offonoff.ab.domain.comment.Comment;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.domain.topic.Topic;
Expand All @@ -21,7 +18,10 @@
@DiscriminatorValue(COMMENT_ON_TOPIC_NOTIFICATION)
public class CommentOnTopicNotification extends Notification {

@OneToOne
/**
* @OneToOne 관계이지만 {@link LikeInCommentNotification}가 {@link Comment}와 @ManyToOne 이기에 @ManyToOne 설정 ({@link Notification} 의 상속 전략 : SINGLE_TABLE)
*/
@ManyToOne
@JoinColumn(name = "comment_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Comment comment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package life.offonoff.ab.domain.notification;

import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.*;
import life.offonoff.ab.domain.comment.Comment;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import static life.offonoff.ab.domain.notification.NotificationType.LIKE_IN_COMMENT_NOTIFICATION;
// TODO:수정대상
Expand All @@ -14,6 +16,17 @@
@DiscriminatorValue(LIKE_IN_COMMENT_NOTIFICATION)
public class LikeInCommentNotification extends Notification {

@ManyToOne
@JoinColumn(name = "comment_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Comment comment;

public LikeInCommentNotification(Comment comment) {
super(comment.getWriter());

this.comment = comment;
}

@Override
public String getType() {
return LIKE_IN_COMMENT_NOTIFICATION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import jakarta.persistence.*;
import life.offonoff.ab.domain.member.Member;
import life.offonoff.ab.domain.vote.VoteResult;
import life.offonoff.ab.domain.topic.Topic;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -18,13 +18,13 @@
public class VoteResultNotification extends Notification {

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "vote_result_id")
@JoinColumn(name = "topic_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private VoteResult voteResult;
private Topic topic;

public VoteResultNotification(Member member, VoteResult voteResult) {
public VoteResultNotification(Member member, Topic topic) {
super(member);
this.voteResult = voteResult;
this.topic = topic;
}

@Override
Expand Down
8 changes: 0 additions & 8 deletions src/main/java/life/offonoff/ab/domain/topic/Topic.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import life.offonoff.ab.domain.topic.content.TopicContent;
import life.offonoff.ab.domain.topic.hide.HiddenTopic;
import life.offonoff.ab.domain.vote.Vote;
import life.offonoff.ab.domain.vote.VoteResult;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -58,9 +57,6 @@ public class Topic extends BaseEntity {
@OneToMany(mappedBy = "topic", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<TopicReport> reports = new ArrayList<>();

@OneToOne(mappedBy = "topic", cascade = CascadeType.ALL)
private VoteResult voteResult;

@Enumerated(EnumType.STRING)
private TopicStatus status = TopicStatus.VOTING;

Expand Down Expand Up @@ -143,10 +139,6 @@ public void addChoice(Choice choice) {
this.choices.add(choice);
}

public void setVoteResult(VoteResult voteResult) {
this.voteResult = voteResult;
}

public boolean isBeforeDeadline(LocalDateTime requestTime) {
if (deadline == null) {
return true;
Expand Down
Loading

0 comments on commit 85425bd

Please sign in to comment.