Skip to content

Commit 20cabb2

Browse files
authored
#114 [Refactor] 댓글 조회 API 설계 수정 (#132)
## #️⃣ 연관된 이슈 <!-- Ex) - #이슈번호 --> <!-- 연관된 이슈 번호를 링크 형태로 작성하세요 --> - #114 ## 📝 작업 내용 <!-- 이번 PR/이슈에서 실제 수행한 작업 내용을 작성하세요 --> ### ✨ Feat <!-- 새로운 기능 구현 내용 작성 --> | 내용 | 파일 | |------|------| | 로그인 기능 구현 | `AuthController.java`, `AuthService.java` | | 'API 설계 수정' | | ### ♻️ Refactor <!-- 기존 코드 리팩토링 내용 작성 --> | 내용 | 파일 | |------|------| | 불필요한 import 제거 | `UserService.java` | | 댓글 API 설계 수정 | 'perspectiveService.java'| ### 🐛 Fix <!-- 버그 수정 내용 작성 --> | 내용 | 파일 | |------|------| | 널 포인트 예외 처리 | `PaymentService.java` | | | | ## 📌 공유 사항 <!-- 팀원에게 공유할 내용이나 참고 사항 작성 --> <!-- 노션 환경 설정 파일 확인 부탁드립니다! --> > 1. ## ✅ 체크리스트 <!-- PR 제출 전에 체크해야 할 사항들 --> - [ ] Reviewer에 팀원들을 선택했나요? - [ ] Assignees에 본인을 선택했나요? - [ ] 컨벤션에 맞는 Type을 선택했나요? - [ ] Development에 이슈를 연동했나요? - [ ] Merge 하려는 브랜치가 올바르게 설정되어 있나요? - [ ] 컨벤션을 지키고 있나요? - [ ] 로컬에서 실행했을 때 에러가 발생하지 않나요? - [ ] 팀원들에게 PR 링크 공유를 했나요? ## 📸 스크린샷 <!-- Swagger, Postman, JUnit 테스트 화면 첨부 --> <!-- 기능 동작 화면이나 테스트 결과 캡처를 첨부하면 좋습니다 --> ## 💬 리뷰 요구사항 <!-- 리뷰어에게 요청하는 구체적인 사항 작성 --> <!-- 종료 의도 판단을 Java 키워드 → AI 2차 검증 구조로 설계했는데 해당 구조가 유지보수 및 확장 측면에서 적절한지 의견 부탁드립니다. --> > 1.
1 parent 0e8e477 commit 20cabb2

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/main/java/com/swyp/picke/domain/perspective/controller/PerspectiveCommentController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ public ApiResponse<CommentListResponse> getComments(
5151
return ApiResponse.onSuccess(commentService.getComments(perspectiveId, userId, cursor, size));
5252
}
5353

54+
@Operation(summary = "댓글 목록 조회 (옵션 라벨)", description = "특정 관점의 댓글 목록을 커서 기반 페이지네이션으로 조회합니다. stance는 투표한 옵션의 라벨(A/B)로 반환됩니다.")
55+
@GetMapping("/perspectives/{perspectiveId}/comments/labeled")
56+
public ApiResponse<CommentListResponse> getCommentsWithLabel(
57+
@PathVariable Long perspectiveId,
58+
@AuthenticationPrincipal Long userId,
59+
@RequestParam(required = false) String cursor,
60+
@RequestParam(required = false) Integer size
61+
) {
62+
return ApiResponse.onSuccess(commentService.getCommentsWithLabel(perspectiveId, userId, cursor, size));
63+
}
64+
5465
@Operation(summary = "댓글 삭제", description = "본인이 작성한 댓글을 삭제합니다.")
5566
@DeleteMapping("/perspectives/{perspectiveId}/comments/{commentId}")
5667
public ApiResponse<Void> deleteComment(

src/main/java/com/swyp/picke/domain/perspective/service/PerspectiveCommentService.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,50 @@ public CommentListResponse getComments(Long perspectiveId, Long userId, String c
123123
return new CommentListResponse(items, nextCursor, nextCursor != null);
124124
}
125125

126+
public CommentListResponse getCommentsWithLabel(Long perspectiveId, Long userId, String cursor, Integer size) {
127+
Perspective perspective = findPerspectiveById(perspectiveId);
128+
129+
int pageSize = (size == null || size <= 0) ? DEFAULT_PAGE_SIZE : size;
130+
PageRequest pageable = PageRequest.of(0, pageSize);
131+
132+
List<PerspectiveComment> comments = cursor == null
133+
? commentRepository.findByPerspectiveOrderByCreatedAtDesc(perspective, pageable)
134+
: commentRepository.findByPerspectiveAndCreatedAtBeforeOrderByCreatedAtDesc(
135+
perspective, LocalDateTime.parse(cursor), pageable);
136+
137+
Long battleId = perspective.getBattle().getId();
138+
List<CommentListResponse.Item> items = comments.stream()
139+
.filter(c -> !c.isHidden())
140+
.map(c -> {
141+
UserSummary user = userQueryService.findSummaryById(c.getUser().getId());
142+
String characterImageUrl = resolveCharacterImageUrl(user.characterType());
143+
Long postVoteOptionId = voteService.findPostVoteOptionId(battleId, c.getUser().getId());
144+
String stance = null;
145+
if (postVoteOptionId != null) {
146+
BattleOption option = battleService.findOptionById(postVoteOptionId);
147+
stance = option.getLabel().name();
148+
}
149+
boolean isLiked = commentLikeRepository.existsByCommentAndUserId(c, userId);
150+
return new CommentListResponse.Item(
151+
c.getId(),
152+
new CommentListResponse.UserSummary(user.userTag(), user.nickname(), user.characterType(), characterImageUrl),
153+
stance,
154+
c.getContent(),
155+
c.getLikeCount(),
156+
isLiked,
157+
c.getUser().getId().equals(userId),
158+
c.getCreatedAt()
159+
);
160+
})
161+
.toList();
162+
163+
String nextCursor = comments.size() == pageSize
164+
? comments.get(comments.size() - 1).getCreatedAt().toString()
165+
: null;
166+
167+
return new CommentListResponse(items, nextCursor, nextCursor != null);
168+
}
169+
126170
@Transactional
127171
public void deleteComment(Long perspectiveId, Long commentId, Long userId) {
128172
Perspective perspective = findPerspectiveById(perspectiveId);

0 commit comments

Comments
 (0)