Skip to content

Commit 8b105b0

Browse files
authored
Merge pull request #119 from prgrms-web-devcourse-final-project/develop
chore[배포]
2 parents 68e7485 + cadf580 commit 8b105b0

37 files changed

+1852
-319
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,172 @@
11
package com.ai.lawyer.domain.poll.controller;
22

3+
import com.ai.lawyer.domain.poll.dto.PollCreateDto;
4+
import com.ai.lawyer.domain.poll.dto.PollDto;
5+
import com.ai.lawyer.domain.poll.dto.PollVoteDto;
6+
import com.ai.lawyer.domain.poll.entity.PollVote;
7+
import com.ai.lawyer.domain.poll.entity.PollOptions;
8+
import com.ai.lawyer.domain.poll.entity.PollStatics;
9+
import com.ai.lawyer.domain.poll.service.PollService;
10+
import com.ai.lawyer.domain.post.dto.PostDetailDto;
11+
import com.ai.lawyer.domain.post.service.PostService;
12+
import com.ai.lawyer.global.response.ApiResponse;
13+
import io.swagger.v3.oas.annotations.Operation;
14+
import io.swagger.v3.oas.annotations.tags.Tag;
15+
import lombok.RequiredArgsConstructor;
16+
import org.springframework.http.ResponseEntity;
17+
import org.springframework.security.core.Authentication;
18+
import org.springframework.security.core.context.SecurityContextHolder;
19+
import org.springframework.web.bind.annotation.*;
20+
21+
import org.springframework.web.server.ResponseStatusException;
22+
23+
import java.util.List;
24+
25+
@Tag(name = "Poll API", description = "투표 관련 API")
26+
@RestController
27+
@RequestMapping("/api/polls")
28+
@RequiredArgsConstructor
329
public class PollController {
30+
31+
private final PollService pollService;
32+
private final PostService postService;
33+
34+
@Operation(summary = "투표 단일 조회")
35+
@GetMapping("/{pollId}")
36+
public ResponseEntity<ApiResponse<PollDto>> getPoll(@PathVariable Long pollId) {
37+
PollDto poll = pollService.getPoll(pollId);
38+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 단일 조회 성공", poll));
39+
}
40+
41+
@Operation(summary = "투표 옵션 목록 조회")
42+
@GetMapping("/{pollId}/options")
43+
public ResponseEntity<ApiResponse<List<PollOptions>>> getPollOptions(@PathVariable Long pollId) {
44+
List<PollOptions> options = pollService.getPollOptions(pollId);
45+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 옵션 목록 조회 성공", options));
46+
}
47+
48+
@Operation(summary = "투표하기")
49+
@PostMapping("/{pollId}/vote")
50+
public ResponseEntity<ApiResponse<PollVoteDto>> vote(@PathVariable Long pollId, @RequestParam Long pollItemsId) {
51+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
52+
Long memberId = Long.parseLong(authentication.getName());
53+
PollVoteDto result = pollService.vote(pollId, pollItemsId, memberId);
54+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 성공적으로 완료되었습니다.", result));
55+
}
56+
57+
@Operation(summary = "투표 통계 조회")
58+
@GetMapping("/{pollId}/statics")
59+
public ResponseEntity<ApiResponse<List<PollStatics>>> getPollStatics(@PathVariable Long pollId) {
60+
List<PollStatics> statics = pollService.getPollStatics(pollId);
61+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 통계 조회 성공", statics));
62+
}
63+
64+
@Operation(summary = "투표 종료")
65+
@PutMapping("/{pollId}/close")
66+
public ResponseEntity<ApiResponse<Void>> closePoll(@PathVariable Long pollId) {
67+
pollService.closePoll(pollId);
68+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 종료되었습니다.", null));
69+
}
70+
71+
@Operation(summary = "투표 삭제")
72+
@DeleteMapping("/{pollId}")
73+
public ResponseEntity<ApiResponse<Void>> deletePoll(@PathVariable Long pollId) {
74+
pollService.deletePoll(pollId);
75+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 삭제되었습니다.", null));
76+
}
77+
78+
@Operation(summary = "진행중인 투표 Top 1 조회")
79+
@GetMapping("/top/ongoing")
80+
public ResponseEntity<ApiResponse<PollDto>> getTopOngoingPoll() {
81+
PollDto poll = pollService.getTopPollByStatus(PollDto.PollStatus.ONGOING);
82+
return ResponseEntity.ok(new ApiResponse<>(200, "진행중인 투표 Top 1 조회 성공", poll));
83+
}
84+
85+
@Operation(summary = "종료된 투표 Top 1 조회")
86+
@GetMapping("/top/closed")
87+
public ResponseEntity<ApiResponse<PollDto>> getTopClosedPoll() {
88+
PollDto poll = pollService.getTopPollByStatus(PollDto.PollStatus.CLOSED);
89+
return ResponseEntity.ok(new ApiResponse<>(200, "종료된 투표 Top 1 조회 성공", poll));
90+
}
91+
92+
// @Operation(summary = "진행중인 투표 상세 조회")
93+
// @GetMapping("/top/ongoing-detail")
94+
// public PostDetailDto getTopOngoingPollDetail() {
95+
// PollDto pollDto = pollService.getTopPollByStatus(PollDto.PollStatus.ONGOING);
96+
// return postService.getPostDetailById(pollDto.getPostId());
97+
// }
98+
//
99+
// @Operation(summary = "종료된 투표 상세 조회")
100+
// @GetMapping("/top/closed-detail")
101+
// public PostDetailDto getTopClosedPollDetail() {
102+
// PollDto pollDto = pollService.getTopPollByStatus(PollDto.PollStatus.CLOSED);
103+
// return postService.getPostDetailById(pollDto.getPostId());
104+
// }
105+
106+
@Operation(summary = "투표 생성")
107+
@PostMapping("")
108+
public ResponseEntity<ApiResponse<PollDto>> createPoll(@RequestBody PollCreateDto pollCreateDto) {
109+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
110+
Long memberId = Long.parseLong(authentication.getName());
111+
PollDto created = pollService.createPoll(pollCreateDto, memberId);
112+
return ResponseEntity.ok(new ApiResponse<>(201, "투표가 생성되었습니다.", created));
113+
}
114+
115+
@Operation(summary = "투표 수정")
116+
@PutMapping("/{pollId}")
117+
public ResponseEntity<ApiResponse<PollDto>> updatePoll(@PathVariable Long pollId, @RequestBody com.ai.lawyer.domain.poll.dto.PollUpdateDto pollUpdateDto) {
118+
PollDto updated = pollService.updatePoll(pollId, pollUpdateDto);
119+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 수정되었습니다.", updated));
120+
}
121+
122+
@Operation(summary = "진행중인 투표 전체 목록 조회")
123+
@GetMapping("/ongoing")
124+
public ResponseEntity<ApiResponse<List<PollDto>>> getOngoingPolls() {
125+
List<PollDto> polls = pollService.getPollsByStatus(PollDto.PollStatus.ONGOING);
126+
return ResponseEntity.ok(new ApiResponse<>(200, "진행중인 투표 전체 목록 조회 성공", polls));
127+
}
128+
129+
@Operation(summary = "종료된 투표 전체 목록 조회")
130+
@GetMapping("/closed")
131+
public ResponseEntity<ApiResponse<List<PollDto>>> getClosedPolls() {
132+
List<PollDto> polls = pollService.getPollsByStatus(PollDto.PollStatus.CLOSED);
133+
return ResponseEntity.ok(new ApiResponse<>(200, "종료된 투표 전체 목록 조회 성공", polls));
134+
}
135+
136+
@Operation(summary = "종료된 투표 Top N 조회")
137+
@GetMapping("/top/closed-list") //검색조건 : pi/polls/top/closed-list?size=3
138+
public ResponseEntity<ApiResponse<List<PollDto>>> getTopClosedPolls(@RequestParam(defaultValue = "3") int size) {
139+
List<PollDto> polls = pollService.getTopNPollsByStatus(PollDto.PollStatus.CLOSED, size);
140+
String message = String.format("종료된 투표 Top %d 조회 성공", size);
141+
return ResponseEntity.ok(new ApiResponse<>(200, message, polls));
142+
}
143+
144+
@Operation(summary = "진행중인 투표 Top N 조회")
145+
@GetMapping("/top/ongoing-list") //검색조건 : api/polls/top/ongoing-list?size=3
146+
public ResponseEntity<ApiResponse<List<PollDto>>> getTopOngoingPolls(@RequestParam(defaultValue = "3") int size) {
147+
List<PollDto> polls = pollService.getTopNPollsByStatus(PollDto.PollStatus.ONGOING, size);
148+
String message = String.format("진행중인 투표 Top %d 조회 성공", size);
149+
return ResponseEntity.ok(new ApiResponse<>(200, message, polls));
150+
}
151+
152+
@Operation(summary = "index(순번)로 투표하기 - Swagger 편의용")
153+
@PostMapping("/{pollId}/vote-by-index")
154+
public ResponseEntity<ApiResponse<PollVoteDto>> voteByIndex(@PathVariable Long pollId, @RequestParam int index) {
155+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
156+
Long memberId = Long.parseLong(authentication.getName());
157+
List<PollOptions> options = pollService.getPollOptions(pollId);
158+
if (index < 1 || index > options.size()) {
159+
throw new ResponseStatusException(org.springframework.http.HttpStatus.BAD_REQUEST, "index가 옵션 범위를 벗어났습니다.");
160+
}
161+
Long pollItemsId = options.get(index - 1).getPollItemsId();
162+
PollVoteDto result = pollService.vote(pollId, pollItemsId, memberId);
163+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 성공적으로 완료되었습니다.", result));
164+
}
165+
166+
@ExceptionHandler(ResponseStatusException.class)
167+
public ResponseEntity<ApiResponse<Void>> handleResponseStatusException(ResponseStatusException ex) {
168+
int code = ex.getStatusCode().value();
169+
String message = ex.getReason();
170+
return ResponseEntity.status(code).body(new ApiResponse<>(code, message, null));
171+
}
4172
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import java.util.List;
9+
import java.time.LocalDateTime;
10+
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Builder
15+
public class PollCreateDto {
16+
@Schema(description = "게시글 ID", example = "123")
17+
private Long postId;
18+
@Schema(description = "투표 제목", example = "당신의 선택은?")
19+
private String voteTitle;
20+
@Schema(description = "투표 항목(2개 필수)", example = "[{\"content\": \"항목1 내용\"}, {\"content\": \"항목2 내용\"}]")
21+
private List<PollOptionCreateDto> pollOptions;
22+
private LocalDateTime reservedCloseAt;
23+
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.*;
44
import java.time.LocalDateTime;
5+
import java.util.List;
56

67
@Data
78
@NoArgsConstructor
@@ -14,9 +15,11 @@ public class PollDto {
1415
private PollStatus status;
1516
private LocalDateTime createdAt;
1617
private LocalDateTime closedAt;
18+
private LocalDateTime expectedCloseAt;
19+
private List<PollOptionDto> pollOptions;
20+
private Long totalVoteCount;
1721

1822
public enum PollStatus {
1923
ONGOING, CLOSED
2024
}
2125
}
22-
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
@Data
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Builder
13+
public class PollOptionCreateDto {
14+
@Schema(description = "투표 항목 내용", example = "항목1 내용")
15+
private String content;
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import lombok.*;
4+
5+
@Data
6+
@NoArgsConstructor
7+
@AllArgsConstructor
8+
@Builder
9+
public class PollOptionDto {
10+
private Long pollItemsId;
11+
private String content;
12+
private Long voteCount;
13+
private java.util.List<PollStaticsDto> statics;
14+
private int pollOptionIndex;
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
@Data
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Builder
13+
public class PollOptionUpdateDto {
14+
@Schema(description = "투표 항목 id", example = "1")
15+
private Long pollItemsId;
16+
17+
@Schema(description = "투표 항목 내용", example = "항목1 내용")
18+
private String content;
19+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import lombok.*;
4+
5+
@Data
6+
@NoArgsConstructor
7+
@AllArgsConstructor
8+
@Builder
9+
public class PollStaticsDto {
10+
private String gender;
11+
private String ageGroup;
12+
private Long voteCount;
13+
}
14+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import java.util.List;
9+
import java.time.LocalDateTime;
10+
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Builder
15+
public class PollUpdateDto {
16+
@Schema(description = "투표 제목", example = "당신의 선택은?")
17+
private String voteTitle;
18+
@Schema(description = "투표 항목(2개 필수)", example = "[{\"content\": \"항목1 내용\"}, {\"content\": \"항목2 내용\"}]")
19+
private List<PollOptionUpdateDto> pollOptions;
20+
private LocalDateTime reservedCloseAt;
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@NoArgsConstructor
10+
@AllArgsConstructor
11+
@Builder
12+
public class PollVoteDto {
13+
private Long pollVoteId;
14+
private Long pollId;
15+
private Long pollItemsId;
16+
private Long memberId;
17+
private Long voteCount;
18+
}
19+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import com.ai.lawyer.domain.post.dto.PostDto;
4+
import lombok.*;
5+
6+
@Data
7+
@NoArgsConstructor
8+
@AllArgsConstructor
9+
@Builder
10+
public class PollWithPostDto {
11+
private PollDto poll;
12+
private PostDto post;
13+
}
14+

0 commit comments

Comments
 (0)