1+ package store .lastdance .controller .calendar ;
2+
3+ import io .swagger .v3 .oas .annotations .Operation ;
4+ import io .swagger .v3 .oas .annotations .security .SecurityRequirement ;
5+ import io .swagger .v3 .oas .annotations .tags .Tag ;
6+ import jakarta .validation .Valid ;
7+ import lombok .RequiredArgsConstructor ;
8+ import lombok .extern .slf4j .Slf4j ;
9+ import org .springframework .data .domain .Pageable ;
10+ import org .springframework .format .annotation .DateTimeFormat ;
11+ import org .springframework .http .HttpStatus ;
12+ import org .springframework .http .ResponseEntity ;
13+ import org .springframework .security .core .annotation .AuthenticationPrincipal ;
14+ import org .springframework .web .bind .annotation .*;
15+ import store .lastdance .dto .calender .request .CreateCalendarRequestDTO ;
16+ import store .lastdance .dto .calender .request .UpdateCalendarRequestDTO ;
17+ import store .lastdance .dto .calender .response .CalendarResponseDTO ;
18+ import store .lastdance .dto .response .ApiResponse ;
19+ import store .lastdance .exception .CustomException ;
20+ import store .lastdance .exception .ErrorCode ;
21+ import store .lastdance .security .oauth .CustomOAuth2User ;
22+ import store .lastdance .service .calendar .CalendarV2Service ;
23+
24+ import java .time .LocalDateTime ;
25+ import java .util .List ;
26+ import java .util .UUID ;
27+
28+ @ Tag (name = "Calender" , description = "캘린더 관리 API" )
29+ @ RestController
30+ @ RequestMapping ("/api/v2/calendars" )
31+ @ RequiredArgsConstructor
32+ @ Slf4j
33+ public class CalendarV2Controller {
34+
35+ private final CalendarV2Service calendarService ;
36+
37+ @ Operation (
38+ summary = "캘린더 생성" ,
39+ description = "새로운 일정을 생성합니다." ,
40+ security = @ SecurityRequirement (name = "bearerAuth" )
41+ )
42+ @ PostMapping
43+ public ResponseEntity <ApiResponse <CalendarResponseDTO >> createCalendar (
44+ @ Valid @ RequestBody CreateCalendarRequestDTO request ,
45+ @ RequestParam (required = false ) UUID groupId ,
46+ @ AuthenticationPrincipal CustomOAuth2User user ) {
47+
48+ try {
49+ CalendarResponseDTO calendar = calendarService .createCalendar (request , user .getUserId (), groupId );
50+
51+ return ResponseEntity .status (HttpStatus .CREATED )
52+ .body (ApiResponse .success (calendar ));
53+
54+ } catch (Exception e ) {
55+ log .error ("일정 생성 실패 - 사용자: {}, 에러: {}" , user .getUserId (), e .getMessage (), e );
56+ throw new CustomException (ErrorCode .CALENDAR_CREATE_FAILED );
57+ }
58+ }
59+
60+ @ Operation (
61+ summary = "내 일정 목록 조회" ,
62+ description = "사용자의 모든 일정을 조회합니다. (필터링 가능)" ,
63+ security = @ SecurityRequirement (name = "bearerAuth" )
64+ )
65+ @ GetMapping ("/me" )
66+ public ResponseEntity <ApiResponse <List <CalendarResponseDTO >>> getMyCalendars (
67+ @ RequestParam (required = false , defaultValue = "MONTHLY" ) String viewType ,
68+ @ RequestParam (required = false ) LocalDateTime dateTime ,
69+ @ RequestParam (required = false ) String type ,
70+ @ RequestParam (required = false ) String category ,
71+ @ RequestParam (required = false ) UUID groupId ,
72+ @ AuthenticationPrincipal CustomOAuth2User user ,
73+ Pageable pageable ) {
74+
75+ try {
76+ List <CalendarResponseDTO > responses = calendarService .getCalendarsByUser (
77+ user .getUserId (), viewType , dateTime , type , category , groupId , pageable );
78+
79+ return ResponseEntity .ok (ApiResponse .success (responses ));
80+ } catch (Exception e ) {
81+ log .error ("일정 조회 실패 - 사용자: {}, 에러: {}" , user .getUserId (), e .getMessage ());
82+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
83+ }
84+ }
85+
86+ @ Operation (
87+ summary = "특정 일정 상세 조회" ,
88+ description = "특정 일정의 상세 정보를 조회합니다." ,
89+ security = @ SecurityRequirement (name = "bearerAuth" )
90+ )
91+ @ GetMapping ("/{calendarId}" )
92+ public ResponseEntity <ApiResponse <CalendarResponseDTO >> getCalendar (
93+ @ PathVariable Long calendarId ,
94+ @ AuthenticationPrincipal CustomOAuth2User user ) {
95+
96+ try {
97+ CalendarResponseDTO calendar = calendarService .getCalendarById (calendarId , user .getUserId ());
98+
99+ return ResponseEntity .ok (ApiResponse .success (calendar ));
100+
101+ } catch (CustomException e ) {
102+ log .warn ("일정 조회 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" , user .getUserId (), calendarId );
103+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
104+ } catch (Exception e ) {
105+ log .error ("일정 조회 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
106+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
107+ }
108+ }
109+
110+ @ Operation (
111+ summary = "일정 수정" ,
112+ description = "기존 일정의 정보를 수정합니다." ,
113+ security = @ SecurityRequirement (name = "bearerAuth" )
114+ )
115+ @ PatchMapping ("/{calendarId}" )
116+ public ResponseEntity <ApiResponse <CalendarResponseDTO >> updateCalendar (
117+ @ PathVariable Long calendarId ,
118+ @ Valid @ RequestBody UpdateCalendarRequestDTO request ,
119+ @ AuthenticationPrincipal CustomOAuth2User user ) {
120+
121+ try {
122+ CalendarResponseDTO calendar = calendarService .updateCalendar (calendarId , request , user .getUserId ());
123+
124+ return ResponseEntity .ok (ApiResponse .success (calendar ));
125+
126+ } catch (CustomException e ) {
127+ log .warn ("일정 수정 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" , user .getUserId (), calendarId );
128+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
129+
130+ } catch (Exception e ) {
131+ log .error ("일정 수정 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
132+ throw new CustomException (ErrorCode .CALENDAR_UPDATE_FAILED );
133+ }
134+ }
135+
136+ @ Operation (
137+ summary = "일정 삭제" ,
138+ description = "기존 일정을 삭제합니다." ,
139+ security = @ SecurityRequirement (name = "bearerAuth" )
140+ )
141+ @ DeleteMapping ("/{calendarId}" )
142+ public ResponseEntity <ApiResponse <Void >> deleteCalendar (
143+ @ PathVariable Long calendarId ,
144+ @ RequestParam (required = false )
145+ @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE_TIME )
146+ LocalDateTime instanceDate ,
147+ @ AuthenticationPrincipal CustomOAuth2User user ) {
148+
149+ try {
150+ calendarService .deleteCalendar (calendarId , instanceDate , user .getUserId ());
151+
152+ return ResponseEntity .ok (ApiResponse .success ());
153+
154+ } catch (CustomException e ) {
155+ log .warn ("일정 삭제 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" ,
156+ user .getUserId (), calendarId );
157+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
158+
159+ } catch (Exception e ) {
160+ log .error ("일정 삭제 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
161+ throw new CustomException (ErrorCode .CALENDAR_DELETE_FAILED );
162+ }
163+ }
164+
165+ @ Operation (
166+ summary = "그룹 일정 목록 조회" ,
167+ description = "특정 그룹의 모든 일정을 조회합니다. (필터링 가능)" ,
168+ security = @ SecurityRequirement (name = "bearerAuth" )
169+ )
170+ @ GetMapping ("/groups/{groupId}" )
171+ public ResponseEntity <ApiResponse <List <CalendarResponseDTO >>> getGroupCalendars (
172+ @ PathVariable UUID groupId ,
173+ @ RequestParam (required = false , defaultValue = "MONTHLY" ) String viewType ,
174+ @ RequestParam (required = false ) LocalDateTime dateTime ,
175+ @ RequestParam (required = false ) String type ,
176+ @ RequestParam (required = false ) String category ,
177+ @ AuthenticationPrincipal CustomOAuth2User user ,
178+ Pageable pageable ) {
179+
180+ try {
181+ if (!calendarService .isGroupMember (groupId , user .getUserId ())) {
182+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
183+ }
184+
185+ List <CalendarResponseDTO > responses = calendarService .getCalendarsByUser (
186+ user .getUserId (), viewType , dateTime , type , category , groupId , pageable );
187+
188+ return ResponseEntity .ok (ApiResponse .success (responses ));
189+
190+ } catch (Exception e ) {
191+ log .error ("그룹 일정 조회 실패 - 그룹 ID: {}, 에러: {}" , groupId , e .getMessage ());
192+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
193+ }
194+ }
195+ }
0 commit comments