Skip to content

Commit 22f41c9

Browse files
committed
feat[post]:myvotedpaged
1 parent 4450f10 commit 22f41c9

File tree

11 files changed

+227
-92
lines changed

11 files changed

+227
-92
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,7 @@ public ResponseEntity<ApiResponse<PollDto>> updatePoll(@PathVariable Long pollId
7575
@DeleteMapping("/{pollId}")
7676
public ResponseEntity<ApiResponse<Void>> deletePoll(@PathVariable Long pollId) {
7777
Long currentMemberId = AuthUtil.getCurrentMemberId();
78-
PollDto poll = pollService.getPoll(pollId, currentMemberId);
79-
if (!poll.getPostId().equals(currentMemberId)) {
80-
return ResponseEntity.status(403).body(new ApiResponse<>(403, "본인만 투표를 삭제할 수 있습니다.", null));
81-
}
82-
pollService.deletePoll(pollId);
78+
pollService.deletePoll(pollId, currentMemberId);
8379
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 삭제되었습니다.", null));
8480
}
8581

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import com.ai.lawyer.domain.poll.entity.PollVote;
44
import org.springframework.data.jpa.repository.JpaRepository;
55

6+
import java.util.List;
67
import java.util.Optional;
78

89
public interface PollVoteRepository extends JpaRepository<PollVote, Long>, PollVoteRepositoryCustom {
910
Optional<PollVote> findByMember_MemberIdAndPoll_PollId(Long memberId, Long pollId);
1011
void deleteByMember_MemberIdAndPoll_PollId(Long memberId, Long pollId);
1112
Optional<PollVote> findByMember_MemberIdAndPollOptions_PollItemsId(Long memberId, Long pollItemsId);
13+
List<PollVote> findByMember_MemberId(Long memberId);
1214
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public interface PollService {
3434
PollDto updatePoll(Long pollId, PollUpdateDto pollUpdateDto, Long memberId);
3535
void patchUpdatePoll(Long pollId, PollUpdateDto pollUpdateDto);
3636
void closePoll(Long pollId);
37-
void deletePoll(Long pollId);
37+
void deletePoll(Long pollId, Long memberId);
3838

3939
// ===== 검증 관련 =====
4040
void validatePollCreate(PollCreateDto dto);

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import com.ai.lawyer.domain.poll.repository.*;
55
import com.ai.lawyer.domain.poll.dto.PollDto;
66
import com.ai.lawyer.domain.member.entity.Member;
7-
import com.ai.lawyer.domain.member.repositories.MemberRepository;
7+
import com.ai.lawyer.domain.post.dto.PostDto;
88
import com.ai.lawyer.domain.post.entity.Post;
99
import com.ai.lawyer.domain.post.repository.PostRepository;
1010
import lombok.RequiredArgsConstructor;
1111
import lombok.extern.slf4j.Slf4j;
12+
import org.springframework.data.domain.Page;
1213
import org.springframework.http.HttpStatus;
1314
import org.springframework.stereotype.Service;
1415
import org.springframework.transaction.annotation.Transactional;
@@ -31,6 +32,7 @@
3132
import com.ai.lawyer.domain.poll.dto.PollGenderStaticsDto;
3233
import com.ai.lawyer.domain.poll.dto.PollStaticsResponseDto;
3334
import com.ai.lawyer.domain.poll.dto.PollAgeStaticsDto;
35+
import com.ai.lawyer.global.util.AuthUtil;
3436

3537
@Service
3638
@Transactional
@@ -42,7 +44,6 @@ public class PollServiceImpl implements PollService {
4244
private final PollOptionsRepository pollOptionsRepository;
4345
private final PollVoteRepository pollVoteRepository;
4446
private final PollStaticsRepository pollStaticsRepository;
45-
private final MemberRepository memberRepository;
4647
private final PostRepository postRepository;
4748

4849
@Override
@@ -51,8 +52,7 @@ public PollDto createPoll(PollCreateDto request, Long memberId) {
5152
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글 ID는 필수입니다.");
5253
}
5354
validatePollCommon(request.getVoteTitle(), request.getPollOptions(), request.getReservedCloseAt());
54-
Member member = memberRepository.findById(memberId)
55-
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "회원 정보를 찾을 수 없습니다."));
55+
Member member = AuthUtil.getMemberOrThrow(memberId);
5656
Post post = postRepository.findById(request.getPostId())
5757
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글을 찾을 수 없습니다."));
5858
if (post.getPoll() != null) {
@@ -117,8 +117,7 @@ public PollVoteDto vote(Long pollId, Long pollItemsId, Long memberId) {
117117
}
118118
PollOptions pollOptions = pollOptionsRepository.findById(pollItemsId)
119119
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "투표 항목을 찾을 수 없습니다."));
120-
Member member = memberRepository.findById(memberId)
121-
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "회원 정보를 찾을 수 없습니다."));
120+
Member member = AuthUtil.getMemberOrThrow(memberId);
122121
// USER 또는 ADMIN만 투표 가능
123122
if (!(member.getRole().name().equals("USER") || member.getRole().name().equals("ADMIN"))) {
124123
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "투표 권한이 없습니다.");
@@ -190,7 +189,7 @@ public PollStaticsResponseDto getPollStatics(Long pollId) {
190189
PollAgeStaticsDto.AgeGroupCountDto dto = PollAgeStaticsDto.AgeGroupCountDto.builder()
191190
.option(option)
192191
.ageGroup(arr[1] != null ? arr[1].toString() : null)
193-
.voteCount(arr[2] != null ? ((Number)arr[2]).longValue() : 0L)
192+
.voteCount(arr[2] != null ? ((Number) arr[2]).longValue() : 0L)
194193
.build();
195194
ageGroupMap.computeIfAbsent(pollItemsId, k -> new java.util.ArrayList<>()).add(dto);
196195
}
@@ -214,7 +213,7 @@ public PollStaticsResponseDto getPollStatics(Long pollId) {
214213
PollGenderStaticsDto.GenderCountDto dto = PollGenderStaticsDto.GenderCountDto.builder()
215214
.option(option)
216215
.gender(arr[1] != null ? arr[1].toString() : null)
217-
.voteCount(arr[2] != null ? ((Number)arr[2]).longValue() : 0L)
216+
.voteCount(arr[2] != null ? ((Number) arr[2]).longValue() : 0L)
218217
.build();
219218
genderGroupMap.computeIfAbsent(pollItemsId, k -> new java.util.ArrayList<>()).add(dto);
220219
}
@@ -246,10 +245,12 @@ public void closePoll(Long pollId) {
246245
}
247246

