Skip to content

Commit 4fbd70c

Browse files
authored
Merge pull request #169 from prgrms-web-devcourse-final-project/feature/EA3-134-study-optimal-time-vote
[EA3-134] refactor: 스터디 모임시간 조율 전체 구조 리팩터링 및 응답/요청 구조 개선
2 parents 2ad0fa2 + 40fa20f commit 4fbd70c

18 files changed

+279
-285
lines changed
Lines changed: 48 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,86 @@
11
package grep.neogul_coder.domain.timevote.controller;
22

3-
import grep.neogul_coder.domain.timevote.dto.request.*;
4-
import grep.neogul_coder.domain.timevote.dto.response.*;
3+
import grep.neogul_coder.domain.timevote.dto.request.TimeVoteCreateRequest;
4+
import grep.neogul_coder.domain.timevote.dto.request.TimeVoteDeleteRequest;
5+
import grep.neogul_coder.domain.timevote.dto.request.TimeVotePeriodCreateRequest;
6+
import grep.neogul_coder.domain.timevote.dto.request.TimeVoteUpdateRequest;
7+
import grep.neogul_coder.domain.timevote.dto.response.TimeVotePeriodResponse;
8+
import grep.neogul_coder.domain.timevote.dto.response.TimeVoteResponse;
9+
import grep.neogul_coder.domain.timevote.dto.response.TimeVoteStatListResponse;
10+
import grep.neogul_coder.domain.timevote.dto.response.TimeVoteSubmissionStatusResponse;
11+
import grep.neogul_coder.domain.timevote.service.TimeVotePeriodService;
12+
import grep.neogul_coder.global.auth.Principal;
513
import grep.neogul_coder.global.response.ApiResponse;
614
import jakarta.validation.Valid;
15+
import java.util.Collections;
716
import java.util.List;
8-
import org.springframework.web.bind.annotation.*;
17+
import lombok.RequiredArgsConstructor;
18+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
19+
import org.springframework.web.bind.annotation.DeleteMapping;
20+
import org.springframework.web.bind.annotation.GetMapping;
21+
import org.springframework.web.bind.annotation.PathVariable;
22+
import org.springframework.web.bind.annotation.PostMapping;
23+
import org.springframework.web.bind.annotation.PutMapping;
24+
import org.springframework.web.bind.annotation.RequestBody;
25+
import org.springframework.web.bind.annotation.RequestMapping;
26+
import org.springframework.web.bind.annotation.RestController;
927

