Skip to content
Open
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 @@ -128,7 +128,7 @@ public CreateCommentResponse createComment(Long articleId, CreateCommentRequest
Article article = articleRepository.findByIdFetchJoin(articleId)
.orElseThrow(NotFoundArticleException::new);
CommentEntity savedComment = commentRepository.save(
new CommentEntity(request.getContent(), article, member)
CommentEntity.of(request.getContent(), article, member)
);
Member articleOwner = article.getArticleOwner();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public CreateChildCommentResponse createChildComment(
CommentEntity parentComment = commentRepository.findById(parentCommentId)
.orElseThrow(NotFoundCommentException::new);

CommentEntity childComment = commentRepository.save(new CommentEntity(request.getContent(), article, member));
CommentEntity childComment = commentRepository.save(CommentEntity.of(request.getContent(), article, member));
childComment.updateParent(parentComment);

Member owner = memberRepository.findById(parentComment.getAuthorId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@
import com.numberone.backend.domain.notification.entity.NotificationEntity;
import com.numberone.backend.domain.notification.entity.NotificationTag;
import com.numberone.backend.domain.notification.repository.NotificationRepository;
import com.numberone.backend.exception.notfound.*;
import com.numberone.backend.provider.security.SecurityContextProvider;
import com.numberone.backend.exception.conflict.AlreadyLikedException;
import com.numberone.backend.exception.conflict.AlreadyUnLikedException;
import com.numberone.backend.exception.notfound.NotFoundApiException;
import com.numberone.backend.exception.notfound.NotFoundCommentException;
import com.numberone.backend.exception.notfound.NotFoundMemberException;
import com.numberone.backend.provider.fcm.service.FcmMessageProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -43,17 +41,16 @@ public class LikeService {

@Transactional
public Integer increaseArticleLike(Long articleId) {
long principal = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(principal)
Long memberId = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(memberId)
.orElseThrow(NotFoundMemberException::new);
Article article = articleRepository.findByIdFetchJoin(articleId)
.orElseThrow(NotFoundApiException::new);
if (isAlreadyLikedArticle(member, articleId)) {
// 이미 좋아요를 누른 게시글입니다.
.orElseThrow(NotFoundArticleException::new);

if (isAlreadyLikedArticle(memberId, articleId))
throw new AlreadyLikedException();
}
article.increaseLikeCount();
articleLikeRepository.save(new ArticleLike(member, article));
articleLikeRepository.save(ArticleLike.of(member, article));

Member articleOwner = article.getArticleOwner();
String memberName = member.getNickName() != null ? member.getNickName() : member.getRealName();
Expand All @@ -70,40 +67,35 @@ public Integer increaseArticleLike(Long articleId) {

@Transactional
public Integer decreaseArticleLike(Long articleId) {
long principal = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(principal)
Long memberId = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(memberId)
.orElseThrow(NotFoundMemberException::new);
Article article = articleRepository.findById(articleId)
.orElseThrow(NotFoundApiException::new);
if (!isAlreadyLikedArticle(member, articleId)) {
// 좋아요를 누르지 않은 게시글이라 취소할 수 없습니다.
if (!isAlreadyLikedArticle(member.getId(), articleId))
throw new AlreadyUnLikedException();
}
article.decreaseLikeCount();

// 사용자의 게시글 좋아요 목록에서 제거
List<ArticleLike> articleLikeList = articleLikeRepository.findByMember(member);
articleLikeList.forEach(articleLike -> {
if (articleLike.getArticleId().equals(articleId))
articleLikeRepository.delete(articleLike);
});
article.decreaseLikeCount();
ArticleLike articleLike = articleLikeRepository.findByMemberIdAndArticleId(memberId, articleId)
.orElseThrow(NotFoundArticleLikeException::new);
articleLikeRepository.delete(articleLike);

return article.getLikeCount();
}

@Transactional
public Integer increaseCommentLike(Long commentId) {
long principal = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(principal)
Long memberId = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(memberId)
.orElseThrow(NotFoundMemberException::new);
CommentEntity commentEntity = commentRepository.findById(commentId)
.orElseThrow(NotFoundCommentException::new);
if (isAlreadyLikedComment(member, commentId)) {
// 이미 좋아요를 누른 댓글입니다.
if (isAlreadyLikedComment(member.getId(), commentId))
throw new AlreadyLikedException();
}

commentEntity.increaseLikeCount();
commentLikeRepository.save(new CommentLike(member, commentEntity));
commentLikeRepository.save(CommentLike.of(member, commentEntity));


Long ownerId = commentEntity.getAuthorId();
Expand All @@ -124,34 +116,27 @@ public Integer increaseCommentLike(Long commentId) {

@Transactional
public Integer decreaseCommentLike(Long commentId) {
long principal = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(principal)
long memberId = SecurityContextProvider.getAuthenticatedUserId();
Member member = memberRepository.findById(memberId)
.orElseThrow(NotFoundMemberException::new);
CommentEntity commentEntity = commentRepository.findById(commentId)
.orElseThrow(NotFoundCommentException::new);
if (!isAlreadyLikedComment(member, commentId)) {
// 좋아요를 누르지 않은 댓글이라 좋아요를 취소할 수 없습니다.
if (!isAlreadyLikedComment(member.getId(), commentId))
throw new AlreadyUnLikedException();
}

commentEntity.decreaseLikeCount();
// 사용자의 댓글 좋아요 목록에서 제거
List<CommentLike> commentLikeList = commentLikeRepository.findByMember(member);
commentLikeList.forEach(commentLike -> {
if (commentLike.getCommentId().equals(commentId))
commentLikeRepository.delete(commentLike);
});
CommentLike commentLike = commentLikeRepository.findByMemberIdAndCommentId(memberId, commentId)
.orElseThrow(NotFoundCommentLikeException::new);
commentLikeRepository.delete(commentLike);

return commentEntity.getLikeCount();
}

private boolean isAlreadyLikedArticle(Member member, Long articleId) {
return articleLikeRepository.findByMember(member).stream()
.anyMatch(articleLike -> articleLike.getArticleId().equals(articleId));
private boolean isAlreadyLikedArticle(Long memberId, Long articleId) {
return articleLikeRepository.existsByMemberIdAndArticleId(memberId, articleId);
}

private boolean isAlreadyLikedComment(Member member, Long commentId) {
return commentLikeRepository.findByMember(member).stream()
.anyMatch(commentLike -> commentLike.getCommentId().equals(commentId));
private boolean isAlreadyLikedComment(Long memberId, Long commentId) {
return commentLikeRepository.existsByMemberIdAndCommentId(memberId, commentId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package com.numberone.backend.domain.like.service;

import com.numberone.backend.domain.article.entity.Article;
import com.numberone.backend.domain.article.entity.ArticleTag;
import com.numberone.backend.domain.article.repository.ArticleRepository;
import com.numberone.backend.domain.comment.entity.CommentEntity;
import com.numberone.backend.domain.comment.repository.CommentRepository;
import com.numberone.backend.domain.like.entity.ArticleLike;
import com.numberone.backend.domain.like.entity.CommentLike;
import com.numberone.backend.domain.like.repository.ArticleLikeRepository;
import com.numberone.backend.domain.like.repository.CommentLikeRepository;
import com.numberone.backend.domain.member.entity.Member;
import com.numberone.backend.domain.member.repository.MemberRepository;
import com.numberone.backend.domain.notification.repository.NotificationRepository;
import com.numberone.backend.provider.fcm.service.FcmMessageProvider;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class LikeServiceTest {
@InjectMocks
private LikeService likeService;
@Mock
private ArticleLikeRepository articleLikeRepository;
@Mock
private ArticleRepository articleRepository;
@Mock
private MemberRepository memberRepository;
@Mock
private FcmMessageProvider fcmMessageProvider;
@Mock
private NotificationRepository notificationRepository;
@Mock
private CommentRepository commentRepository;
@Mock
private CommentLikeRepository commentLikeRepository;

private Member loginMember;

@BeforeEach
void setUp() {
setAuthentication();
}

@AfterEach
void tearDown() {
clearAuthentication();
}

@Test
@DisplayName("게시글의 좋아요를 설정한다")
void increaseArticleLike() {
// given
Member articleOwner = getDummyArticleOwner();
given(articleOwner.getId())
.willReturn(2L);
given(articleOwner.getFcmToken())
.willReturn("fcmToken123");

Article article = getDummyArticle(articleOwner);
given(article.getId())
.willReturn(1L);
given(articleRepository.findByIdFetchJoin(article.getId()))
.willReturn(Optional.of(article));

//when
likeService.increaseArticleLike(article.getId());

// then
assertThat(article.getLikeCount()).isEqualTo(1);
verify(articleLikeRepository, times(1)).save(any());
verify(fcmMessageProvider, times(1)).sendFcm(eq(articleOwner.getFcmToken()), any(), any());
verify(notificationRepository, times(1)).save(any());
}

@Test
@DisplayName("게시글의 좋아요를 취소한다")
void decreaseArticleLike() {
// given
Member articleOwner = getDummyArticleOwner();

Article article = getDummyArticle(articleOwner);
article.increaseLikeCount();
article.increaseLikeCount();
given(article.getId())
.willReturn(1L);
given(articleRepository.findById(article.getId()))
.willReturn(Optional.of(article));

ArticleLike articleLike = ArticleLike.of(loginMember, article);
given(articleLikeRepository.existsByMemberIdAndArticleId(loginMember.getId(), article.getId()))
.willReturn(true);
given(articleLikeRepository.findByMemberIdAndArticleId(loginMember.getId(), article.getId()))
.willReturn(Optional.of(articleLike));

//when
likeService.decreaseArticleLike(article.getId());

// then
assertThat(article.getLikeCount()).isEqualTo(1);
verify(articleLikeRepository, times(1)).delete(any());
}

@Test
@DisplayName("댓글의 좋아요를 설정한다")
void increaseCommentLike() {
//given
Member articleOwner = getDummyArticleOwner();

Article article = getDummyArticle(articleOwner);

Member commentOwner = getDummyCommentOwner();
given(memberRepository.findById(commentOwner.getId()))
.willReturn(Optional.of(commentOwner));
given(commentOwner.getFcmToken())
.willReturn("fcmToken123");

CommentEntity commentEntity = getDummyComment(article, commentOwner);
given(commentEntity.getId())
.willReturn(1L);
given(commentRepository.findById(commentEntity.getId()))
.willReturn(Optional.of(commentEntity));

//when
likeService.increaseCommentLike(commentEntity.getId());

//then
assertThat(commentEntity.getLikeCount()).isEqualTo(1);
verify(commentLikeRepository, times(1)).save(any());
verify(fcmMessageProvider, times(1)).sendFcm(eq(commentOwner.getFcmToken()), any(), any());
verify(notificationRepository, times(1)).save(any());
}

@Test
@DisplayName("댓글의 좋아요를 취소한다")
void decreaseCommentLike() {
//given
Member articleOwner = getDummyArticleOwner();

Article article = getDummyArticle(articleOwner);

Member commentOwner = getDummyCommentOwner();

CommentEntity commentEntity = getDummyComment(article, commentOwner);
commentEntity.increaseLikeCount();
commentEntity.increaseLikeCount();
given(commentEntity.getId())
.willReturn(1L);
given(commentRepository.findById(commentEntity.getId()))
.willReturn(Optional.of(commentEntity));

CommentLike commentLike = CommentLike.of(loginMember, commentEntity);
given(commentLikeRepository.existsByMemberIdAndCommentId(loginMember.getId(), commentEntity.getId()))
.willReturn(true);
given(commentLikeRepository.findByMemberIdAndCommentId(loginMember.getId(), commentEntity.getId()))
.willReturn(Optional.of(commentLike));

//when
likeService.decreaseCommentLike(commentEntity.getId());

//then
assertThat(commentEntity.getLikeCount()).isEqualTo(1);
verify(commentLikeRepository, times(1)).delete(any());
}

private Member getDummyCommentOwner() {
Member commentOwner = spy(Member.ofKakao(3456L));
given(commentOwner.getId())
.willReturn(3L);
return commentOwner;
}

private Member getDummyArticleOwner() {
Member articleOwner = spy(Member.ofKakao(2345L));
return articleOwner;
}

private Article getDummyArticle(Member articleOwner) {
return spy(Article.of("title1", "content1", articleOwner, ArticleTag.LIFE));
}

private CommentEntity getDummyComment(Article article, Member commentOwner) {
return spy(CommentEntity.of("hello", article, commentOwner));
}

private void setAuthentication() {
loginMember = spy(Member.ofKakao(1234L));
given(loginMember.getId())
.willReturn(1L);
given(memberRepository.findById(loginMember.getId()))
.willReturn(Optional.of(loginMember));

Authentication authentication = UsernamePasswordAuthenticationToken.authenticated(loginMember.getId(), null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
}

private void clearAuthentication() {
SecurityContextHolder.clearContext();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ public enum CustomExceptionContext implements ExceptionContext {

// article 관련 예외
NOT_FOUND_ARTICLE("해당 게시글을 찾을 수 없습니다.", 8000),
NOT_FOUND_ARTICLE_LIKE("해당 게시글의 좋아요를 찾을 수 없습니다.", 8001),

// article image 관련 예외
NOT_FOUND_ARTICLE_IMAGE("해당 이미지를 찾을 수 없습니다.", 9000),
UNAUTHORIZED_LOCATION_ERROR("사용자가 해당 요청을 처리할 수 없는 지역에 위치하고 있습니다.", 9001),

// comment 관련 예외
NOT_FOUND_COMMENT("해당 댓글을 찾을 수 없습니다.", 10000),
NOT_FOUND_COMMENT_LIKE("해당 댓글의 좋아요를 찾을 수 없습니다.", 10001),

// like 관련 예외
ALREADY_LIKED_ERROR("이미 좋아요 처리된 엔티티입니다.", 11000),
Expand Down
Loading