248247
@Override
249-
public void deletePoll(Long pollId) {
248+
public void deletePoll(Long pollId, Long memberId) {
250249
Poll poll = pollRepository.findById(pollId)
251250
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "투표를 찾을 수 없습니다."));
252-
251+
if (poll.getPost() == null || !poll.getPost().getMember().getMemberId().equals(memberId)) {
252+
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "본인만 투표를 삭제할 수 있습니다.");
253+
}
253254
// 1. 이 Poll을 참조하는 Post가 있으면 연결 해제
254255
Post post = postRepository.findAll().stream()
255256
.filter(p -> p.getPoll() != null && p.getPoll().getPollId().equals(pollId))
@@ -259,7 +260,6 @@ public void deletePoll(Long pollId) {
259260
post.setPoll(null);
260261
postRepository.save(post);
261262
}
262-
263263
// 2. Poll 삭제
264264
pollRepository.deleteById(pollId);
265265
}
@@ -458,12 +458,12 @@ private PollDto convertToDto(Poll poll, Long memberId, boolean withStatistics) {
458458
statics = staticsRaw.stream()
459459
.map(arr -> {
460460
String gender = arr[1] != null ? arr[1].toString() : null;
461-
Integer age = arr[2] != null ? ((Number)arr[2]).intValue() : null;
461+
Integer age = arr[2] != null ? ((Number) arr[2]).intValue() : null;
462462
String ageGroup = getAgeGroup(age);
463463
return PollStaticsDto.builder()
464464
.gender(gender)
465465
.ageGroup(ageGroup)
466-
.voteCount((Long)arr[3])
466+
.voteCount((Long) arr[3])
467467
.build();
468468
}).toList();
469469
}

