diff --git a/src/docs/asciidoc/posts.adoc b/src/docs/asciidoc/posts.adoc index 76f50fe4..a704caf3 100644 --- a/src/docs/asciidoc/posts.adoc +++ b/src/docs/asciidoc/posts.adoc @@ -9,6 +9,20 @@ operation::post-controller-test/create-post[snippets='http-request,curl-request, [[게시글-상세-조회]] === `GET` 게시글 상세 조회 +공유 키 관련 +|=== +|공개범위(scope)|유저|shareKey 일치 여부|응답 여부 + +|PUBLIC|작성자|O|O +|PUBLIC|작성자|X|O +|PUBLIC|다른 사용자|O|O +|PUBLIC|다른 사용자|X|O +|PRIVATE|작성자|O|O +|PRIVATE|작성자|X|O +|PRIVATE|다른 사용자|O|O +|PRIVATE|다른 사용자|X|400에러 +|=== + operation::post-controller-test/find-post[snippets='http-request,curl-request,path-parameters,http-response,response-fields'] [[개사굴-공유-url-조회]] diff --git a/src/main/java/com/chooz/common/exception/ErrorCode.java b/src/main/java/com/chooz/common/exception/ErrorCode.java index 72dad149..9d83b48f 100644 --- a/src/main/java/com/chooz/common/exception/ErrorCode.java +++ b/src/main/java/com/chooz/common/exception/ErrorCode.java @@ -49,6 +49,7 @@ public enum ErrorCode { INVALID_ONBOARDING_STEP("유효하지 않은 온보딩 단계."), NICKNAME_LENGTH_EXCEEDED("닉네임 길이 초과"), NOTIFICATION_NOT_FOUND("존재하지 않는 알림 입니다."), + POST_NOT_REVEALABLE("공개 불가능한 게시글입니다."), //401 EXPIRED_TOKEN("토큰이 만료됐습니다."), diff --git a/src/main/java/com/chooz/post/application/MyPagePostManager.java b/src/main/java/com/chooz/post/application/MyPagePostManager.java new file mode 100644 index 00000000..d32b994e --- /dev/null +++ b/src/main/java/com/chooz/post/application/MyPagePostManager.java @@ -0,0 +1,120 @@ +package com.chooz.post.application; + +import com.chooz.common.dto.CursorBasePaginatedResponse; +import com.chooz.post.application.dto.PollChoiceVoteInfo; +import com.chooz.post.application.dto.PostWithVoteCount; +import com.chooz.post.domain.PollChoiceRepository; +import com.chooz.post.domain.PostRepository; +import com.chooz.post.presentation.dto.MostVotedPollChoiceDto; +import com.chooz.post.presentation.dto.MyPagePostResponse; +import com.chooz.vote.application.RatioCalculator; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.stereotype.Component; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class MyPagePostManager { + + private final PostRepository postRepository; + private final PollChoiceRepository pollChoiceRepository; + private final RatioCalculator ratioCalculator; + + public CursorBasePaginatedResponse getUserPosts( + Long userId, + Long myPageUserId, + Long cursor, + Pageable pageable + ) { + Slice postSlice = postRepository.findPostsWithVoteCountByUserId( + userId, + myPageUserId, + cursor, + pageable + ); + + return getMyPageCursoredResponse(postSlice); + } + + public CursorBasePaginatedResponse getVotedPosts( + Long userId, + Long myPageUserId, + Long cursor, + Pageable pageable + ) { + Slice postSlice = postRepository.findVotedPostsWithVoteCount( + userId, + myPageUserId, + cursor, + pageable + ); + + return getMyPageCursoredResponse(postSlice); + } + + private CursorBasePaginatedResponse getMyPageCursoredResponse(Slice postSlice) { + if (postSlice.isEmpty()) { + return CursorBasePaginatedResponse.of(new SliceImpl<>( + List.of(), + postSlice.getPageable(), + false + )); + } + + List postIds = getPostIds(postSlice); + Map mostVotedPollChoiceByPostId = getMostVotedPollChoiceByPostId(postIds); + + List responses = getMyPagePostResponses(postSlice, mostVotedPollChoiceByPostId); + + return CursorBasePaginatedResponse.of(new SliceImpl<>( + responses, + postSlice.getPageable(), + postSlice.hasNext() + )); + } + + private Map getMostVotedPollChoiceByPostId(List postIds) { + List pollChoiceWithVoteInfo = pollChoiceRepository.findPollChoiceWithVoteInfo(postIds); + return pollChoiceWithVoteInfo.stream() + .collect(Collectors.groupingBy( + PollChoiceVoteInfo::postId, + Collectors.collectingAndThen( + Collectors.toList(), + choices -> choices.stream() + .max(Comparator.comparing(PollChoiceVoteInfo::voteCounts)) + .orElse(null) + ) + )); + } + + private List getMyPagePostResponses( + Slice postSlice, + Map mostVotedPollChoiceByPostId + ) { + return postSlice.getContent() + .stream() + .map(postWithVoteCount -> { + var pollChoiceVoteInfo = mostVotedPollChoiceByPostId.get(postWithVoteCount.post().getId()); + var mostVotedPollChoiceInfo = MostVotedPollChoiceDto.of( + pollChoiceVoteInfo, + ratioCalculator.calculate(postWithVoteCount.voteCount(), pollChoiceVoteInfo.voteCounts()) + ); + return MyPagePostResponse.of(postWithVoteCount, mostVotedPollChoiceInfo); + }) + .toList(); + } + + private List getPostIds(Slice postSlice) { + return postSlice.getContent() + .stream() + .map(postWithVoteCount -> postWithVoteCount.post().getId()) + .toList(); + } +} diff --git a/src/main/java/com/chooz/post/application/PostQueryService.java b/src/main/java/com/chooz/post/application/PostQueryService.java index 41d3974d..b68a19db 100644 --- a/src/main/java/com/chooz/post/application/PostQueryService.java +++ b/src/main/java/com/chooz/post/application/PostQueryService.java @@ -4,38 +4,29 @@ import com.chooz.common.dto.CursorBasePaginatedResponse; import com.chooz.common.exception.BadRequestException; import com.chooz.common.exception.ErrorCode; -import com.chooz.post.application.dto.PollChoiceVoteInfo; -import com.chooz.post.application.dto.PostWithVoteCount; +import com.chooz.post.application.dto.FeedDto; 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.presentation.UpdatePostResponse; import com.chooz.post.presentation.dto.AuthorDto; -import com.chooz.post.application.dto.FeedDto; import com.chooz.post.presentation.dto.FeedResponse; -import com.chooz.post.presentation.dto.MostVotedPollChoiceDto; import com.chooz.post.presentation.dto.MyPagePostResponse; import com.chooz.post.presentation.dto.PollChoiceVoteResponse; import com.chooz.post.presentation.dto.PostResponse; +import com.chooz.post.presentation.dto.UpdatePostResponse; import com.chooz.user.domain.User; import com.chooz.user.domain.UserRepository; -import com.chooz.vote.application.RatioCalculator; import com.chooz.vote.domain.Vote; import com.chooz.vote.domain.VoteRepository; +import jakarta.annotation.Nullable; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Service @Transactional(readOnly = true) @@ -43,11 +34,10 @@ public class PostQueryService { private final PostRepository postRepository; - private final PollChoiceRepository pollChoiceRepository; private final UserRepository userRepository; private final VoteRepository voteRepository; private final CommentRepository commentRepository; - private final RatioCalculator ratioCalculator; + private final MyPagePostManager myPagePostManager; public PostResponse findByShareUrl(Long userId, String shareUrl) { Post post = postRepository.findByShareUrlFetchPollChoices(shareUrl) @@ -55,9 +45,12 @@ public PostResponse findByShareUrl(Long userId, String shareUrl) { return createPostResponse(userId, post); } - public PostResponse findById(Long userId, Long postId) { + public PostResponse findById(Long userId, Long postId, @Nullable String shareKey) { Post post = postRepository.findByIdFetchPollChoices(postId) .orElseThrow(() -> new BadRequestException(ErrorCode.POST_NOT_FOUND)); + if (!post.isRevealable(userId, shareKey)) { + throw new BadRequestException(ErrorCode.POST_NOT_REVEALABLE); + } return createPostResponse(userId, post); } @@ -100,73 +93,22 @@ private Long getVoteId(List voteList, Long pollChoiceId, Long userId) { .orElse(null); } - public CursorBasePaginatedResponse findUserPosts(Long userId, Long cursor, int size) { - Slice postSlice = postRepository.findPostsWithVoteCountByUserId(userId, cursor, Pageable.ofSize(size)); - - return getCursorPaginatedResponse(postSlice); - } - - public CursorBasePaginatedResponse findVotedPosts(Long userId, Long cursor, int size) { - Slice postSlice = postRepository.findVotedPostsWithVoteCount(userId, cursor, Pageable.ofSize(size)); - - return getCursorPaginatedResponse(postSlice); - } - - private CursorBasePaginatedResponse getCursorPaginatedResponse(Slice postSlice) { - if (postSlice.isEmpty()) { - return CursorBasePaginatedResponse.of(new SliceImpl<>( - List.of(), - postSlice.getPageable(), - false - )); - } - - Map mostVotedPollChoiceByPostId = getMostVotedPollChoiceByPostId(getPostIds(postSlice)); - - List response = getMyPagePostResponses(postSlice, mostVotedPollChoiceByPostId); - - return CursorBasePaginatedResponse.of(new SliceImpl<>( - response, - postSlice.getPageable(), - postSlice.hasNext() - )); - } - - private List getMyPagePostResponses( - Slice postSlice, - Map mostVotedPollChoiceByPostId + public CursorBasePaginatedResponse findUserPosts( + Long userId, + Long myPageUserId, + Long cursor, + int size ) { - return postSlice.getContent().stream() - .map(postWithVoteCount -> { - var pollChoiceVoteInfo = mostVotedPollChoiceByPostId.get(postWithVoteCount.post().getId()); - var mostVotedPollChoiceInfo = MostVotedPollChoiceDto.of( - pollChoiceVoteInfo, - ratioCalculator.calculate(postWithVoteCount.voteCount(), pollChoiceVoteInfo.voteCounts()) - ); - return MyPagePostResponse.of(postWithVoteCount, mostVotedPollChoiceInfo); - }) - .toList(); - } - - private Map getMostVotedPollChoiceByPostId(List postIds) { - List pollChoiceWithVoteInfo = pollChoiceRepository.findPollChoiceWithVoteInfo(postIds); - return pollChoiceWithVoteInfo.stream() - .collect(Collectors.groupingBy( - PollChoiceVoteInfo::postId, - Collectors.collectingAndThen( - Collectors.toList(), - choices -> choices.stream() - .max(Comparator.comparing(PollChoiceVoteInfo::voteCounts)) - .orElse(null) - ) - )); + return myPagePostManager.getUserPosts(userId, myPageUserId, cursor, Pageable.ofSize(size)); } - private List getPostIds(Slice postSlice) { - return postSlice.getContent() - .stream() - .map(postWithVoteCount -> postWithVoteCount.post().getId()) - .toList(); + public CursorBasePaginatedResponse findVotedPosts( + Long userId, + Long myPageUserId, + Long cursor, + int size + ) { + return myPagePostManager.getVotedPosts(userId, myPageUserId, cursor, Pageable.ofSize(size)); } public CursorBasePaginatedResponse findFeed(Long userId, Long cursor, int size) { diff --git a/src/main/java/com/chooz/post/application/PostService.java b/src/main/java/com/chooz/post/application/PostService.java index cd3ccf81..af33302e 100644 --- a/src/main/java/com/chooz/post/application/PostService.java +++ b/src/main/java/com/chooz/post/application/PostService.java @@ -1,7 +1,7 @@ package com.chooz.post.application; import com.chooz.common.dto.CursorBasePaginatedResponse; -import com.chooz.post.presentation.UpdatePostResponse; +import com.chooz.post.presentation.dto.UpdatePostResponse; import com.chooz.post.presentation.dto.CreatePostRequest; import com.chooz.post.presentation.dto.CreatePostResponse; import com.chooz.post.presentation.dto.FeedResponse; @@ -40,16 +40,26 @@ public void update(Long userId, Long postId, UpdatePostRequest request) { postCommandService.update(userId, postId, request); } - public PostResponse findById(Long userId, Long postId) { - return postQueryService.findById(userId, postId); + public PostResponse findById(Long userId, Long postId, String shareKey) { + return postQueryService.findById(userId, postId, shareKey); } - public CursorBasePaginatedResponse findUserPosts(Long userId, Long cursor, int size) { - return postQueryService.findUserPosts(userId, cursor, size); + public CursorBasePaginatedResponse findUserPosts( + Long userId, + Long myPageUserId, + Long cursor, + int size + ) { + return postQueryService.findUserPosts(userId, myPageUserId, cursor, size); } - public CursorBasePaginatedResponse findVotedPosts(Long userId, Long cursor, int size) { - return postQueryService.findVotedPosts(userId, cursor, size); + public CursorBasePaginatedResponse findVotedPosts( + Long userId, + Long myPageUserId, + Long cursor, + int size + ) { + return postQueryService.findVotedPosts(userId, myPageUserId, cursor, size); } public PostResponse findByShareUrl(Long userId, String shareUrl) { diff --git a/src/main/java/com/chooz/post/domain/Post.java b/src/main/java/com/chooz/post/domain/Post.java index 97440a35..4296bd79 100644 --- a/src/main/java/com/chooz/post/domain/Post.java +++ b/src/main/java/com/chooz/post/domain/Post.java @@ -222,4 +222,13 @@ public void delete(Long userId) { } this.delete(); } + + public boolean isRevealable(Long userId) { + return this.pollOption.getScope().equals(Scope.PUBLIC) || + this.userId.equals(userId); + } + + public boolean isRevealable(Long userId, String shareUrl) { + return isRevealable(userId) || this.shareUrl.equals(shareUrl); + } } diff --git a/src/main/java/com/chooz/post/domain/PostRepository.java b/src/main/java/com/chooz/post/domain/PostRepository.java index 50f473df..7b370280 100644 --- a/src/main/java/com/chooz/post/domain/PostRepository.java +++ b/src/main/java/com/chooz/post/domain/PostRepository.java @@ -30,9 +30,9 @@ public interface PostRepository { Optional findCommentActiveByPostId(Long postId); - Slice findPostsWithVoteCountByUserId(Long userId, Long postId, Pageable pageable); + Slice findPostsWithVoteCountByUserId(Long userId, Long authorId, Long postId, Pageable pageable); - Slice findVotedPostsWithVoteCount(Long userId, Long postId, Pageable pageable); + Slice findVotedPostsWithVoteCount(Long userId, Long authorId, Long postId, Pageable pageable); Optional findByIdAndUserId(Long postId, Long userId); } diff --git a/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java b/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java index dc3d2d1a..2295b963 100644 --- a/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java +++ b/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java @@ -1,16 +1,15 @@ package com.chooz.post.persistence; +import com.chooz.post.application.dto.FeedDto; import com.chooz.post.application.dto.PostWithVoteCount; import com.chooz.post.application.dto.QFeedDto; import com.chooz.post.application.dto.QPostWithVoteCount; import com.chooz.post.domain.Post; -import com.chooz.post.application.dto.FeedDto; import com.chooz.post.domain.Scope; -import com.chooz.user.domain.QUser; +import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.NumberPath; import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -21,8 +20,8 @@ import java.util.List; import static com.chooz.comment.domain.QComment.comment; -import static com.chooz.post.domain.QPost.*; -import static com.chooz.user.domain.QUser.*; +import static com.chooz.post.domain.QPost.post; +import static com.chooz.user.domain.QUser.user; import static com.chooz.vote.domain.QVote.vote; @Repository @@ -60,6 +59,7 @@ private boolean isHasNext(Pageable pageable, List results) { /** * 피드 관련 데이터 조회 + * * @param postId * @param pageable * @return @@ -93,7 +93,6 @@ public Slice findFeed(Long postId, Pageable pageable) { .from(post) .innerJoin(user).on(post.userId.eq(user.id)) .where( - post.deleted.isFalse(), post.pollOption.scope.eq(Scope.PUBLIC), cursor(postId, post.id), post.deleted.isFalse() @@ -112,49 +111,52 @@ public Slice findFeed(Long postId, Pageable pageable) { /** * 유저가 작성한 게시글 리스트 조회 + * * @param userId * @param postId * @param pageable * @return */ - public Slice findPostsWithVoteCountByUserId(Long userId, Long postId, Pageable pageable) { - List results = queryFactory - .select(new QPostWithVoteCount( - post, - JPAExpressions - .select(vote.userId.count()) - .from(vote) - .where( - vote.postId.eq(post.id), - vote.deleted.isFalse() - ) - )) - .from(post) - .where( - post.userId.eq(userId), - cursor(postId, post.id), - post.deleted.isFalse() - ) - .orderBy(post.id.desc()) - .limit(pageable.getPageSize() + 1) - .fetch(); - - boolean hasNext = isHasNext(pageable, results); - - if (hasNext) { - results.removeLast(); - } - return new SliceImpl<>(results, pageable, hasNext); + public Slice findPostsWithVoteCountByUserId(Long userId, Long authorId, Long postId, Pageable pageable) { + BooleanBuilder builder = new BooleanBuilder( + post.userId.eq(authorId) + .and(cursor(postId, post.id)) + .and(post.deleted.isFalse()) + ); + return getPostWithVoteCounts(userId, authorId, pageable, builder); } /** * 유저가 투표한 게시글 리스트 조회 + * * @param userId + * @param authorId * @param postId * @param pageable * @return */ - public Slice findVotedPostsWithVoteCount(Long userId, Long postId, Pageable pageable) { + public Slice findVotedPostsWithVoteCount(Long userId, Long authorId, Long postId, Pageable pageable) { + BooleanBuilder builder = new BooleanBuilder( + post.id.in( + JPAExpressions + .select(vote.postId) + .from(vote) + .where( + vote.userId.eq(authorId), + vote.deleted.isFalse() + ) + ) + .and(cursor(postId, post.id)) + .and(post.deleted.isFalse()) + ); + return getPostWithVoteCounts(userId, authorId, pageable, builder); + } + + private Slice getPostWithVoteCounts(Long userId, Long authorId, Pageable pageable, BooleanBuilder builder) { + if (!userId.equals(authorId)) { + builder.and(post.pollOption.scope.eq(Scope.PUBLIC)); + } + List results = queryFactory .select(new QPostWithVoteCount( post, @@ -167,19 +169,7 @@ public Slice findVotedPostsWithVoteCount(Long userId, Long po ) )) .from(post) - .where( - post.id.in( - JPAExpressions - .select(vote.postId) - .from(vote) - .where( - vote.userId.eq(userId), - vote.deleted.isFalse() - ) - ), - cursor(postId, post.id), - post.deleted.isFalse() - ) + .where(builder) .orderBy(post.id.desc()) .limit(pageable.getPageSize() + 1) .fetch(); diff --git a/src/main/java/com/chooz/post/persistence/PostRepositoryImpl.java b/src/main/java/com/chooz/post/persistence/PostRepositoryImpl.java index ab9af2fb..6432f971 100644 --- a/src/main/java/com/chooz/post/persistence/PostRepositoryImpl.java +++ b/src/main/java/com/chooz/post/persistence/PostRepositoryImpl.java @@ -66,13 +66,13 @@ public Optional findCommentActiveByPostId(Long postId) { } @Override - public Slice findPostsWithVoteCountByUserId(Long userId, Long postId, Pageable pageable) { - return postQueryDslRepository.findPostsWithVoteCountByUserId(userId, postId, pageable); + public Slice findPostsWithVoteCountByUserId(Long userId, Long authorId, Long postId, Pageable pageable) { + return postQueryDslRepository.findPostsWithVoteCountByUserId(userId, authorId, postId, pageable); } @Override - public Slice findVotedPostsWithVoteCount(Long userId, Long postId, Pageable pageable) { - return postQueryDslRepository.findVotedPostsWithVoteCount(userId, postId, pageable); + public Slice findVotedPostsWithVoteCount(Long userId, Long authorId, Long postId, Pageable pageable) { + return postQueryDslRepository.findVotedPostsWithVoteCount(userId, authorId, postId, pageable); } @Override diff --git a/src/main/java/com/chooz/post/presentation/PostController.java b/src/main/java/com/chooz/post/presentation/PostController.java index 565d3218..1c7b2e7f 100644 --- a/src/main/java/com/chooz/post/presentation/PostController.java +++ b/src/main/java/com/chooz/post/presentation/PostController.java @@ -9,6 +9,7 @@ import com.chooz.post.presentation.dto.UpdatePostRequest; import com.chooz.post.presentation.dto.MyPagePostResponse; import com.chooz.post.presentation.dto.FeedResponse; +import com.chooz.post.presentation.dto.UpdatePostResponse; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; @@ -44,12 +45,13 @@ public ResponseEntity createPost( @GetMapping("/{postId}") public ResponseEntity findPostById( @PathVariable("postId") Long postId, + @RequestParam(value = "shareKey", required = false ) String shareKey, @AuthenticationPrincipal UserInfo userInfo ) { Long userId = Optional.ofNullable(userInfo) .map(UserInfo::userId) .orElse(null); - return ResponseEntity.ok(postService.findById(userId, postId)); + return ResponseEntity.ok(postService.findById(userId, postId, shareKey)); } @GetMapping("/shareUrl/{shareUrl}") @@ -102,20 +104,22 @@ public ResponseEntity deletePost( @GetMapping("/users/{userId}") public ResponseEntity> findMyPosts( - @PathVariable("userId") Long userId, + @PathVariable("userId") Long myPageUserId, + @AuthenticationPrincipal UserInfo userInfo, @RequestParam(name = "cursor", required = false) @Min(0) Long cursor, @RequestParam(name = "size", required = false, defaultValue = "10") @Min(1) int size ) { - return ResponseEntity.ok(postService.findUserPosts(userId, cursor, size)); + return ResponseEntity.ok(postService.findUserPosts(userInfo.userId(), myPageUserId, cursor, size)); } @GetMapping("/users/{userId}/voted") public ResponseEntity> findVotedPosts( - @PathVariable("userId") Long userId, + @PathVariable("userId") Long myPageUserId, + @AuthenticationPrincipal UserInfo userInfo, @RequestParam(name = "cursor", required = false) @Min(0) Long cursor, @RequestParam(name = "size", required = false, defaultValue = "10") @Min(1) int size ) { - return ResponseEntity.ok(postService.findVotedPosts(userId, cursor, size)); + return ResponseEntity.ok(postService.findVotedPosts(userInfo.userId(), myPageUserId, cursor, size)); } @GetMapping("/feed") diff --git a/src/main/java/com/chooz/post/presentation/UpdatePostResponse.java b/src/main/java/com/chooz/post/presentation/dto/UpdatePostResponse.java similarity index 89% rename from src/main/java/com/chooz/post/presentation/UpdatePostResponse.java rename to src/main/java/com/chooz/post/presentation/dto/UpdatePostResponse.java index 95811165..e3dd4b10 100644 --- a/src/main/java/com/chooz/post/presentation/UpdatePostResponse.java +++ b/src/main/java/com/chooz/post/presentation/dto/UpdatePostResponse.java @@ -1,12 +1,9 @@ -package com.chooz.post.presentation; +package com.chooz.post.presentation.dto; import com.chooz.post.domain.CloseOption; import com.chooz.post.domain.PollOption; import com.chooz.post.domain.Post; import com.chooz.post.domain.Status; -import com.chooz.post.presentation.dto.CloseOptionDto; -import com.chooz.post.presentation.dto.PollChoiceResponse; -import com.chooz.post.presentation.dto.PollOptionDto; import java.time.LocalDateTime; import java.util.List; diff --git a/src/test/java/com/chooz/comment/application/CommentQueryServiceTest.java b/src/test/java/com/chooz/comment/application/CommentQueryServiceTest.java index 65b4388c..6960b375 100644 --- a/src/test/java/com/chooz/comment/application/CommentQueryServiceTest.java +++ b/src/test/java/com/chooz/comment/application/CommentQueryServiceTest.java @@ -20,7 +20,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -122,7 +121,7 @@ void findComments20Cursor11() { void findCommentsCloseCommentActive() { // given User user = userRepository.save(UserFixture.createDefaultUser()); - PollOption pollOption = PostFixture.createPollOptionBuilder() + PollOption pollOption = PostFixture.pollOptionBuilder() .commentActive(CommentActive.CLOSED).build(); Post post = postRepository.save(PostFixture.createPostBuilder() .userId(user.getId()) diff --git a/src/test/java/com/chooz/notification/application/CommentLikeNotificationListenerTest.java b/src/test/java/com/chooz/notification/application/CommentLikeNotificationListenerTest.java index 02947488..3545ae53 100644 --- a/src/test/java/com/chooz/notification/application/CommentLikeNotificationListenerTest.java +++ b/src/test/java/com/chooz/notification/application/CommentLikeNotificationListenerTest.java @@ -6,14 +6,18 @@ import com.chooz.notification.application.web.dto.NotificationDto; import com.chooz.notification.domain.NotificationQueryRepository; 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; import com.chooz.support.fixture.PostFixture; import com.chooz.support.fixture.UserFixture; 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; @@ -29,7 +33,13 @@ class CommentLikeNotificationListenerTest extends IntegrationTest { UserRepository userRepository; @Autowired - PostRepository postRepository; + PostJpaRepository postRepository; + + @Autowired + VoteJpaRepository voteRepository; + + @Autowired + PollChoiceRepository pollChoiceRepository; @Autowired CommentRepository commentRepository; @@ -40,6 +50,14 @@ class CommentLikeNotificationListenerTest extends IntegrationTest { @Autowired CommentLikeService commentLikeService; + @AfterEach + void tearDown() { + voteRepository.deleteAllInBatch(); + pollChoiceRepository.deleteAllInBatch(); + postRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + @Test @DisplayName("댓글좋아요 알림") void onCommentLiked() throws Exception { diff --git a/src/test/java/com/chooz/notification/application/MyPostClosedNotificationListenerTest.java b/src/test/java/com/chooz/notification/application/MyPostClosedNotificationListenerTest.java index 561516db..a4ed8d5c 100644 --- a/src/test/java/com/chooz/notification/application/MyPostClosedNotificationListenerTest.java +++ b/src/test/java/com/chooz/notification/application/MyPostClosedNotificationListenerTest.java @@ -8,8 +8,10 @@ import com.chooz.post.application.PostCommandService; import com.chooz.post.application.PostVotedEventListener; 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; import com.chooz.support.fixture.UserFixture; @@ -18,6 +20,8 @@ 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; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -35,10 +39,13 @@ class MyPostClosedNotificationListenerTest extends IntegrationTest { UserRepository userRepository; @Autowired - PostRepository postRepository; + PostJpaRepository postRepository; @Autowired - VoteRepository voteRepository; + VoteJpaRepository voteRepository; + + @Autowired + PollChoiceRepository pollChoiceRepository; @Autowired NotificationQueryRepository notificationQueryRepository; @@ -52,6 +59,14 @@ class MyPostClosedNotificationListenerTest extends IntegrationTest { @Autowired PostCommandService postCommandService; + @AfterEach + void tearDown() { + voteRepository.deleteAllInBatch(); + pollChoiceRepository.deleteAllInBatch(); + postRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + @Test @DisplayName("내 투표 마감 알림(참여자 수 마감)") void onMyPostClosedByVoter() throws Exception { diff --git a/src/test/java/com/chooz/notification/application/PostClosedNotificationListenerTest.java b/src/test/java/com/chooz/notification/application/PostClosedNotificationListenerTest.java index ece5368a..36215bb0 100644 --- a/src/test/java/com/chooz/notification/application/PostClosedNotificationListenerTest.java +++ b/src/test/java/com/chooz/notification/application/PostClosedNotificationListenerTest.java @@ -7,8 +7,10 @@ import com.chooz.post.application.PostCommandService; import com.chooz.post.application.PostVotedEventListener; 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; import com.chooz.support.fixture.UserFixture; @@ -17,6 +19,8 @@ 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; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -35,10 +39,13 @@ class PostClosedNotificationListenerTest extends IntegrationTest { UserRepository userRepository; @Autowired - PostRepository postRepository; + PostJpaRepository postRepository; @Autowired - VoteRepository voteRepository; + VoteJpaRepository voteRepository; + + @Autowired + PollChoiceRepository pollChoiceRepository; @Autowired NotificationQueryRepository notificationQueryRepository; @@ -52,6 +59,14 @@ class PostClosedNotificationListenerTest extends IntegrationTest { @Autowired PostCommandService postCommandService; + @AfterEach + void tearDown() { + voteRepository.deleteAllInBatch(); + pollChoiceRepository.deleteAllInBatch(); + postRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + @Test @DisplayName("투표 마감 알림(참여자 수 마감)") void onPostClosedByVoter() throws Exception { diff --git a/src/test/java/com/chooz/notification/application/VotedNotificationListenerTest.java b/src/test/java/com/chooz/notification/application/VotedNotificationListenerTest.java index b55fa3de..bdc913d7 100644 --- a/src/test/java/com/chooz/notification/application/VotedNotificationListenerTest.java +++ b/src/test/java/com/chooz/notification/application/VotedNotificationListenerTest.java @@ -4,14 +4,18 @@ import com.chooz.notification.domain.NotificationQueryRepository; import com.chooz.notification.domain.TargetType; 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; import com.chooz.support.fixture.UserFixture; import com.chooz.user.domain.User; import com.chooz.user.domain.UserRepository; import com.chooz.vote.application.VoteService; +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; @@ -29,7 +33,10 @@ class VotedNotificationListenerTest extends IntegrationTest { UserRepository userRepository; @Autowired - PostRepository postRepository; + PostJpaRepository postRepository; + + @Autowired + VoteJpaRepository voteRepository; @Autowired VoteService voteService; @@ -37,6 +44,17 @@ class VotedNotificationListenerTest extends IntegrationTest { @Autowired NotificationQueryRepository notificationQueryRepository; + @Autowired + PollChoiceRepository pollChoiceRepository; + + @AfterEach + void tearDown() { + voteRepository.deleteAllInBatch(); + pollChoiceRepository.deleteAllInBatch(); + postRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + } + @Test @DisplayName("투표참여 알림") void onVoted() throws Exception { diff --git a/src/test/java/com/chooz/post/application/PostQueryServiceTest.java b/src/test/java/com/chooz/post/application/PostQueryServiceTest.java index 9a0973e6..f6791a5e 100644 --- a/src/test/java/com/chooz/post/application/PostQueryServiceTest.java +++ b/src/test/java/com/chooz/post/application/PostQueryServiceTest.java @@ -3,7 +3,14 @@ import com.chooz.comment.domain.Comment; import com.chooz.comment.domain.CommentRepository; import com.chooz.common.dto.CursorBasePaginatedResponse; -import com.chooz.post.domain.*; +import com.chooz.common.exception.BadRequestException; +import com.chooz.common.exception.ErrorCode; +import com.chooz.post.domain.CommentActive; +import com.chooz.post.domain.PollOption; +import com.chooz.post.domain.PollType; +import com.chooz.post.domain.Post; +import com.chooz.post.domain.PostRepository; +import com.chooz.post.domain.Scope; import com.chooz.post.presentation.dto.FeedResponse; import com.chooz.post.presentation.dto.MyPagePostResponse; import com.chooz.post.presentation.dto.PollChoiceVoteResponse; @@ -33,6 +40,8 @@ import static com.chooz.support.fixture.UserFixture.createUserBuilder; import static com.chooz.support.fixture.VoteFixture.createDefaultVote; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; class PostQueryServiceTest extends IntegrationTest { @@ -67,7 +76,7 @@ void findById() throws Exception { Vote vote = voteRepository.save(VoteFixture.createDefaultVote(user1.getId(), post.getId(), post.getPollChoices().get(0).getId())); //when - PostResponse response = postService.findById(user1.getId(), post.getId()); + PostResponse response = postService.findById(user1.getId(), post.getId(), "shareKey"); //then List pollChoices = response.pollChoices(); @@ -91,6 +100,66 @@ void findById() throws Exception { ); } + @Test + @DisplayName("게시글 조회 - 공개 범위 PUBLIC") + void findById_public() throws Exception { + //given + User author = userRepository.save(createDefaultUser()); + User otherUser = userRepository.save(createDefaultUser()); + String shareKey = "shareKey"; + String otherKey = "otherKey"; + Post post = postRepository.save(PostFixture.createPostBuilder() + .shareUrl(shareKey) + .userId(author.getId()) + .pollOption(PostFixture.pollOptionBuilder().scope(Scope.PUBLIC).build()) + .build()); + + //when then + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), shareKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), otherKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), null)); + assertThatNoException() + .isThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), shareKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), otherKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), null)); + } + + @Test + @DisplayName("게시글 조회 - 공개 범위 PRIVATE") + void findById_private() throws Exception { + //given + User author = userRepository.save(createDefaultUser()); + User otherUser = userRepository.save(createDefaultUser()); + String shareKey = "shareKey"; + String otherKey = "otherKey"; + Post post = postRepository.save(PostFixture.createPostBuilder() + .shareUrl(shareKey) + .userId(author.getId()) + .pollOption(PostFixture.pollOptionBuilder().scope(Scope.PRIVATE).build()) + .build()); + + //when then + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), shareKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), otherKey)); + assertThatNoException() + .isThrownBy(() -> postService.findById(author.getId(), post.getId(), null)); + assertThatNoException() + .isThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), shareKey)); + assertThatThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), otherKey)) + .isInstanceOf(BadRequestException.class) + .hasMessage(ErrorCode.POST_NOT_REVEALABLE.getMessage()); + assertThatThrownBy(() -> postService.findById(otherUser.getId(), post.getId(), null)) + .isInstanceOf(BadRequestException.class) + .hasMessage(ErrorCode.POST_NOT_REVEALABLE.getMessage()); + } + @Test @DisplayName("유저가 작성한 게시글 조회 - 커서 null인 경우") void findUserPosts() throws Exception { @@ -100,7 +169,7 @@ void findUserPosts() throws Exception { int size = 10; //when - var response = postService.findUserPosts(user.getId(), null, size); + var response = postService.findUserPosts(user.getId(), user.getId(), null, size); //then assertAll( @@ -119,7 +188,7 @@ void findUserPosts2() throws Exception { int size = 10; //when - var response = postService.findUserPosts(user.getId(), posts.get(3).getId(), size); + var response = postService.findUserPosts(user.getId(), user.getId(), posts.get(3).getId(), size); //then assertAll( @@ -150,7 +219,7 @@ void findUserPosts_multiple() { voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post2.getId(), post2.getPollChoices().get(0).getId())); //when - var response = postService.findUserPosts(user.getId(), null, 10); + var response = postService.findUserPosts(user.getId(), user.getId(), null, 10); //then List data = response.data(); @@ -194,7 +263,7 @@ void findUserPosts_multiple2() { voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post.getId(), post.getPollChoices().get(0).getId())); //when - var response = postService.findUserPosts(user.getId(), null, 10); + var response = postService.findUserPosts(user.getId(), user.getId(), null, 10); //then List data = response.data(); @@ -225,7 +294,7 @@ void findVotedPosts() throws Exception { int size = 10; //when - var response = postService.findVotedPosts(user.getId(), null, size); + var response = postService.findVotedPosts(user.getId(), user.getId(), null, size); //then int 전체_15개에서_맨_마지막_데이터_인덱스 = posts.size() - size; @@ -256,9 +325,9 @@ void findVotedPosts_multiple() { //유저1 게시글2 투표 후 취소 voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post2.getId(), post2.getPollChoices().get(1).getId())); voteService.vote(user.getId(), post2.getId(), List.of()); - + //when - var response = postService.findVotedPosts(user.getId(), null, 10); + var response = postService.findVotedPosts(user.getId(), user.getId(), null, 10); //then List data = response.data(); @@ -294,7 +363,7 @@ void findVotedPosts_multiple2() { voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post.getId(), post.getPollChoices().get(0).getId())); //when - var response = postService.findVotedPosts(user.getId(), null, 10); + var response = postService.findVotedPosts(user.getId(), user.getId(), null, 10); //then List data = response.data(); @@ -312,6 +381,65 @@ void findVotedPosts_multiple2() { ); } + @Test + @DisplayName("마이페이지 게시글 공개 범위 - 본인인 경우") + void scope_author() { + //given + User user = userRepository.save(UserFixture.createDefaultUser()); + Post publicPost = postRepository.save(PostFixture.createPostBuilder() + .userId(user.getId()) + .pollOption(PostFixture.pollOptionBuilder() + .scope(Scope.PUBLIC) + .build()) + .build()); + Post privatePost = postRepository.save(PostFixture.createPostBuilder() + .userId(user.getId()) + .pollOption(PostFixture.pollOptionBuilder() + .scope(Scope.PRIVATE) + .build()) + .build()); + //유저1 본인 게시글 1 2 투표 + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), publicPost.getId(), publicPost.getPollChoices().get(0).getId())); + + //when + var response1 = postService.findVotedPosts(user.getId(), user.getId(), null, 10); + var response2 = postService.findUserPosts(user.getId(), user.getId(), null, 10); + + //then + assertThat(response1.data()).hasSize(1); + assertThat(response2.data()).hasSize(2); + } + + @Test + @DisplayName("마이페이지 게시글 공개 범위 - 다른 사람인 경우") + void scope_otherUser() { + //given + User author = userRepository.save(UserFixture.createDefaultUser()); + User user = userRepository.save(UserFixture.createDefaultUser()); + Post publicPost = postRepository.save(PostFixture.createPostBuilder() + .userId(author.getId()) + .pollOption(PostFixture.pollOptionBuilder() + .scope(Scope.PUBLIC) + .build()) + .build()); + Post privatePost = postRepository.save(PostFixture.createPostBuilder() + .userId(author.getId()) + .pollOption(PostFixture.pollOptionBuilder() + .scope(Scope.PRIVATE) + .build()) + .build()); + //유저1 본인 게시글 1 2 투표 + voteRepository.save(VoteFixture.createDefaultVote(author.getId(), privatePost.getId(), privatePost.getPollChoices().get(0).getId())); + + //when + var response1 = postService.findVotedPosts(user.getId(), author.getId(), null, 10); + var response2 = postService.findUserPosts(user.getId(), author.getId(), null, 10); + + //then + assertThat(response1.data()).hasSize(0); + assertThat(response2.data()).hasSize(1); + } + @Test @DisplayName("피드 조회 - 내 게시글 1개, 공개 게시글 15개, 투표 10개, 댓글 20개") void findFeed() throws Exception { @@ -345,7 +473,7 @@ void findFeed() throws Exception { private List createPosts(User user, int size) { List posts = new ArrayList<>(); - for (int i = 0; i < size; i ++) { + for (int i = 0; i < size; i++) { Post post = postRepository.save(createDefaultPost(user.getId())); posts.add(post); thumbnailRepository.save(createDefaultThumbnail(post.getId(), post.getPollChoices().get(0).getId())); @@ -355,7 +483,7 @@ private List createPosts(User user, int size) { private List createPostsWithScope(User user, Scope scope, int size) { List posts = new ArrayList<>(); - for (int i = 0; i < size; i ++) { + for (int i = 0; i < size; i++) { Post post = createPostBuilder() .userId(user.getId()) .pollOption(PollOption.create(PollType.SINGLE, scope, CommentActive.OPEN)) diff --git a/src/test/java/com/chooz/post/domain/PostRepositoryTest.java b/src/test/java/com/chooz/post/domain/PostRepositoryTest.java index c50523b1..580b17f3 100644 --- a/src/test/java/com/chooz/post/domain/PostRepositoryTest.java +++ b/src/test/java/com/chooz/post/domain/PostRepositoryTest.java @@ -162,6 +162,7 @@ void findPostsWithVoteCountByUserId() throws Exception { // when Slice result = postRepository.findPostsWithVoteCountByUserId( + user1.getId(), user1.getId(), null, PageRequest.of(0, 10) @@ -188,7 +189,7 @@ void findVotedPostsWithVoteCount() throws Exception { Post post1 = postRepository.save(PostFixture.createDefaultPost(user2.getId())); Post post2 = postRepository.save(PostFixture.createDefaultPost(user2.getId())); Post post3 = postRepository.save(PostFixture.createDefaultPost(user2.getId())); - Post post4 = postRepository.save(PostFixture.createDefaultPost(user3.getId())); + Post post4 = postRepository.save(PostFixture.createDefaultPost(user2.getId())); List post1Choices = post1.getPollChoices(); List post2Choices = post2.getPollChoices(); @@ -214,6 +215,7 @@ void findVotedPostsWithVoteCount() throws Exception { // when Slice result = postRepository.findVotedPostsWithVoteCount( + user1.getId(), user1.getId(), null, PageRequest.of(0, 10) @@ -229,6 +231,54 @@ void findVotedPostsWithVoteCount() throws Exception { ); } + @Test + @DisplayName("본인의 마이페이지를 보는 경우, hasNext가 true여야 함") + void findPostsWithVoteCountByUserId_hasNext_true() throws Exception { + // given + User user1 = userRepository.save(UserFixture.createDefaultUser()); + + // 비공개 3개, 공개 9개 + createPostsWithScope(user1, Scope.PRIVATE, 3); + List publicPosts = createPostsWithScope(user1, Scope.PUBLIC, 9); + + voteRepository.save(VoteFixture.createDefaultVote(user1.getId(), publicPosts.getFirst().getId(), publicPosts.getFirst().getPollChoices().getFirst().getId())); + + // when + Slice result = postRepository.findPostsWithVoteCountByUserId( + user1.getId(), + user1.getId(), + null, + PageRequest.of(0, 10) + ); + + // then + assertThat(result.getContent()).hasSize(10); + assertThat(result.hasNext()).isTrue(); + } + + @Test + @DisplayName("다른 사람의 마이페이지를 보는 경우, hasNext가 false여야 함") + void findPostsWithVoteCountByUserId_hasNext_false() throws Exception { + // given + User user1 = userRepository.save(UserFixture.createDefaultUser()); + User user2 = userRepository.save(UserFixture.createDefaultUser()); + + // 비공개 3개, 공개 9개 + createPostsWithScope(user1, Scope.PRIVATE, 3); + createPostsWithScope(user1, Scope.PUBLIC, 9); + + // when + Slice result = postRepository.findPostsWithVoteCountByUserId( + user2.getId(), + user1.getId(), + null, + PageRequest.of(0, 10) + ); + + // then + assertThat(result.getContent()).hasSize(9); + assertThat(result.hasNext()).isFalse(); + } private List createPosts(long userId, int size) { List posts = new ArrayList<>(); diff --git a/src/test/java/com/chooz/post/domain/PostTest.java b/src/test/java/com/chooz/post/domain/PostTest.java index 9235af1d..692aef86 100644 --- a/src/test/java/com/chooz/post/domain/PostTest.java +++ b/src/test/java/com/chooz/post/domain/PostTest.java @@ -3,19 +3,17 @@ import com.chooz.common.exception.BadRequestException; import com.chooz.common.exception.ErrorCode; import com.chooz.support.fixture.PostFixture; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; -import static com.chooz.support.fixture.PostFixture.SELF_CREATE_OPTION; import static com.chooz.support.fixture.PostFixture.createDefaultPost; import static com.chooz.support.fixture.PostFixture.createPostBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertAll; class PostTest { @@ -177,4 +175,56 @@ void closeByAuthor_onlySelfCanClose() throws Exception { .isInstanceOf(BadRequestException.class) .hasMessage(ErrorCode.ONLY_SELF_CAN_CLOSE.getMessage()); } + + @Test + @DisplayName("공개 범위 - public") + void isRevealable_public() throws Exception { + // given + long author = 1L; + long otherUser = 2L; + String shareKey = "key"; + Post post = createPostBuilder() + .userId(author) + .shareUrl(shareKey) + .pollOption(PostFixture.pollOptionBuilder().scope(Scope.PUBLIC).build()) + .build(); + + // when + boolean res1 = post.isRevealable(author, shareKey); //본인, 키 같음 + boolean res2 = post.isRevealable(author, shareKey + 1); //본인, 키 다름 + boolean res3 = post.isRevealable(otherUser, shareKey); //다른 유저, 키 같음 + boolean res4 = post.isRevealable(otherUser, shareKey + 1); //다른 유저, 키 다름 + + // then + assertThat(res1).isTrue(); + assertThat(res2).isTrue(); + assertThat(res3).isTrue(); + assertThat(res4).isTrue(); + } + + @Test + @DisplayName("공개 범위 - private") + void isRevealable_private() throws Exception { + // given + long author = 1L; + long otherUser = 2L; + String shareKey = "key"; + Post post = createPostBuilder() + .userId(author) + .shareUrl(shareKey) + .pollOption(PostFixture.pollOptionBuilder().scope(Scope.PRIVATE).build()) + .build(); + + // when + boolean res1 = post.isRevealable(author, shareKey); //본인, 키 같음 + boolean res2 = post.isRevealable(author, shareKey + 1); //본인, 키 다름 + boolean res3 = post.isRevealable(otherUser, shareKey); //다른 유저, 키 같음 + boolean res4 = post.isRevealable(otherUser, shareKey + 1); //다른 유저, 키 다름 + + // then + assertThat(res1).isTrue(); + assertThat(res2).isTrue(); + assertThat(res3).isTrue(); + assertThat(res4).isFalse(); + } } diff --git a/src/test/java/com/chooz/post/presentation/PostControllerTest.java b/src/test/java/com/chooz/post/presentation/PostControllerTest.java index 907238a4..7f890776 100644 --- a/src/test/java/com/chooz/post/presentation/PostControllerTest.java +++ b/src/test/java/com/chooz/post/presentation/PostControllerTest.java @@ -19,6 +19,7 @@ import com.chooz.post.presentation.dto.PollOptionDto; import com.chooz.post.presentation.dto.PostResponse; import com.chooz.post.presentation.dto.UpdatePostRequest; +import com.chooz.post.presentation.dto.UpdatePostResponse; import com.chooz.support.RestDocsTest; import com.chooz.support.WithMockUserInfo; import org.junit.jupiter.api.DisplayName; @@ -231,17 +232,21 @@ void findPost() throws Exception { LocalDateTime.of(2025, 2, 13, 12, 0) ); //given - given(postService.findById(any(), any())) + given(postService.findById(any(), any(), any())) .willReturn(response); //when then - mockMvc.perform(RestDocumentationRequestBuilders.get("/posts/{postId}", "1")) + mockMvc.perform(RestDocumentationRequestBuilders.get("/posts/{postId}", "1") + .param("shareKey", "shareKey")) .andExpect(status().isOk()) .andExpect(content().json(objectMapper.writeValueAsString(response))) .andDo(restDocs.document( pathParameters( parameterWithName("postId").description("게시글 Id") ), + queryParameters( + parameterWithName("shareKey").description("공유 키").optional() + ), responseFields( fieldWithPath("id").type(JsonFieldType.NUMBER).description("게시글 Id"), fieldWithPath("title").type(JsonFieldType.STRING).description("게시글 제목"), @@ -312,7 +317,7 @@ void findMyPost() throws Exception { ) ) ); - given(postService.findUserPosts(1L, null, 10)) + given(postService.findUserPosts(1L, 1L, null, 10)) .willReturn(response); //when then @@ -414,7 +419,7 @@ void findVotedPost() throws Exception { ) ) ); - given(postService.findVotedPosts(1L, null, 10)) + given(postService.findVotedPosts(1L, 1L, null, 10)) .willReturn(response); //when then diff --git a/src/test/java/com/chooz/support/fixture/PostFixture.java b/src/test/java/com/chooz/support/fixture/PostFixture.java index 25958fd9..391adb73 100644 --- a/src/test/java/com/chooz/support/fixture/PostFixture.java +++ b/src/test/java/com/chooz/support/fixture/PostFixture.java @@ -67,7 +67,7 @@ public static CloseOption voterCloseOption(int maxVoterCount) { public static final CloseOption SELF_CREATE_OPTION = new CloseOption(CloseType.SELF, null, null); - public static PollOption.PollOptionBuilder createPollOptionBuilder() { + public static PollOption.PollOptionBuilder pollOptionBuilder() { return PollOption.builder() .pollType(PollType.SINGLE) .scope(Scope.PUBLIC) @@ -75,7 +75,7 @@ public static PollOption.PollOptionBuilder createPollOptionBuilder() { } public static PollOption multiplePollOption() { - return createPollOptionBuilder() + return pollOptionBuilder() .pollType(PollType.MULTIPLE) .build(); } diff --git a/src/test/java/com/chooz/vote/application/VoteConcurrentTest.java b/src/test/java/com/chooz/vote/application/VoteConcurrentTest.java index 5cf1b35f..d4b924e7 100644 --- a/src/test/java/com/chooz/vote/application/VoteConcurrentTest.java +++ b/src/test/java/com/chooz/vote/application/VoteConcurrentTest.java @@ -24,8 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@ActiveProfiles("mysql") -@SpringBootTest +//@ActiveProfiles("mysql") +//@SpringBootTest class VoteConcurrentTest { @Autowired diff --git a/src/test/java/com/chooz/vote/application/VoteServiceTest.java b/src/test/java/com/chooz/vote/application/VoteServiceTest.java index b541ae3e..ce7e4083 100644 --- a/src/test/java/com/chooz/vote/application/VoteServiceTest.java +++ b/src/test/java/com/chooz/vote/application/VoteServiceTest.java @@ -51,7 +51,7 @@ void singleVote() { Post post = postRepository.save( PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.SINGLE) .build()) .build() @@ -79,7 +79,7 @@ void singleVote_change() { Post post = postRepository.save( PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.SINGLE) .build()) .build()); @@ -103,7 +103,7 @@ void singleVote_cancelByEmptyChoice() { User user = userRepository.save(UserFixture.createDefaultUser()); Post post = postRepository.save( PostFixture.createPostBuilder() - .pollOption(PostFixture.createPollOptionBuilder().pollType(PollType.SINGLE).build()) + .pollOption(PostFixture.pollOptionBuilder().pollType(PollType.SINGLE).build()) .build() ); Long pollChoiceId = post.getPollChoices().getFirst().getId(); @@ -125,7 +125,7 @@ void multipleVote_atOnce() { Post post = postRepository.save( PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.MULTIPLE) .build()) .build() @@ -156,7 +156,7 @@ void multipleVote_changeChoices() { PostFixture.createPollChoice(), PostFixture.createPollChoice()) ) - .pollOption(PostFixture.createPollOptionBuilder() + .pollOption(PostFixture.pollOptionBuilder() .pollType(PollType.MULTIPLE) .build()) .build() @@ -227,7 +227,7 @@ void singleVote_multipleChoicesException() { Post post = postRepository.save( PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.SINGLE) .build()) .build() @@ -248,7 +248,7 @@ void multipleVote_duplicateChoicesException() { Post post = postRepository.save( PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.MULTIPLE) .build()) .build() @@ -269,7 +269,7 @@ void multipleVote_cancelAllChoices() { User user = userRepository.save(UserFixture.createDefaultUser()); Post post = postRepository.save( PostFixture.createPostBuilder() - .pollOption(PostFixture.createPollOptionBuilder().pollType(PollType.MULTIPLE).build()) + .pollOption(PostFixture.pollOptionBuilder().pollType(PollType.MULTIPLE).build()) .build() ); List pollChoices = post.getPollChoices(); diff --git a/src/test/java/com/chooz/vote/application/VoteValidatorTest.java b/src/test/java/com/chooz/vote/application/VoteValidatorTest.java index b558a430..b3c25663 100644 --- a/src/test/java/com/chooz/vote/application/VoteValidatorTest.java +++ b/src/test/java/com/chooz/vote/application/VoteValidatorTest.java @@ -105,7 +105,7 @@ void validateSingleVote_multipleChoices() { // given Post post = PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.SINGLE) .build() ) @@ -124,7 +124,7 @@ void validateMultipleVotes_duplicateChoices() { // given Post post = PostFixture.createPostBuilder() .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.MULTIPLE) .build() ) diff --git a/src/test/java/com/chooz/vote/domain/VoteRepositoryTest.java b/src/test/java/com/chooz/vote/domain/VoteRepositoryTest.java index 6b5a016f..a6587c26 100644 --- a/src/test/java/com/chooz/vote/domain/VoteRepositoryTest.java +++ b/src/test/java/com/chooz/vote/domain/VoteRepositoryTest.java @@ -53,7 +53,7 @@ void countVoterByPostId_multiple() throws Exception { Post post = postRepository.save(PostFixture.createPostBuilder() .userId(user1.getId()) .pollOption( - PostFixture.createPollOptionBuilder() + PostFixture.pollOptionBuilder() .pollType(PollType.MULTIPLE) .build()) .build());