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 @@ -14,6 +14,7 @@
import com.back.member.domain.MemberRepository;
import com.back.post.application.PostErrorCode;
import com.back.post.entity.Post;
import com.back.post.entity.PostStatus;
import com.back.post.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -45,7 +46,7 @@ public Long createComment(Long postId, Long memberId, CommentCreateReq req) {
Member member = memberRepository.findById(memberId)
.orElseThrow(AuthErrorCode.MEMBER_NOT_FOUND::toException);

Post post = postRepository.findById(postId)
Post post = postRepository.findByIdAndStatusNot(postId, PostStatus.HIDDEN)
.orElseThrow(PostErrorCode.POST_NOT_FOUND::toException);

Comment parentComment = null;
Expand Down Expand Up @@ -86,7 +87,7 @@ public Long createComment(Long postId, Long memberId, CommentCreateReq req) {
*/
@Transactional(readOnly = true)
public Slice<CommentInfoRes> getComments(Long postId, Pageable pageable){
postRepository.findById(postId)
postRepository.findByIdAndStatusNot(postId, PostStatus.HIDDEN)
.orElseThrow(PostErrorCode.POST_NOT_FOUND::toException);

CommentPageCache cachedPage = commentCacheRepository.findPage(postId, pageable.getPageNumber(), pageable.getPageSize());
Expand Down
16 changes: 16 additions & 0 deletions back/src/main/java/com/back/post/repository/PostRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.back.post.entity.Post;
import com.back.post.entity.PostCategory;
import com.back.post.entity.PostStatus;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -26,6 +27,21 @@ public interface PostRepository extends JpaRepository<Post, Long> {

void deleteByTitleStartingWith(String prefix);

Slice<Post> findAllByStatusNot(PostStatus status, Pageable pageable);

Slice<Post> findByTitleContainingAndStatusNot(String title, PostStatus status, Pageable pageable);

Slice<Post> findByCategoryAndStatusNot(PostCategory category, PostStatus status, Pageable pageable);

Slice<Post> findByTitleContainingAndCategoryAndStatusNot(
String title,
PostCategory category,
PostStatus status,
Pageable pageable
);

java.util.Optional<Post> findByIdAndStatusNot(Long id, PostStatus status);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("update Post p set p.viewCount = p.viewCount + :delta where p.id = :postId")
int incrementViewCount(@Param("postId") Long postId, @Param("delta") int delta);
Expand Down
12 changes: 7 additions & 5 deletions back/src/main/java/com/back/post/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.back.post.entity.Post;
import com.back.post.entity.PostCategory;
import com.back.post.entity.PostResolutionStatus;
import com.back.post.entity.PostStatus;
import com.back.post.repository.PostRepository;
import com.back.post.repository.PostViewCountRedisRepository;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -81,13 +82,14 @@ public Slice<PostListRes> getPosts(String title, PostCategory category, Pageable
boolean hasTitle = StringUtils.hasText(title);

if (hasTitle && category != null) {
posts = postRepository.findByTitleContainingAndCategory(title, category, pageable);
posts = postRepository.findByTitleContainingAndCategoryAndStatusNot(
title, category, PostStatus.HIDDEN, pageable);
} else if (hasTitle) {
posts = postRepository.findByTitleContaining(title, pageable);
posts = postRepository.findByTitleContainingAndStatusNot(title, PostStatus.HIDDEN, pageable);
} else if (category != null) {
posts = postRepository.findByCategory(category, pageable);
posts = postRepository.findByCategoryAndStatusNot(category, PostStatus.HIDDEN, pageable);
} else {
posts = postRepository.findAllBy(pageable);
posts = postRepository.findAllByStatusNot(PostStatus.HIDDEN, pageable);
}

return posts.map(PostListRes::from);
Expand All @@ -106,7 +108,7 @@ public Slice<PostListRes> getPosts(String title, PostCategory category, Pageable
*/
@Transactional
public PostInfoRes getPost(Long id) {
Post post = postRepository.findById(id)
Post post = postRepository.findByIdAndStatusNot(id, PostStatus.HIDDEN)
.orElseThrow(PostErrorCode.POST_NOT_FOUND::toException);

long pendingViewCount = postViewCountRedisRepository.incrementViewCount(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void createCommentConnectsAuthorAndPost() {
Member member = savedMember(1L, "member1@test.com", "member1");
Post post = savedPost(10L, member);
given(memberRepository.findById(1L)).willReturn(Optional.of(member));
given(postRepository.findById(10L)).willReturn(Optional.of(post));
given(postRepository.findByIdAndStatusNot(10L, PostStatus.HIDDEN)).willReturn(Optional.of(post));
given(commentRepository.save(any(Comment.class))).willAnswer(invocation -> invocation.getArgument(0));

commentService.createComment(10L, 1L, new CommentCreateReq(" 댓글 내용 ", null, null));
Expand All @@ -67,7 +67,7 @@ void createReplyFailsWhenParentBelongsToAnotherPost() {
setId(parent, 100L);

given(memberRepository.findById(1L)).willReturn(Optional.of(member));
given(postRepository.findById(10L)).willReturn(Optional.of(requestPost));
given(postRepository.findByIdAndStatusNot(10L, PostStatus.HIDDEN)).willReturn(Optional.of(requestPost));
given(commentRepository.findById(100L)).willReturn(Optional.of(parent));

assertThatThrownBy(() -> commentService.createComment(10L, 1L, new CommentCreateReq("reply", null, 100L)))
Expand Down Expand Up @@ -122,6 +122,20 @@ void deleteCommentHardDeletesWhenNoRepliesExist() {
then(commentRepository).should().delete(comment);
}

@Test
@DisplayName("숨김 게시글에는 댓글을 작성할 수 없다")
void createCommentFailsWhenPostHidden() {
Member member = savedMember(1L, "member1@test.com", "member1");
given(memberRepository.findById(1L)).willReturn(Optional.of(member));
given(postRepository.findByIdAndStatusNot(10L, PostStatus.HIDDEN)).willReturn(Optional.empty());

assertThatThrownBy(() -> commentService.createComment(10L, 1L, new CommentCreateReq("댓글", null, null)))
.isInstanceOf(ServiceException.class)
.satisfies(
exception ->
assertThat(((ServiceException) exception).getRsData().resultCode()).isEqualTo("404-1"));
}

private Member savedMember(Long id, String email, String nickname) {
Member member = Member.create(email, "$2a$10$stored", nickname);
setId(member, id);
Expand Down
50 changes: 50 additions & 0 deletions back/src/test/java/com/back/post/service/PostServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import com.back.post.entity.Post;
import com.back.post.entity.PostCategory;
import com.back.post.entity.PostResolutionStatus;
import com.back.post.entity.PostStatus;
import com.back.post.repository.PostRepository;
import com.back.post.repository.PostViewCountRedisRepository;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -24,12 +27,16 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.SliceImpl;

@ExtendWith(MockitoExtension.class)
@DisplayName("게시글 서비스 멤버 연결 테스트")
class PostServiceTest {

@Mock private PostRepository postRepository;
@Mock private PostViewCountRedisRepository postViewCountRedisRepository;
@Mock private MemberRepository memberRepository;
@Mock private CommentRepository commentRepository;

Expand Down Expand Up @@ -145,12 +152,55 @@ void updateResolutionStatusByOwner() {
assertThat(post.getResolutionStatus()).isEqualTo(PostResolutionStatus.RESOLVED);
}

@Test
@DisplayName("게시글 목록 조회 시 숨김 게시글은 제외한다")
void getPostsExcludesHiddenPosts() {
Pageable pageable = PageRequest.of(0, 10);
Member author = savedMember(1L, "member1@test.com", "member1");
Post visiblePost = savedPost(20L, author);

given(postRepository.findAllByStatusNot(PostStatus.HIDDEN, pageable))
.willReturn(new SliceImpl<>(List.of(visiblePost), pageable, false));

var result = postService.getPosts(null, null, pageable);

assertThat(result.getContent()).hasSize(1);
then(postRepository).should().findAllByStatusNot(PostStatus.HIDDEN, pageable);
}

@Test
@DisplayName("숨김 게시글 상세 조회는 존재하지 않는 게시글로 처리한다")
void getPostFailsWhenHidden() {
given(postRepository.findByIdAndStatusNot(21L, PostStatus.HIDDEN)).willReturn(Optional.empty());

assertThatThrownBy(() -> postService.getPost(21L))
.isInstanceOf(ServiceException.class)
.satisfies(
exception ->
assertThat(((ServiceException) exception).getRsData().resultCode()).isEqualTo("404-1"));
}

private Member savedMember(Long id, String email, String nickname) {
Member member = Member.create(email, "$2a$10$stored", nickname);
setId(member, id);
return member;
}

private Post savedPost(Long id, Member member) {
Post post =
Post.builder()
.title("title")
.content("content")
.summary("content")
.thumbnail("thumbnail")
.member(member)
.category(PostCategory.DAILY)
.status(PostStatus.PUBLISHED)
.build();
setId(post, id);
return post;
}

private void setId(Object target, Long id) {
try {
Class<?> type = target.getClass();
Expand Down
Loading