Skip to content

Commit aef8d63

Browse files
committed
feat[poll]:상위투표조회추가
1 parent 6efd118 commit aef8d63

File tree

7 files changed

+121
-17
lines changed

7 files changed

+121
-17
lines changed

backend/src/main/java/com/ai/lawyer/domain/poll/controller/PollController.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
import io.swagger.v3.oas.annotations.Operation;
1313
import io.swagger.v3.oas.annotations.tags.Tag;
1414
import lombok.RequiredArgsConstructor;
15+
import org.springframework.http.ResponseEntity;
1516
import org.springframework.security.core.Authentication;
1617
import org.springframework.security.core.context.SecurityContextHolder;
1718
import org.springframework.web.bind.annotation.*;
1819

20+
import org.springframework.web.server.ResponseStatusException;
21+
1922
import java.util.List;
2023

2124
@Tag(name = "Poll API", description = "투표 관련 API")
@@ -104,4 +107,38 @@ public PollDto createPoll(@RequestBody PollCreateDto request) {
104107
public PollDto updatePoll(@PathVariable Long pollId, @RequestBody com.ai.lawyer.domain.poll.dto.PollUpdateDto pollUpdateDto) {
105108
return pollService.updatePoll(pollId, pollUpdateDto);
106109
}
110+
111+
@Operation(summary = "진행중인 투표 전체 목록 조회")
112+
@GetMapping("/ongoing")
113+
public List<PollDto> getOngoingPolls() {
114+
return pollService.getPollsByStatus(PollDto.PollStatus.ONGOING);
115+
}
116+
117+
@Operation(summary = "종료된 투표 전체 목록 조회")
118+
@GetMapping("/closed")
119+
public List<PollDto> getClosedPolls() {
120+
return pollService.getPollsByStatus(PollDto.PollStatus.CLOSED);
121+
}
122+
123+
@Operation(summary = "종료된 투표 Top N 조회")
124+
@GetMapping("/top/closed-list") ///api/polls/top/closed-list?size=3
125+
public List<PollDto> getTopClosedPolls(@RequestParam(defaultValue = "3") int size) {
126+
return pollService.getTopNPollsByStatus(PollDto.PollStatus.CLOSED, size);
127+
}
128+
129+
@Operation(summary = "진행중인 투표 Top N 조회")
130+
@GetMapping("/top/ongoing-list") ///api/polls/top/ongoing-list?size=3
131+
public List<PollDto> getTopOngoingPolls(@RequestParam(defaultValue = "3") int size) {
132+
return pollService.getTopNPollsByStatus(PollDto.PollStatus.ONGOING, size);
133+
}
134+
135+
@ExceptionHandler(ResponseStatusException.class)
136+
public ResponseEntity<Object> handleResponseStatusException(ResponseStatusException ex) {
137+
int code = ex.getStatusCode().value();
138+
String message = ex.getReason();
139+
return ResponseEntity.status(code).body(new java.util.HashMap<String, Object>() {{
140+
put("code", code);
141+
put("message", message);
142+
}});
143+
}
107144
}

backend/src/main/java/com/ai/lawyer/domain/poll/dto/PollOptionUpdateDto.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
@AllArgsConstructor
1212
@Builder
1313
public class PollOptionUpdateDto {
14+
@Schema(description = "투표 항목 id", example = "1")
15+
private Long pollItemsId;
16+
1417
@Schema(description = "투표 항목 내용", example = "항목1 내용")
1518
private String content;
1619
}

backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollStaticsRepository.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
import com.ai.lawyer.domain.poll.entity.PollStatics;
44
import org.springframework.data.jpa.repository.JpaRepository;
55

6-
public interface PollStaticsRepository extends JpaRepository<PollStatics, Long> {}
6+
import java.util.List;
77

8+
public interface PollStaticsRepository extends JpaRepository<PollStatics, Long> {
9+
List<PollStatics> findByPoll_PollId(Long pollId);
10+
}

backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
import com.ai.lawyer.domain.poll.entity.Poll;
55
import org.springframework.data.jpa.repository.JpaRepository;
66
import org.springframework.data.jpa.repository.Query;
7+
import org.springframework.data.domain.Pageable;
78
import org.springframework.data.repository.query.Param;
89
import java.util.List;
910

