Skip to content

Commit df7671b

Browse files
authored
Merge pull request #15 from 508PERFACT/feature/12-report-list
Feat : 과거 레포트 조회 API 구현
2 parents ba280b9 + 930f76c commit df7671b

File tree

8 files changed

+124
-11
lines changed

8 files changed

+124
-11
lines changed

src/main/java/com/perfact/be/domain/report/converter/ReportConverter.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
import com.perfact.be.domain.news.dto.NewsArticleResponse;
44
import com.perfact.be.domain.report.dto.ClovaResponseDTO;
5+
import com.perfact.be.domain.report.dto.ReportResponseDto;
56
import com.perfact.be.domain.report.entity.Report;
67
import com.perfact.be.domain.report.exception.ReportHandler;
78
import com.perfact.be.domain.report.exception.status.ReportErrorStatus;
89
import com.perfact.be.domain.report.util.ClovaResponseParser;
910
import com.perfact.be.domain.report.util.DateParser;
1011
import com.perfact.be.domain.report.util.UrlParser;
1112
import com.perfact.be.domain.user.entity.User;
13+
import java.util.List;
1214
import lombok.RequiredArgsConstructor;
1315
import lombok.extern.slf4j.Slf4j;
16+
import org.springframework.data.domain.Page;
1417
import org.springframework.stereotype.Component;
1518

1619
@Slf4j
@@ -45,4 +48,29 @@ public Report toReport(ClovaResponseDTO clovaResponse, NewsArticleResponse newsD
4548
throw new ReportHandler(ReportErrorStatus.REPORT_CONVERSION_FAILED);
4649
}
4750
}
51+
52+
public ReportResponseDto.ReportDto toDto(Report report) {
53+
return ReportResponseDto.ReportDto.builder()
54+
.reportId(report.getReportId())
55+
.title(report.getTitle())
56+
.createdAt(report.getCreatedAt())
57+
.build();
58+
}
59+
60+
public List<ReportResponseDto.ReportDto> toDtoList(List<Report> reports) {
61+
return reports.stream()
62+
.map(this::toDto)
63+
.toList();
64+
}
65+
66+
public ReportResponseDto.ReportListDto toListDto(Page<Report> reportsPage) {
67+
return ReportResponseDto.ReportListDto.builder()
68+
.reports(toDtoList(reportsPage.getContent()))
69+
.currentPage(reportsPage.getNumber() + 1)
70+
.totalPages(reportsPage.getTotalPages())
71+
.totalElements(reportsPage.getTotalElements())
72+
.isLast(reportsPage.isLast())
73+
.build();
74+
}
75+
4876
}

src/main/java/com/perfact/be/domain/report/dto/ReportResponseDto.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,45 @@ public static ReportBadgeDto from(ReportBadge reportBadge) {
136136
.build();
137137
}
138138
}
139+
140+
@Getter
141+
@Builder
142+
@NoArgsConstructor
143+
@AllArgsConstructor
144+
@Schema(description = "레포트 리스트 응답 DTO")
145+
public static class ReportListDto {
146+
147+
@Schema(description = "레포트 목록")
148+
private List<ReportDto> reports;
149+
150+
@Schema(description = "현재 페이지 번호 (1부터 시작)", example = "1")
151+
private int currentPage;
152+
153+
@Schema(description = "전체 페이지 수", example = "5")
154+
private int totalPages;
155+
156+
@Schema(description = "전체 레포트 수", example = "27")
157+
private long totalElements;
158+
159+
@Schema(description = "현재 페이지가 마지막 페이지 여부", example = "false")
160+
private boolean isLast;
161+
}
162+
163+
164+
@Getter
165+
@Builder
166+
@NoArgsConstructor
167+
@AllArgsConstructor
168+
@Schema(description = "리포트 응답 DTO")
169+
public static class ReportDto {
170+
171+
@Schema(description = "리포트 ID", example = "1")
172+
private Long reportId;
173+
174+
@Schema(description = "뉴스 제목", example = "뉴스 제목입니다")
175+
private String title;
176+
177+
@Schema(description = "생성일시")
178+
private LocalDateTime createdAt;
179+
}
139180
}

