diff --git a/src/main/java/com/moongeul/backend/api/member/controller/MemberController.java b/src/main/java/com/moongeul/backend/api/member/controller/MemberController.java index d0747ea..ef2f0f2 100644 --- a/src/main/java/com/moongeul/backend/api/member/controller/MemberController.java +++ b/src/main/java/com/moongeul/backend/api/member/controller/MemberController.java @@ -156,6 +156,34 @@ public ResponseEntity> getCategoryPostL return ApiResponse.success(SuccessStatus.GET_CATEGORY_POST_LIST_SUCCESS, categoryPostListResponseDTO); } + @Operation( + summary = "공감한 기록 리스트 조회 API (마이페이지)", + description = "사용자가 공감한 기록 리스트를 조회합니다. userId 쿼리 파라미터가 없으면 본인, 있으면 해당 사용자의 공감 기록을 조회합니다. " + + "최신순, 오래된순, 평점 높은순, 평점 낮은순으로 정렬할 수 있습니다." + + "

[enum] 정렬 옵션 (sortBy):" + + "
- LATEST: 최신순 (기본값)" + + "
- OLDEST: 오래된순" + + "
- RATING_HIGH: 평점 높은순" + + "
- RATING_LOW: 평점 낮은순" + ) + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "공감한 기록 리스트 조회 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "해당 사용자의 정보는 공개되지 않습니다."), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "해당 사용자를 찾을 수 없습니다.") + }) + @GetMapping("/liked-posts") + public ResponseEntity> getLikedPostList( + @AuthenticationPrincipal UserDetails userDetails, + @RequestParam(required = false) Long userId, + @RequestParam(defaultValue = "LATEST") String sortBy, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size) { + + CategoryPostListResponseDTO likedPostListResponseDTO = + memberService.getLikedPostList(userDetails.getUsername(), userId, sortBy, page, size); + return ApiResponse.success(SuccessStatus.GET_LIKED_POST_LIST_SUCCESS, likedPostListResponseDTO); + } + @Operation( summary = "마이페이지 질문 리스트 조회 API", description = "사용자가 작성한 질문 리스트를 페이징하여 조회합니다. userId 쿼리파라미터가 없으면 본인 질문, 있으면 해당 사용자의 질문을 조회합니다." diff --git a/src/main/java/com/moongeul/backend/api/member/service/MemberService.java b/src/main/java/com/moongeul/backend/api/member/service/MemberService.java index 37ceca2..e9e9fd6 100644 --- a/src/main/java/com/moongeul/backend/api/member/service/MemberService.java +++ b/src/main/java/com/moongeul/backend/api/member/service/MemberService.java @@ -359,6 +359,50 @@ public CategoryPostListResponseDTO getCategoryPostList(String email, Long userId .build(); } + // 공감한 기록 리스트 조회 + @Transactional(readOnly = true) + public CategoryPostListResponseDTO getLikedPostList(String email, Long userId, String sortBy, Integer page, Integer size) { + + Member currentMember = getMemberByEmail(email); + Member targetMember = (userId == null) + ? currentMember + : memberRepository.findById(userId) + .orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage())); + + validatePrivacyAccess(currentMember, targetMember); + + Pageable pageable = PageRequest.of(page - 1, size); + + Page postPage = switch (sortBy.toUpperCase()) { + case "LATEST" -> + postRepository.findLikedPostsByMemberIdOrderByCreatedAtDesc(targetMember.getId(), pageable); + case "OLDEST" -> + postRepository.findLikedPostsByMemberIdOrderByCreatedAtAsc(targetMember.getId(), pageable); + case "RATING_HIGH" -> + postRepository.findLikedPostsByMemberIdOrderByRatingDesc(targetMember.getId(), pageable); + case "RATING_LOW" -> + postRepository.findLikedPostsByMemberIdOrderByRatingAsc(targetMember.getId(), pageable); + default -> + postRepository.findLikedPostsByMemberIdOrderByCreatedAtDesc(targetMember.getId(), pageable); + }; + + List postList = postPage.getContent().stream() + .map(this::convertToPostDTO) + .collect(Collectors.toList()); + + log.info("공감한 기록 리스트 조회 완료 - 사용자 ID: {}, 정렬: {}, 페이지: {}, 결과 수: {}", + targetMember.getId(), sortBy, page, postList.size()); + + return CategoryPostListResponseDTO.builder() + .total(postPage.getTotalElements()) + .page(page) + .size(size) + .totalPages(postPage.getTotalPages()) + .isLast(postPage.isLast()) + .data(postList) + .build(); + } + // Post를 PostDTO로 변환 private PostDTO convertToPostDTO(Post post) { diff --git a/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java b/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java index 3fffc32..39d82b1 100644 --- a/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java +++ b/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java @@ -84,6 +84,34 @@ List findWeeklyRecommendationByReadingTasteType( @Query("SELECT p FROM Post p WHERE p.category.id = :categoryId ORDER BY p.rating ASC, p.createdAt DESC") Page findByCategoryIdOrderByRatingAsc(@Param("categoryId") Long categoryId, Pageable pageable); + // 사용자가 공감한 기록 조회 (최신순) + @Query(value = "SELECT DISTINCT l.post FROM Likes l " + + "WHERE l.member.id = :memberId " + + "ORDER BY l.post.createdAt DESC", + countQuery = "SELECT COUNT(DISTINCT l.post.id) FROM Likes l WHERE l.member.id = :memberId") + Page findLikedPostsByMemberIdOrderByCreatedAtDesc(@Param("memberId") Long memberId, Pageable pageable); + + // 사용자가 공감한 기록 조회 (오래된순) + @Query(value = "SELECT DISTINCT l.post FROM Likes l " + + "WHERE l.member.id = :memberId " + + "ORDER BY l.post.createdAt ASC", + countQuery = "SELECT COUNT(DISTINCT l.post.id) FROM Likes l WHERE l.member.id = :memberId") + Page findLikedPostsByMemberIdOrderByCreatedAtAsc(@Param("memberId") Long memberId, Pageable pageable); + + // 사용자가 공감한 기록 조회 (평점 높은순) + @Query(value = "SELECT DISTINCT l.post FROM Likes l " + + "WHERE l.member.id = :memberId " + + "ORDER BY l.post.rating DESC, l.post.createdAt DESC", + countQuery = "SELECT COUNT(DISTINCT l.post.id) FROM Likes l WHERE l.member.id = :memberId") + Page findLikedPostsByMemberIdOrderByRatingDesc(@Param("memberId") Long memberId, Pageable pageable); + + // 사용자가 공감한 기록 조회 (평점 낮은순) + @Query(value = "SELECT DISTINCT l.post FROM Likes l " + + "WHERE l.member.id = :memberId " + + "ORDER BY l.post.rating ASC, l.post.createdAt DESC", + countQuery = "SELECT COUNT(DISTINCT l.post.id) FROM Likes l WHERE l.member.id = :memberId") + Page findLikedPostsByMemberIdOrderByRatingAsc(@Param("memberId") Long memberId, Pageable pageable); + // 읽은 날짜 기준 월별 게시글 조회 (일자 오름차순, 같은 일자 내 최신 작성순) @Query("SELECT p FROM Post p JOIN FETCH p.book " + "WHERE p.member = :member AND p.readDate BETWEEN :startDate AND :endDate " + diff --git a/src/main/java/com/moongeul/backend/common/response/SuccessStatus.java b/src/main/java/com/moongeul/backend/common/response/SuccessStatus.java index 638b5c7..1c0c702 100644 --- a/src/main/java/com/moongeul/backend/common/response/SuccessStatus.java +++ b/src/main/java/com/moongeul/backend/common/response/SuccessStatus.java @@ -60,6 +60,7 @@ public enum SuccessStatus { GET_ALL_POST_SUCCESS(HttpStatus.OK, "기록(게시글) 전체 조회 성공"), GET_POST_SUCCESS(HttpStatus.OK, "기록(게시글) 상세 조회 성공"), GET_CATEGORY_POST_LIST_SUCCESS(HttpStatus.OK, "카테고리별 기록 리스트 조회 성공"), + GET_LIKED_POST_LIST_SUCCESS(HttpStatus.OK, "공감한 기록 리스트 조회 성공"), UPDATE_POST_SUCCESS(HttpStatus.OK, "기록(게시글) 수정 성공"), DELETE_POST_SUCCESS(HttpStatus.OK, "기록(게시글) 삭제 성공"), POST_LIKE_SUCCESS(HttpStatus.OK, "기록(게시글) 공감 버튼 등록 성공"),