backend/src/main/java/com/ai/lawyer/domain/post/controller/PostController.java

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,7 @@ public class PostController {
3636
@Operation(summary = "게시글 등록")
3737
@PostMapping
3838
public ResponseEntity<ApiResponse<PostDto>> createPost(@RequestBody PostRequestDto postRequestDto) {
39-
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
40-
Object principal = authentication.getPrincipal();
41-
Long memberId;
42-
if (principal instanceof org.springframework.security.core.userdetails.User user) {
43-
memberId = Long.valueOf(user.getUsername());
44-
} else if (principal instanceof Long) {
45-
memberId = (Long) principal;
46-
} else {
47-
throw new IllegalArgumentException("올바른 회원 ID가 아닙니다");
48-
}
39+
Long memberId = AuthUtil.getAuthenticatedMemberId();
4940
PostDto created = postService.createPost(postRequestDto, memberId);
5041
return ResponseEntity.ok(new ApiResponse<>(201, "게시글이 등록되었습니다.", created));
5142
}
@@ -91,43 +82,31 @@ public ResponseEntity<ApiResponse<List<PostDetailDto>>> getPostsByMember(@PathVa
9182
@Operation(summary = "게시글 수정")
9283
@PutMapping("/{postId}")
9384
public ResponseEntity<ApiResponse<PostDetailDto>> updatePost(@PathVariable Long postId, @RequestBody PostUpdateDto postUpdateDto) {
94-
Long currentMemberId = AuthUtil.getCurrentMemberId();
95-
String currentRole = AuthUtil.getCurrentMemberRole();
96-
PostDetailDto postDetail = postService.getPostDetailById(postId, currentMemberId);
85+
PostDetailDto postDetail = postService.getPostDetailById(postId, AuthUtil.getAuthenticatedMemberId());
9786
Long postOwnerId = postDetail.getPost().getMemberId();
98-
if (!postOwnerId.equals(currentMemberId) && !"ADMIN".equals(currentRole)) {
99-
return ResponseEntity.status(403).body(new ApiResponse<>(403, "본인 또는 관리자만 수정 가능합니다.", null));
100-
}
87+
AuthUtil.validateOwnerOrAdmin(postOwnerId);
10188
postService.updatePost(postId, postUpdateDto);
102-
PostDetailDto updated = postService.getPostDetailById(postId, currentMemberId);
89+
PostDetailDto updated = postService.getPostDetailById(postId, AuthUtil.getAuthenticatedMemberId());
10390
return ResponseEntity.ok(new ApiResponse<>(200, "게시글이 수정되었습니다.", updated));
10491
}
10592

10693
@Operation(summary = "게시글 부분 수정(PATCH)")
10794
@PatchMapping("/{postId}")
10895
public ResponseEntity<ApiResponse<PostDetailDto>> patchUpdatePost(@PathVariable Long postId, @RequestBody PostUpdateDto postUpdateDto) {
109-
Long currentMemberId = AuthUtil.getCurrentMemberId();
110-
String currentRole = AuthUtil.getCurrentMemberRole();
111-
PostDetailDto postDetail = postService.getPostDetailById(postId, currentMemberId);
96+
PostDetailDto postDetail = postService.getPostDetailById(postId, AuthUtil.getAuthenticatedMemberId());
11297
Long postOwnerId = postDetail.getPost().getMemberId();
113-
if (!postOwnerId.equals(currentMemberId) && !"ADMIN".equals(currentRole)) {
114-
return ResponseEntity.status(403).body(new ApiResponse<>(403, "본인 또는 관리자만 수정 가능합니다.", null));
115-
}
98+
AuthUtil.validateOwnerOrAdmin(postOwnerId);
11699
postService.patchUpdatePost(postId, postUpdateDto);
117-
PostDetailDto updated = postService.getPostDetailById(postId, currentMemberId);
100+
PostDetailDto updated = postService.getPostDetailById(postId, AuthUtil.getAuthenticatedMemberId());
118101
return ResponseEntity.ok(new ApiResponse<>(200, "게시글이 수정되었습니다.", updated));
119102
}
120103

121104
@Operation(summary = "게시글 삭제")
122105
@DeleteMapping("/{postId}")
123106
public ResponseEntity<ApiResponse<Void>> deletePost(@PathVariable Long postId) {
124-
Long currentMemberId = AuthUtil.getCurrentMemberId();
125-
String currentRole = AuthUtil.getCurrentMemberRole();
126-
PostDetailDto postDetail = postService.getPostDetailById(postId, currentMemberId);
107+
PostDetailDto postDetail = postService.getPostDetailById(postId, AuthUtil.getAuthenticatedMemberId());
127108
Long postOwnerId = postDetail.getPost().getMemberId();
128-
if (!postOwnerId.equals(currentMemberId) && !"ADMIN".equals(currentRole)) {
129-
return ResponseEntity.status(403).body(new ApiResponse<>(403, "본인 또는 관리자만 삭제 가능합니다.", null));
130-
}
109+
AuthUtil.validateOwnerOrAdmin(postOwnerId);
131110
postService.deletePost(postId);
132111
return ResponseEntity.ok(new ApiResponse<>(200, "게시글이 삭제되었습니다.", null));
133112
}
@@ -142,50 +121,23 @@ public ResponseEntity<ApiResponse<Void>> handleResponseStatusException(ResponseS
142121
@Operation(summary = "본인 게시글 단일 조회")
143122
@GetMapping("/my/{postId}")
144123
public ResponseEntity<ApiResponse<PostDto>> getMyPostById(@PathVariable Long postId) {
145-
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
146-
Object principal = authentication.getPrincipal();
147-
Long memberId;
148-
if (principal instanceof org.springframework.security.core.userdetails.User user) {
149-
memberId = Long.valueOf(user.getUsername());
150-
} else if (principal instanceof Long) {
151-
memberId = (Long) principal;
152-
} else {
153-
throw new IllegalArgumentException("올바른 회원 ID가 아닙니다");
154-
}
124+
Long memberId = AuthUtil.getAuthenticatedMemberId();
155125
PostDto postDto = postService.getMyPostById(postId, memberId);
156126
return ResponseEntity.ok(new ApiResponse<>(200, "본인 게시글 단일 조회 성공", postDto));
157127
}
158128

159129
@Operation(summary = "본인 게시글 전체 조회")
160130
@GetMapping("/my")
161131
public ResponseEntity<ApiResponse<List<PostDto>>> getMyPosts() {
162-
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
163-
Object principal = authentication.getPrincipal();
164-
Long memberId;
165-
if (principal instanceof org.springframework.security.core.userdetails.User user) {
166-
memberId = Long.valueOf(user.getUsername());
167-
} else if (principal instanceof Long) {
168-
memberId = (Long) principal;
169-
} else {
170-
throw new IllegalArgumentException("올바른 회원 ID가 아닙니다");
171-
}
132+
Long memberId = AuthUtil.getAuthenticatedMemberId();
172133
List<PostDto> posts = postService.getMyPosts(memberId);
173134
return ResponseEntity.ok(new ApiResponse<>(200, "본인 게시글 전체 조회 성공", posts));
174135
}
175136

176137
@Operation(summary = "게시글+투표 동시 등록")
177138
@PostMapping("/createPost")
178139
public ResponseEntity<ApiResponse<PostDetailDto>> createPostWithPoll(@RequestBody PostWithPollCreateDto dto) {
179-
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
180-
Object principal = authentication.getPrincipal();
181-
Long memberId;
182-
if (principal instanceof org.springframework.security.core.userdetails.User user) {
183-
memberId = Long.valueOf(user.getUsername());
184-
} else if (principal instanceof Long) {
185-
memberId = (Long) principal;
186-
} else {
187-
throw new ResponseStatusException(org.springframework.http.HttpStatus.UNAUTHORIZED, "인증 정보가 올바르지 않습니다.");
188-
}
140+
Long memberId = AuthUtil.getAuthenticatedMemberId();
189141
PostDetailDto result = postService.createPostWithPoll(dto, memberId);
190142
return ResponseEntity.ok(new ApiResponse<>(200, "게시글+투표 등록 완료", result));
191143
}
@@ -271,4 +223,43 @@ public ResponseEntity<ApiResponse<PostDto>> getTopClosedPoll() {
271223
PostDto post = postService.getTopPollByStatus(PollDto.PollStatus.CLOSED, memberId);
272224
return ResponseEntity.ok(new ApiResponse<>(200, "마감된 투표 Top 1 조회 성공", post));
273225
}
274-
}
226+
227+
@Operation(summary = "내가 참여한 진행중 투표 게시글 페이징 조회")
228+
@GetMapping("/my/ongoingPaged")
229+
public ResponseEntity<ApiResponse<PostPageDto>> getMyOngoingPostsPaged(
230+
@RequestParam(defaultValue = "0") int page,
231+
@RequestParam(defaultValue = "10") int size
232+
) {
233+
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
234+
Long memberId = AuthUtil.getAuthenticatedMemberId();
235+
Page<PostDto> posts = postService.getMyOngoingPostsPaged(pageable, memberId);
236+
PostPageDto response = new PostPageDto(posts);
237+
return ResponseEntity.ok(new ApiResponse<>(200, "내가 참여한 진행중 투표 게시글 페이징 조회 성공", response));
238+
}
239+
240+
@Operation(summary = "내가 참여한 마감 투표 게시글 페이징 조회")
241+
@GetMapping("/my/closedPaged")
242+
public ResponseEntity<ApiResponse<PostPageDto>> getMyClosedPostsPaged(
243+
@RequestParam(defaultValue = "0") int page,
244+
@RequestParam(defaultValue = "10") int size
245+
) {
246+
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
247+
Long memberId = AuthUtil.getAuthenticatedMemberId();
248+
Page<PostDto> posts = postService.getMyClosedPostsPaged(pageable, memberId);
249+
PostPageDto response = new PostPageDto(posts);
250+
return ResponseEntity.ok(new ApiResponse<>(200, "내가 참여한 마감 투표 게시글 페이징 조회 성공", response));
251+
}
252+
253+
@Operation(summary = "내가 참여한 모든 투표 게시글 페이징 조회")
254+
@GetMapping("/my/votedPaged")
255+
public ResponseEntity<ApiResponse<PostPageDto>> getMyVotedPostsPaged(
256+
@RequestParam(defaultValue = "0") int page,
257+
@RequestParam(defaultValue = "10") int size
258+
) {
259+
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
260+
Long memberId = AuthUtil.getAuthenticatedMemberId();
261+
Page<PostDto> posts = postService.getMyVotedPostsPaged(pageable, memberId);
262+
PostPageDto response = new PostPageDto(posts);
263+
return ResponseEntity.ok(new ApiResponse<>(200, "내가 참여한 모든 투표 게시글 페이징 조회 성공", response));
264+
}
265+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public interface PostService {
3636
Page<PostDto> getPostsPaged(Pageable pageable, Long memberId);
3737
Page<PostDto> getOngoingPostsPaged(Pageable pageable, Long memberId);
3838
Page<PostDto> getClosedPostsPaged(Pageable pageable, Long memberId);
39+
Page<PostDto> getMyOngoingPostsPaged(Pageable pageable, Long memberId);
40+
Page<PostDto> getMyClosedPostsPaged(Pageable pageable, Long memberId);
41+
Page<PostDto> getMyVotedPostsPaged(Pageable pageable, Long memberId);
3942

4043
// ===== 투표 Top 관련 =====
4144
List<PostDto> getTopNPollsByStatus(PollDto.PollStatus status, int n, Long memberId);

0 commit comments

Comments
 (0)