Skip to content

Commit

Permalink
Feat: 내가 좋아요한 한줄요약 조회 API 구현 (#170)
Browse files Browse the repository at this point in the history
* #166 - refactor: 파라미터 순서 변경

* #166 - feat: 본인의 한줄요약에는 좋아요 할 수 없는 기능 추가

* #166 - feat: 내가 좋아요한 한줄요약 조회 API 구현

* #166 - test: 내가 좋아요한 한줄요약 조회 API 테스트 구현

* #166 - test: 내가 쓴 한줄요약은 좋아요 하지 못하도록 테스트 변경
  • Loading branch information
morenow98 authored Feb 19, 2024
1 parent 4308871 commit e7c36be
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,22 @@ public class SecurityConfig {
"/auth/**"
};

private final String[] REQUIRED_AUTHENTICATE = {
"/posts/likes",
"/posts/me",
"/reviews/likes",
"/reviews/me",
"/books/likes/**"
};

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(HttpMethod.GET, "/posts/likes", "/posts/me", "/books/likes/**").authenticated()
.requestMatchers(HttpMethod.GET, REQUIRED_AUTHENTICATE).authenticated()
.requestMatchers(HttpMethod.GET).permitAll()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public ResponseEntity<PostDetailResponse> getPost(

@GetMapping("/all")
public ResponseEntity<PostListResponse> getAllPost(
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
@AuthenticationPrincipal AuthDetails details
@AuthenticationPrincipal AuthDetails details,
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
) {
if (details == null) {
return ResponseEntity.ok(postService.getAllPost(pageable, DEFAULT_USER_ID));
Expand All @@ -97,8 +97,8 @@ public ResponseEntity<PostListResponse> getAllPost(
public ResponseEntity<PostListResponse> searchPost(
@IsValidIsbn @RequestParam(required = false) String isbn13,
@RequestParam(name = "member-id", required = false) Long memberId,
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
@AuthenticationPrincipal AuthDetails details
@AuthenticationPrincipal AuthDetails details,
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
) {
if (details == null) {
return ResponseEntity.ok(postService.searchPost(isbn13, memberId, DEFAULT_USER_ID, pageable));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ public ResponseEntity<Void> deleteReview(
return ResponseEntity.noContent().build();
}

@GetMapping("/likes")
public ResponseEntity<ReviewListResponse> searchLikeReview(
@AuthenticationPrincipal AuthDetails details,
Pageable pageable
) {
return ResponseEntity.ok(reviewService.searchLikeReview(details.getId(), pageable));
}

@GetMapping("/recommend")
public ResponseEntity<ReviewListResponse> getRecommendReviews(
@RequestParam RecommendType type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,10 @@ public void deleteReview() {
deleted = true;
likeCount = 0;
}

public void validateReviewLike(Member member) {
if (member.getId().equals(this.member.getId())) {
throw new AccessDeniedException("본인의 한줄요약은 좋아요할 수 없습니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@

public interface ReviewRepositoryCustom {
Page<ReviewDto> findPublicReviewWithLikedByIsbn13(String isbn13, Long memberId, Long loginMemberId, Pageable pageable);

Optional<ReviewDetailDto> findPublicReviewDetailByReviewId(Long reviewId, Long memberId);

Page<ReviewDto> findLikeReviewByMemberId(Long memberId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,38 @@ public Optional<ReviewDetailDto> findPublicReviewDetailByReviewId(Long reviewId,
.fetchOne());
}

@Override
public Page<ReviewDto> findLikeReviewByMemberId(Long memberId, Pageable pageable) {
List<ReviewDto> result = queryFactory
.select(
Projections.constructor(
ReviewDto.class,
review.id,
review.member.id,
review.book.id,
review.content,
review.likeCount,
review.viewCount,
Expressions.constant(true),
review.status
)
)
.from(reviewLike)
.join(reviewLike.review, review)
.where(reviewLike.member.id.eq(memberId))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(reviewLike.createdAt.desc())
.fetch();

JPAQuery<Long> countQuery = queryFactory
.select(review.count())
.from(reviewLike)
.where(reviewLike.member.id.eq(memberId));

return PageableExecutionUtils.getPage(result, pageable, countQuery::fetchOne);
}

private BooleanExpression isLikedByMember(Long memberId, NumberPath<Long> reviewId) {
return JPAExpressions.selectOne()
.from(reviewLike)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public Long registerLike(Long reviewId, Long memberId) {
.orElseThrow(() -> new EntityNotFoundException("한줄요약을 찾을 수 없습니다."));
Member member = memberRepository.getReferenceById(memberId);

review.validateReviewLike(member);

ReviewLike reviewLike = ReviewLike.of(member, review);
reviewLike.increaseReviewLikeCount();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ public void deleteReview(Long reviewId, Long memberId) {
review.deleteReview();
}

public ReviewListResponse searchLikeReview(Long memberId, Pageable pageable) {
return ReviewListResponse.fromDto(reviewRepository.findLikeReviewByMemberId(memberId, pageable), memberId);
}

public ReviewListResponse getRecommendReviews(RecommendType type, int start, Long memberId) {
return switch (type) {
case LIKE -> getMostLikeReviews(start, memberId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ void givenLogin_whenSearchingLikePost_thenReturnPostListResponse() throws Except
}

@Test
@DisplayName("로그인 없이 좋아요 요청시 에러를 반환한다.")
@DisplayName("로그인 없이 좋아요한 게시글 요청시 에러를 반환한다.")
void givenNonLogin_whenSearchingLikePost_thenReturnErrorResponse() throws Exception {
//given

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,33 @@ void givenMemberId_whenSearchingReview_thenReturnReviewListResponse() throws Exc
;
}

@Test
@WithCustomMockUser
@DisplayName("유저가 좋아요한 한줄요약을 조회한다.")
void givenLogin_whenSearchingLikeReview_thenReturnReviewListResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/reviews/likes")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.totalResults").value(1))
.andExpect(jsonPath("$.reviewList[0].reviewId").value(2))
;
}

@Test
@DisplayName("로그인 없이 좋아요한 한줄요약 조회시 에러를 반환한다.")
void givenNonLogin_whenSearchingLikeReview_thenReturnErrorResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/reviews/likes")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized())
;
}

@Test
@DisplayName("좋아요가 많은 순으로 한줄요약을 4개 반환한다.")
void givenPageStartAndRecommendType_whenGettingMostLikeReviews_thenReturnMostLikeReviews() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void givenReviewId_whenRegisteringReviewLike_thenRegisterReviewLike() throws Exc
//given

//when & then
mockMvc.perform(post("/reviews/1/likes")
mockMvc.perform(post("/reviews/3/likes")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated())
.andExpect(header().exists("Location"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class ReviewLikeServiceTest {
void givenReviewId_whenRegisteringReviewLike_thenRegisterReviewLike() {
//given
Long reviewId = 1L;
Long memberId = 1L;
Long memberId = 2L;
Review review = createReview(reviewId);
Member member = createMember(memberId);

Expand Down

0 comments on commit e7c36be

Please sign in to comment.