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 )
69+ @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE_TIME )
70+ LocalDateTime dateTime ,
71+ @ RequestParam (required = false ) String type ,
72+ @ RequestParam (required = false ) String category ,
73+ @ RequestParam (required = false ) UUID groupId ,
74+ @ AuthenticationPrincipal CustomOAuth2User user ,
75+ Pageable pageable ) {
76+
77+ try {
78+ List <CalendarResponseDTO > responses = calendarService .getCalendarsByUser (
79+ user .getUserId (), viewType , dateTime , type , category , groupId , pageable );
80+
81+ return ResponseEntity .ok (ApiResponse .success (responses ));
82+ } catch (Exception e ) {
83+ log .error ("일정 조회 실패 - 사용자: {}, 에러: {}" , user .getUserId (), e .getMessage ());
84+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
85+ }
86+ }
87+
88+ @ Operation (
89+ summary = "특정 일정 상세 조회" ,
90+ description = "특정 일정의 상세 정보를 조회합니다." ,
91+ security = @ SecurityRequirement (name = "bearerAuth" )
92+ )
93+ @ GetMapping ("/{calendarId}" )
94+ public ResponseEntity <ApiResponse <CalendarResponseDTO >> getCalendar (
95+ @ PathVariable Long calendarId ,
96+ @ AuthenticationPrincipal CustomOAuth2User user ) {
97+
98+ try {
99+ CalendarResponseDTO calendar = calendarService .getCalendarById (calendarId , user .getUserId ());
100+
101+ return ResponseEntity .ok (ApiResponse .success (calendar ));
102+
103+ } catch (CustomException e ) {
104+ log .warn ("일정 조회 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" , user .getUserId (), calendarId );
105+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
106+ } catch (Exception e ) {
107+ log .error ("일정 조회 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
108+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
109+ }
110+ }
111+
112+ @ Operation (
113+ summary = "일정 수정" ,
114+ description = "기존 일정의 정보를 수정합니다." ,
115+ security = @ SecurityRequirement (name = "bearerAuth" )
116+ )
117+ @ PatchMapping ("/{calendarId}" )
118+ public ResponseEntity <ApiResponse <CalendarResponseDTO >> updateCalendar (
119+ @ PathVariable Long calendarId ,
120+ @ Valid @ RequestBody UpdateCalendarRequestDTO request ,
121+ @ AuthenticationPrincipal CustomOAuth2User user ) {
122+
123+ try {
124+ CalendarResponseDTO calendar = calendarService .updateCalendar (calendarId , request , user .getUserId ());
125+
126+ return ResponseEntity .ok (ApiResponse .success (calendar ));
127+
128+ } catch (CustomException e ) {
129+ log .warn ("일정 수정 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" , user .getUserId (), calendarId );
130+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
131+
132+ } catch (Exception e ) {
133+ log .error ("일정 수정 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
134+ throw new CustomException (ErrorCode .CALENDAR_UPDATE_FAILED );
135+ }
136+ }
137+
138+ @ Operation (
139+ summary = "일정 삭제" ,
140+ description = "기존 일정을 삭제합니다." ,
141+ security = @ SecurityRequirement (name = "bearerAuth" )
142+ )
143+ @ DeleteMapping ("/{calendarId}" )
144+ public ResponseEntity <ApiResponse <Void >> deleteCalendar (
145+ @ PathVariable Long calendarId ,
146+ @ AuthenticationPrincipal CustomOAuth2User user ) {
147+
148+ try {
149+ calendarService .deleteCalendar (calendarId , user .getUserId ());
150+
151+ return ResponseEntity .ok (ApiResponse .success ());
152+
153+ } catch (CustomException e ) {
154+ log .warn ("일정 삭제 실패 - 권한 없음: 사용자 {}, 일정 ID: {}" ,
155+ user .getUserId (), calendarId );
156+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
157+
158+ } catch (Exception e ) {
159+ log .error ("일정 삭제 실패 - 일정 ID: {}, 에러: {}" , calendarId , e .getMessage ());
160+ throw new CustomException (ErrorCode .CALENDAR_DELETE_FAILED );
161+ }
162+ }
163+
164+ @ Operation (
165+ summary = "그룹 일정 목록 조회" ,
166+ description = "특정 그룹의 모든 일정을 조회합니다. (필터링 가능)" ,
167+ security = @ SecurityRequirement (name = "bearerAuth" )
168+ )
169+ @ GetMapping ("/groups/{groupId}" )
170+ public ResponseEntity <ApiResponse <List <CalendarResponseDTO >>> getGroupCalendars (
171+ @ PathVariable UUID groupId ,
172+ @ RequestParam (required = false , defaultValue = "MONTHLY" ) String viewType ,
173+ @ RequestParam (required = false )
174+ @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE_TIME )
175+ LocalDateTime dateTime ,
176+ @ RequestParam (required = false ) String type ,
177+ @ RequestParam (required = false ) String category ,
178+ @ AuthenticationPrincipal CustomOAuth2User user ,
179+ Pageable pageable ) {
180+
181+ try {
182+ if (!calendarService .isGroupMember (groupId , user .getUserId ())) {
183+ throw new CustomException (ErrorCode .CALENDAR_ACCESS_DENIED );
184+ }
185+
186+ List <CalendarResponseDTO > responses = calendarService .getCalendarsByUser (
187+ user .getUserId (), viewType , dateTime , type , category , groupId , pageable );
188+
189+ return ResponseEntity .ok (ApiResponse .success (responses ));
190+
191+ } catch (Exception e ) {
192+ log .error ("그룹 일정 조회 실패 - 그룹 ID: {}, 에러: {}" , groupId , e .getMessage ());
193+ throw new CustomException (ErrorCode .CALENDAR_FOUND_FAILED );
194+ }
195+ }
196+ }
0 commit comments