src/main/java/com/perfact/be/domain/report/exception/status/ReportErrorStatus.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public enum ReportErrorStatus implements BaseErrorCode {
1414
ANALYSIS_RESULT_PARSING_FAILED(HttpStatus.BAD_REQUEST, "REPORT4003", "분석 결과 파싱에 실패했습니다."),
1515
REPORT_NOT_FOUND(HttpStatus.NOT_FOUND, "REPORT4004", "리포트를 찾을 수 없습니다."),
1616
REPORT_CONVERSION_FAILED(HttpStatus.BAD_REQUEST, "REPORT4005", "리포트 변환에 실패했습니다."),
17+
INVALID_PAGE_NUMBER(HttpStatus.NOT_FOUND, "REPORT4006","페이지 번호가 유효하지 않습니다.")
1718
;
1819

1920
private final HttpStatus httpStatus;

src/main/java/com/perfact/be/domain/report/repository/ReportRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.perfact.be.domain.report.entity.Report;
44
import com.perfact.be.domain.user.entity.User;
5+
import org.springframework.data.domain.Page;
6+
import org.springframework.data.domain.Pageable;
57
import org.springframework.data.jpa.repository.JpaRepository;
68
import org.springframework.stereotype.Repository;
79

@@ -13,4 +15,6 @@ public interface ReportRepository extends JpaRepository<Report, Long> {
1315
List<Report> findByUserOrderByCreatedAtDesc(User user);
1416

1517
List<Report> findByUserAndCategoryOrderByCreatedAtDesc(User user, String category);
18+
19+
Page<Report> findByUserOrderByCreatedAtDesc(User user, Pageable pageable);
1620
}

src/main/java/com/perfact/be/domain/report/service/ReportService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.perfact.be.domain.report.service;
22

3+
import com.perfact.be.domain.report.dto.ReportResponseDto.ReportListDto;
34
import com.perfact.be.domain.report.entity.Report;
45
import com.perfact.be.domain.user.entity.User;
56

@@ -9,4 +10,6 @@ public interface ReportService {
910
Report createReportFromAnalysis(Object analysisResult, String url, User user);
1011

1112
Report analyzeNewsAndCreateReport(String url, User user);
13+
14+
ReportListDto getSavedReports(User loginUser, int page);
1215
}

src/main/java/com/perfact/be/domain/report/service/ReportServiceImpl.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@
55
import com.perfact.be.domain.news.dto.NewsArticleResponse;
66
import com.perfact.be.domain.news.service.NewsService;
77
import com.perfact.be.domain.report.converter.ClovaAnalysisConverter;
8-
import com.perfact.be.domain.report.dto.ClovaRequestDTO;
9-
import com.perfact.be.domain.report.dto.ClovaResponseDTO;
10-
import com.perfact.be.domain.report.entity.Badge;
11-
import com.perfact.be.domain.report.entity.Report;
12-
import com.perfact.be.domain.report.entity.ReportBadge;
13-
import com.perfact.be.domain.report.entity.TrueScore;
14-
import com.perfact.be.domain.report.repository.BadgeRepository;
15-
import com.perfact.be.domain.report.repository.ReportBadgeRepository;
16-
import com.perfact.be.domain.report.repository.ReportRepository;
17-
import com.perfact.be.domain.report.repository.TrueScoreRepository;
8+
import com.perfact.be.domain.report.converter.ReportConverter;
9+
import com.perfact.be.domain.report.dto.*;
10+
import com.perfact.be.domain.report.entity.*;
11+
import com.perfact.be.domain.report.repository.*;
1812
import com.perfact.be.domain.report.exception.ReportHandler;
1913
import com.perfact.be.domain.report.exception.status.ReportErrorStatus;
2014
import com.perfact.be.domain.user.entity.User;
2115
import lombok.RequiredArgsConstructor;
2216
import lombok.extern.slf4j.Slf4j;
2317
import org.springframework.beans.factory.annotation.Value;
18+
import org.springframework.data.domain.Page;
19+
import org.springframework.data.domain.PageRequest;
20+
import org.springframework.data.domain.Pageable;
21+
import org.springframework.data.domain.Sort;
2422
import org.springframework.http.HttpEntity;
2523
import org.springframework.http.HttpHeaders;
2624
import org.springframework.http.HttpMethod;
@@ -48,6 +46,8 @@ public class ReportServiceImpl implements ReportService {
4846
private final ObjectMapper objectMapper;
4947
private final PromptService promptService;
5048

49+
private final ReportConverter reportConverter;
50+
5151
@Value("${api.clova.api-url}")
5252
private String CLOVA_API_URL;
5353

@@ -165,6 +165,19 @@ public Report analyzeNewsAndCreateReport(String url, User user) {
165165
}
166166
}
167167

168+
@Override
169+
@Transactional(readOnly = true)
170+
public ReportResponseDto.ReportListDto getSavedReports(User loginUser, int page) {
171+
if (page < 1) {
172+
throw new ReportHandler(ReportErrorStatus.INVALID_PAGE_NUMBER);
173+
}
174+
175+
Pageable pageable = PageRequest.of(page - 1, 6, Sort.by(Sort.Direction.DESC, "createdAt"));
176+
Page<Report> reportsPage = reportRepository.findByUserOrderByCreatedAtDesc(loginUser, pageable);
177+
return reportConverter.toListDto(reportsPage);
178+
}
179+
180+
168181
private Object analyzeNaverNews(String url) {
169182
try {
170183
NewsArticleResponse newsData = newsService.extractNaverNewsArticle(url);

src/main/java/com/perfact/be/domain/user/controller/UserController.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.perfact.be.domain.user.controller;
22

3+
import com.perfact.be.domain.report.dto.ReportResponseDto;
4+
import com.perfact.be.domain.report.dto.ReportResponseDto.ReportListDto;
5+
import com.perfact.be.domain.report.service.ReportService;
36
import com.perfact.be.domain.user.entity.User;
47
import com.perfact.be.domain.user.exception.status.UserSuccessStatus;
58
import com.perfact.be.domain.user.service.UserService;
@@ -11,8 +14,10 @@
1114
import lombok.RequiredArgsConstructor;
1215
import org.springframework.web.bind.annotation.GetMapping;
1316
import org.springframework.web.bind.annotation.PatchMapping;
17+
import org.springframework.web.bind.annotation.PathVariable;
1418
import org.springframework.web.bind.annotation.PostMapping;
1519
import org.springframework.web.bind.annotation.RequestMapping;
20+
import org.springframework.web.bind.annotation.RequestParam;
1621
import org.springframework.web.bind.annotation.RestController;
1722

1823
@Tag(name="User", description = "유저 관련 API")
@@ -21,6 +26,23 @@
2126
@RequestMapping("/api/users")
2227
public class UserController {
2328
private final UserService userService;
29+
private final ReportService reportService;
30+
31+
@Operation(
32+
summary = "레포트 저장함 리스트 조회",
33+
description = "현재 로그인한 사용자가 저장한 과거 레포트 리스트를 조회합니다. 페이지네이션이 적용되어 있으며, 페이지 번호는 1부터 시작합니다.",
34+
parameters = {
35+
@Parameter(name = "page", description = "페이지 번호 (1부터 시작)", example = "1"),
36+
}
37+
)
38+
@GetMapping("/{reportId}")
39+
public ApiResponse<ReportResponseDto.ReportListDto> getReportList(
40+
@Parameter(hidden = true) @CurrentUser User loginUser,
41+
@RequestParam(name = "page", defaultValue = "1") int page
42+
) {
43+
ReportResponseDto.ReportListDto response = reportService.getSavedReports(loginUser, page);
44+
return ApiResponse.of(UserSuccessStatus.GET_REPORT_LIST_SUCCESS, response);
45+
}
2446

2547
@Operation(summary = "구독 상태 확인", description = "현재 사용자의 구독 상태를 확인합니다.")
2648
@GetMapping("/subscribe")

src/main/java/com/perfact/be/domain/user/exception/status/UserSuccessStatus.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public enum UserSuccessStatus implements BaseCode {
1313
SOCIAL_LOGIN_SUCCESS(HttpStatus.OK, "USER2001", "소셜 로그인이 완료되었습니다."),
1414
GET_SUBSCRIBE_STATUS_SUCCESS(HttpStatus.OK, "USER2002", "구독 상태 조회 성공"),
1515
SUBSCRIBE_SUCCESS(HttpStatus.OK, "USER2003", "구독 신청 성공"),
16-
UNSUBSCRIBE_SUCCESS(HttpStatus.OK, "USER2004", "구독 해지 성공")
16+
UNSUBSCRIBE_SUCCESS(HttpStatus.OK, "USER2004", "구독 해지 성공"),
17+
GET_REPORT_LIST_SUCCESS(HttpStatus.OK, "USER2005","과거 레포트 리스트 조회 성공")
1718

1819
;
1920

0 commit comments

Comments
 (0)