1011
public interface PollVoteRepository extends JpaRepository<PollVote, Long> {
1112
@Query("SELECT v.poll.pollId, COUNT(v.pollVoteId) FROM PollVote v WHERE v.poll.status = :status GROUP BY v.poll.pollId ORDER BY COUNT(v.pollVoteId) DESC")
1213
List<Object[]> findTopPollByStatus(@Param("status") Poll.PollStatus status);
1314

15+
@Query("SELECT p.pollId, COUNT(v) as voteCount FROM PollVote v JOIN v.poll p WHERE p.status = :status GROUP BY p.pollId ORDER BY voteCount DESC")
16+
List<Object[]> findTopNPollByStatus(@Param("status") Poll.PollStatus status, Pageable pageable);
17+
1418
@Query("SELECT COUNT(v.pollVoteId) FROM PollVote v WHERE v.poll.pollId = :pollId")
1519
Long countByPollId(@Param("pollId") Long pollId);
1620

backend/src/main/java/com/ai/lawyer/domain/poll/service/PollService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ public interface PollService {
2424
PollDto getPollWithStatistics(Long pollId);
2525
PollDto createPoll(PollCreateDto request, Long memberId);
2626
void patchUpdatePoll(Long pollId, PollUpdateDto pollUpdateDto);
27+
List<PollDto> getPollsByStatus(PollDto.PollStatus status);
28+
List<PollDto> getTopNPollsByStatus(PollDto.PollStatus status, int n);
2729
}

backend/src/main/java/com/ai/lawyer/domain/poll/service/PollServiceImpl.java

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.ai.lawyer.domain.poll.dto.PollOptionDto;
2222
import com.ai.lawyer.domain.poll.dto.PollVoteDto;
2323
import com.ai.lawyer.domain.poll.dto.PollUpdateDto;
24+
import org.springframework.data.domain.Pageable;
2425

2526
@Service
2627
@Transactional
@@ -46,9 +47,7 @@ public PollDto getPoll(Long pollId) {
4647

4748
@Override
4849
public List<PollOptions> getPollOptions(Long pollId) {
49-
return pollOptionsRepository.findAll().stream()
50-
.filter(opt -> opt.getPoll().getPollId().equals(pollId))
51-
.toList();
50+
return pollOptionsRepository.findByPoll_PollId(pollId);
5251
}
5352

5453
@Override
@@ -91,9 +90,7 @@ public List<PollStatics> getPollStatics(Long pollId) {
9190
if (!pollRepository.existsById(pollId)) {
9291
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "해당 투표가 존재하지 않습니다.");
9392
}
94-
return pollStaticsRepository.findAll().stream()
95-
.filter(stat -> stat.getPoll().getPollId().equals(pollId))
96-
.toList();
93+
return pollStaticsRepository.findByPoll_PollId(pollId);
9794
}
9895

9996
@Override
@@ -128,7 +125,17 @@ public void deletePoll(Long pollId) {
128125
public PollDto getTopPollByStatus(PollDto.PollStatus status) {
129126
List<Object[]> result = pollVoteRepository.findTopPollByStatus(Poll.PollStatus.valueOf(status.name()));
130127
if (result.isEmpty()) {
131-
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "해당 상태의 투표가 없습니다.");
128+
// 종료된 투표가 없으면 빈 PollDto 반환
129+
return PollDto.builder()
130+
.pollId(null)
131+
.postId(null)
132+
.voteTitle(null)
133+
.status(status)
134+
.createdAt(null)
135+
.closedAt(null)
136+
.pollOptions(java.util.Collections.emptyList())
137+
.totalVoteCount(0L)
138+
.build();
132139
}
133140
Long pollId = (Long) result.get(0)[0];
134141
return getPoll(pollId);
@@ -157,16 +164,39 @@ public PollDto updatePoll(Long pollId, PollUpdateDto pollUpdateDto) {
157164
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "투표가 진행된 투표는 수정할 수 없습니다.");
158165
}
159166
if (pollUpdateDto.getVoteTitle() != null) poll.setVoteTitle(pollUpdateDto.getVoteTitle());
160-
// 투표 항목 수정: 기존 항목 삭제 후 새로 저장
161-
if (pollUpdateDto.getPollOptions() != null && pollUpdateDto.getPollOptions().size() == 2) {
162-
pollOptionsRepository.deleteAll(pollOptionsRepository.findByPoll_PollId(pollId));
163-
pollUpdateDto.getPollOptions().forEach(optionDto -> {
164-
PollOptions option = PollOptions.builder()
167+
// 투표 항목 수정
168+
if (pollUpdateDto.getPollOptions() != null) {
169+
List<PollOptions> existingOptions = pollOptionsRepository.findByPoll_PollId(pollId);
170+
// 전달받은 id 목록
171+
List<Long> incomingIds = pollUpdateDto.getPollOptions().stream()
172+
.map(opt -> opt.getPollItemsId())
173+
.filter(id -> id != null)
174+
.toList();
175+
// 기존 옵션 중 전달받지 않은 id 삭제
176+
for (PollOptions option : existingOptions) {
177+
if (!incomingIds.contains(option.getPollItemsId())) {
178+
pollOptionsRepository.deleteById(option.getPollItemsId());
179+
}
180+
}
181+
//추가/수정
182+
for (var optionDto : pollUpdateDto.getPollOptions()) {
183+
if (optionDto.getPollItemsId() != null) {
184+
// update
185+
PollOptions option = existingOptions.stream()
186+
.filter(o -> o.getPollItemsId().equals(optionDto.getPollItemsId()))
187+
.findFirst().orElse(null);
188+
if (option != null) {
189+
option.setOption(optionDto.getContent());
190+
pollOptionsRepository.save(option);
191+
}
192+
} else {
193+
PollOptions newOption = PollOptions.builder()
165194
.poll(poll)
166195
.option(optionDto.getContent())
167196
.build();
168-
pollOptionsRepository.save(option);
169-
});
197+
pollOptionsRepository.save(newOption);
198+
}
199+
}
170200
}
171201
Poll updated = pollRepository.save(poll);
172202
return convertToDto(updated);
@@ -180,7 +210,7 @@ public void patchUpdatePoll(Long pollId, PollUpdateDto pollUpdateDto) {
180210
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "투표가 이미 진행된 투표는 수정할 수 없습니다.");
181211
}
182212
if (pollUpdateDto.getVoteTitle() != null) poll.setVoteTitle(pollUpdateDto.getVoteTitle());
183-
// 투표 항목 수정: 기존 항목 삭제 후 새로 저장
213+
// 투표 항목 수정
184214
if (pollUpdateDto.getPollOptions() != null && pollUpdateDto.getPollOptions().size() == 2) {
185215
pollOptionsRepository.deleteAll(pollOptionsRepository.findByPoll_PollId(pollId));
186216
pollUpdateDto.getPollOptions().forEach(optionDto -> {
@@ -301,6 +331,31 @@ public PollDto createPoll(PollCreateDto request, Long memberId) {
301331
}
302332
}
303333

334+
@Override
335+
public List<PollDto> getPollsByStatus(PollDto.PollStatus status) {
336+
List<Poll> polls = pollRepository.findAll().stream()
337+
.filter(p -> p.getStatus().name().equals(status.name()))
338+
.toList();
339+
List<PollDto> pollDtos = new java.util.ArrayList<>();
340+
for (Poll poll : polls) {
341+
pollDtos.add(convertToDto(poll));
342+
}
343+
return pollDtos;
344+
}
345+
346+
@Override
347+
public List<PollDto> getTopNPollsByStatus(PollDto.PollStatus status, int n) {
348+
Pageable pageable = org.springframework.data.domain.PageRequest.of(0, n);
349+
List<Object[]> result = pollVoteRepository.findTopNPollByStatus(
350+
com.ai.lawyer.domain.poll.entity.Poll.PollStatus.valueOf(status.name()), pageable);
351+
List<PollDto> pollDtos = new java.util.ArrayList<>();
352+
for (Object[] row : result) {
353+
Long pollId = (Long) row[0];
354+
pollDtos.add(getPoll(pollId));
355+
}
356+
return pollDtos;
357+
}
358+
304359
private PollDto convertToDto(Poll poll) {
305360
List<PollOptions> options = pollOptionsRepository.findByPoll_PollId(poll.getPollId());
306361
List<PollOptionDto> optionDtos = new ArrayList<>();

backend/src/main/java/com/ai/lawyer/domain/post/service/PostServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public PostDto updatePost(Long postId, PostUpdateDto postUpdateDto) {
102102

103103
if (postUpdateDto.getPoll() != null) {
104104
if (post.getPoll() == null) {
105-
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "이 게시글에는 투표가 없어 투표 수정이 불가능합니다.");
105+
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "이 게시글에는 투표가 없어 투표 수정이 불가능합니다.");
106106
}
107107
pollService.updatePoll(post.getPoll().getPollId(), postUpdateDto.getPoll());
108108
}

0 commit comments

Comments
 (0)