1028
@RestController
29+
@RequiredArgsConstructor
1130
@RequestMapping("/api/studies/{studyId}/time-vote")
1231
public class TimeVoteController implements TimeVoteSpecification {
1332

33+
private final TimeVotePeriodService timeVotePeriodService;
34+
1435
@PostMapping("/periods")
1536
public ApiResponse<TimeVotePeriodResponse> createPeriod(
1637
@PathVariable("studyId") Long studyId,
17-
@RequestBody @Valid TimeVotePeriodCreateRequest request
18-
) {
19-
return ApiResponse.success(new TimeVotePeriodResponse());
20-
}
21-
22-
@GetMapping("/periods/{periodId}/stats")
23-
public ApiResponse<List<TimeVoteStatResponse>> getVoteStats(
24-
@PathVariable("studyId") Long studyId,
25-
@PathVariable("periodId") Long periodId
38+
@RequestBody @Valid TimeVotePeriodCreateRequest request,
39+
@AuthenticationPrincipal Principal userDetails
2640
) {
27-
return ApiResponse.success(List.of(new TimeVoteStatResponse()));
41+
return ApiResponse.success(new TimeVotePeriodResponse()); // mock response
2842
}
2943

30-
@PostMapping("/single")
44+
@PostMapping("/votes")
3145
public ApiResponse<TimeVoteResponse> submitVote(
3246
@PathVariable("studyId") Long studyId,
33-
@RequestBody @Valid TimeVoteCreateRequest request
34-
) {
35-
return ApiResponse.success(new TimeVoteResponse());
36-
}
37-
38-
@PostMapping("/bulk")
39-
public ApiResponse<List<TimeVoteResponse>> submitVotes(
40-
@PathVariable("studyId") Long studyId,
41-
@RequestBody @Valid TimeVoteBulkCreateRequest request
47+
@RequestBody @Valid TimeVoteCreateRequest request,
48+
@AuthenticationPrincipal Principal userDetails
4249
) {
43-
return ApiResponse.success(List.of(new TimeVoteResponse()));
50+
return ApiResponse.success(new TimeVoteResponse()); // mock response
4451
}
4552

46-
@PutMapping("/single")
53+
@PutMapping("/votes")
4754
public ApiResponse<TimeVoteResponse> updateVote(
4855
@PathVariable("studyId") Long studyId,
49-
@RequestBody @Valid TimeVoteUpdateRequest request
50-
) {
51-
return ApiResponse.success(new TimeVoteResponse());
52-
}
53-
54-
@PutMapping("/bulk")
55-
public ApiResponse<List<TimeVoteResponse>> updateVotes(
56-
@PathVariable("studyId") Long studyId,
57-
@RequestBody @Valid TimeVoteBulkUpdateRequest request
56+
@RequestBody @Valid TimeVoteUpdateRequest request,
57+
@AuthenticationPrincipal Principal userDetails
5858
) {
59-
return ApiResponse.success(List.of(new TimeVoteResponse()));
59+
return ApiResponse.success(new TimeVoteResponse()); // mock response
6060
}
6161

62-
63-
@DeleteMapping("/single")
64-
public ApiResponse<Void> deleteVotes(
62+
@DeleteMapping("/votes")
63+
public ApiResponse<Void> deleteAllVotes(
6564
@PathVariable("studyId") Long studyId,
66-
@RequestBody @Valid TimeVoteDeleteRequest request
65+
@RequestBody @Valid TimeVoteDeleteRequest request,
66+
@AuthenticationPrincipal Principal userDetails
6767
) {
68-
return ApiResponse.noContent();
68+
return ApiResponse.noContent(); // mock response
6969
}
7070

71-
@DeleteMapping("/bulk")
72-
public ApiResponse<Void> deleteMultipleVotes(
71+
@GetMapping("/periods/stats")
72+
public ApiResponse<TimeVoteStatListResponse> getVoteStats(
7373
@PathVariable("studyId") Long studyId,
74-
@RequestBody @Valid TimeVoteBulkDeleteRequest request
74+
@AuthenticationPrincipal Principal userDetails
7575
) {
76-
return ApiResponse.noContent();
76+
return ApiResponse.success(new TimeVoteStatListResponse()); // mock response
7777
}
7878

79-
@DeleteMapping("/all")
80-
public ApiResponse<Void> deleteAllVotes(
79+
@GetMapping("/periods/submissions")
80+
public ApiResponse<List<TimeVoteSubmissionStatusResponse>> getSubmissionStatusList(
8181
@PathVariable("studyId") Long studyId,
82-
@RequestParam("periodId") Long periodId,
83-
@RequestParam("studyMemberId") Long studyMemberId
82+
@AuthenticationPrincipal Principal userDetails
8483
) {
85-
return ApiResponse.noContent();
84+
return ApiResponse.success(Collections.emptyList()); // mock response
8685
}
8786
}

src/main/java/grep/neogul_coder/domain/timevote/controller/TimeVoteSpecification.java

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import grep.neogul_coder.domain.timevote.dto.request.*;
44
import grep.neogul_coder.domain.timevote.dto.response.*;
5+
import grep.neogul_coder.global.auth.Principal;
56
import grep.neogul_coder.global.response.ApiResponse;
67
import io.swagger.v3.oas.annotations.Operation;
78
import io.swagger.v3.oas.annotations.Parameter;
@@ -10,61 +11,46 @@
1011
import java.util.List;
1112
import org.springframework.web.bind.annotation.RequestBody;
1213

13-
@Tag(name = "Time-Vote", description = "스터디 모임 최적 시간 조율 API")
14+
@Tag(name = "Time-Vote", description = "스터디 모임 시간 조율 API")
1415
public interface TimeVoteSpecification {
1516

16-
@Operation(summary = "최적 시간 투표 기간 생성", description = "팀장이 가능한 시간 요청을 생성합니다.")
17+
@Operation(summary = "스터디 모임 일정 투표 기간 생성", description = "팀장이 가능한 시간 요청을 생성합니다.")
1718
ApiResponse<TimeVotePeriodResponse> createPeriod(
1819
@Parameter(description = "스터디 ID", example = "1") Long studyId,
19-
@RequestBody @Valid TimeVotePeriodCreateRequest request
20+
@RequestBody @Valid TimeVotePeriodCreateRequest request,
21+
Principal userDetails
2022
);
2123

22-
@Operation(summary = "사용자 특정 가능 시간대 제출", description = "스터디 멤버가 단일 가능 시간을 제출합니다.")
24+
@Operation(summary = "사용자 가능 시간대 제출", description = "스터디 멤버가 가능 시간을 제출합니다.")
2325
ApiResponse<TimeVoteResponse> submitVote(
2426
@Parameter(description = "스터디 ID", example = "1") Long studyId,
25-
@RequestBody @Valid TimeVoteCreateRequest request
27+
@RequestBody @Valid TimeVoteCreateRequest request,
28+
Principal userDetails
2629
);
2730

28-
@Operation(summary = "사용자 여러 가능 시간대 제출", description = "스터디 멤버가 여러 가능 시간을 제출합니다.")
29-
ApiResponse<List<TimeVoteResponse>> submitVotes(
30-
@Parameter(description = "스터디 ID", example = "1") Long studyId,
31-
@RequestBody @Valid TimeVoteBulkCreateRequest request
32-
);
33-
34-
@Operation(summary = "사용자 특정 시간대 수정", description = "사용자가 기존 제출한 시간 중 하나를 수정합니다.")
31+
@Operation(summary = "사용자 시간대 수정", description = "사용자가 기존에 제출한 시간을 수정합니다.")
3532
ApiResponse<TimeVoteResponse> updateVote(
36-
@Parameter(description = "스터디 ID") Long studyId,
37-
@RequestBody @Valid TimeVoteUpdateRequest request
38-
);
39-
40-
@Operation(summary = "사용자 여러 시간대 수정", description = "사용자가 제출한 여러 시간대를 수정합니다.")
41-
ApiResponse<List<TimeVoteResponse>> updateVotes(
42-
@Parameter(description = "스터디 ID") Long studyId,
43-
@RequestBody @Valid TimeVoteBulkUpdateRequest request
44-
);
45-
46-
@Operation(summary = "사용자 특정 시간대 삭제", description = "사용자가 특정 시간대만 삭제합니다.")
47-
ApiResponse<Void> deleteVotes(
48-
@Parameter(description = "스터디 ID") Long studyId,
49-
@RequestBody @Valid TimeVoteDeleteRequest request
50-
);
51-
52-
@Operation(summary = "사용자 여러 시간대 삭제", description = "사용자가 선택한 여러 시간대를 삭제합니다.")
53-
ApiResponse<Void> deleteMultipleVotes(
54-
@Parameter(description = "스터디 ID") Long studyId,
55-
@RequestBody @Valid TimeVoteBulkDeleteRequest request
33+
@Parameter(description = "스터디 ID", example = "1") Long studyId,
34+
@RequestBody @Valid TimeVoteUpdateRequest request,
35+
Principal userDetails
5636
);
5737

5838
@Operation(summary = "사용자 전체 시간 삭제", description = "사용자가 제출한 시간 전체를 삭제합니다.")
5939
ApiResponse<Void> deleteAllVotes(
60-
@Parameter(description = "스터디 ID") Long studyId,
61-
@Parameter(description = "투표 기간 ID") Long periodId,
62-
@Parameter(description = "스터디 멤버 ID") Long studyMemberId
40+
@Parameter(description = "스터디 ID", example = "1") Long studyId,
41+
@RequestBody @Valid TimeVoteDeleteRequest request,
42+
Principal userDetails
43+
);
44+
45+
@Operation(summary = "투표 통계 조회", description = "투표 기간의 시간대별 통계 정보를 조회합니다.")
46+
ApiResponse<TimeVoteStatListResponse> getVoteStats(
47+
@Parameter(description = "스터디 ID", example = "1") Long studyId,
48+
Principal userDetails
6349
);
6450

65-
@Operation(summary = "투표 통계 조회", description = "특정 투표 기간의 시간대별 통계 정보를 조회합니다.")
66-
ApiResponse<List<TimeVoteStatResponse>> getVoteStats(
51+
@Operation(summary = "사용자별 제출 여부 조회", description = "특정 스터디의 모든 멤버별 시간 제출 여부를 반환합니다.")
52+
ApiResponse<List<TimeVoteSubmissionStatusResponse>> getSubmissionStatusList(
6753
@Parameter(description = "스터디 ID", example = "1") Long studyId,
68-
@Parameter(description = "투표 기간 ID", example = "5") Long periodId
54+
Principal userDetails
6955
);
7056
}

src/main/java/grep/neogul_coder/domain/timevote/dto/request/TimeVoteBulkCreateRequest.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/main/java/grep/neogul_coder/domain/timevote/dto/request/TimeVoteBulkDeleteRequest.java

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/main/java/grep/neogul_coder/domain/timevote/dto/request/TimeVoteBulkUpdateRequest.java

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
package grep.neogul_coder.domain.timevote.dto.request;
22

33
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotEmpty;
45
import jakarta.validation.constraints.NotNull;
56
import java.time.LocalDateTime;
7+
import java.util.List;
8+
import lombok.Builder;
69
import lombok.Getter;
710

811
@Getter
9-
@Schema(description = "스터디 모임 일정 조율 - 단일 가능 시간 제출 요청 DTO")
12+
@Schema(description = "스터디 모임 일정 조율 - 가능 시간 제출 요청 DTO")
1013
public class TimeVoteCreateRequest {
1114

12-
@NotNull
13-
@Schema(description = "기간 ID", example = "5")
14-
private Long periodId;
15-
1615
@NotNull
1716
@Schema(description = "스터디 멤버 ID", example = "12")
1817
private Long studyMemberId;
1918

20-
@NotNull
21-
@Schema(description = "시작 시간", example = "2025-07-16T10:00:00")
22-
private LocalDateTime startTime;
19+
@NotEmpty
20+
@Schema(description = "시간대 리스트", example = "[2025-07-15T10:00:00, 2025-07-15T11:00:00]")
21+
private List<LocalDateTime> timeSlots;
2322

24-
@NotNull
25-
@Schema(description = "종료 시간", example = "2025-07-16T13:00:00")
26-
private LocalDateTime endTime;
23+
private TimeVoteCreateRequest() {}
24+
25+
@Builder
26+
private TimeVoteCreateRequest(Long studyMemberId, List<LocalDateTime> timeSlots) {
27+
this.studyMemberId = studyMemberId;
28+
this.timeSlots = timeSlots;
29+
}
2730
}

0 commit comments

Comments
 (0)