Skip to content

Commit 33ad385

Browse files
authored
Merge pull request #204 from prgrms-aibe-devcourse/refactor/v2-calendar-exception
refector: 캘린더 예외처리, validate 정리, dto 정리
2 parents f7f83ce + 7d9b071 commit 33ad385

14 files changed

Lines changed: 426 additions & 440 deletions

File tree

src/main/java/store/lastdance/controller/calendar/CalendarController.java

Lines changed: 28 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
import org.springframework.http.ResponseEntity;
1616
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1717
import org.springframework.web.bind.annotation.*;
18-
import store.lastdance.domain.calendar.Calendar;
18+
import store.lastdance.exception.CustomException;
19+
import store.lastdance.exception.ErrorCode;
1920
import store.lastdance.security.oauth.CustomOAuth2User;
2021
import store.lastdance.dto.calender.request.CreateCalendarRequestDTO;
2122
import store.lastdance.dto.calender.request.UpdateCalendarRequestDTO;
@@ -66,21 +67,18 @@ public class CalendarController {
6667
@PostMapping
6768
public ResponseEntity<ApiResponse<CalendarResponseDTO>> createCalendar(
6869
@Valid @RequestBody CreateCalendarRequestDTO request,
70+
@RequestParam(required = false) UUID groupId,
6971
@AuthenticationPrincipal CustomOAuth2User user) {
70-
UUID userId = user.getUserId();
7172

7273
try {
73-
Calendar calendar = calendarService.createCalendar(request, userId);
74-
CalendarResponseDTO response = CalendarResponseDTO.from(calendar);
74+
CalendarResponseDTO calendar = calendarService.createCalendar(request, user.getUserId(), groupId);
7575

7676
return ResponseEntity.status(HttpStatus.CREATED)
77-
.body(ApiResponse.success(response, "일정이 성공적으로 생성되었습니다."));
77+
.body(ApiResponse.success(calendar));
7878

7979
} catch (Exception e) {
80-
log.error("일정 생성 실패 - 사용자: {}, 에러: {}",
81-
userId, e.getMessage());
82-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
83-
.body(ApiResponse.error("일정 생성에 실패했습니다: " + e.getMessage()));
80+
log.error("일정 생성 실패 - 사용자: {}, 에러: {}", user.getUserId(), e.getMessage(), e);
81+
throw new CustomException(ErrorCode.CALENDAR_CREATE_FAILED);
8482
}
8583
}
8684

@@ -127,19 +125,14 @@ public ResponseEntity<ApiResponse<List<CalendarResponseDTO>>> getMyCalendars(
127125
dateTime = LocalDateTime.now();
128126
}
129127

130-
log.info("일정 목록 조회 - 사용자: {}, 달력 종류: {}, 기준 날짜: {}",
131-
userId, viewType, dateTime);
132-
133128
try {
134129
List<CalendarResponseDTO> responses = calendarService.getCalendarsByUser(
135130
userId, viewType, dateTime, type, category, groupId, pageable);
136131

137132
return ResponseEntity.ok(ApiResponse.success(responses));
138133
} catch (Exception e) {
139-
log.error("일정 조회 실패 - 사용자: {}, 에러: {}",
140-
userId, e.getMessage());
141-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
142-
.body(ApiResponse.error("일정 조회에 실패했습니다."));
134+
log.error("일정 조회 실패 - 사용자: {}, 에러: {}", userId, e.getMessage());
135+
throw new CustomException(ErrorCode.CALENDAR_FOUND_FAILED);
143136
}
144137
}
145138

@@ -180,25 +173,18 @@ public ResponseEntity<ApiResponse<CalendarResponseDTO>> getCalendar(
180173
@PathVariable Long calendarId,
181174
@AuthenticationPrincipal CustomOAuth2User user) {
182175
UUID userId = user.getUserId();
183-
log.info("일정 상세 조회 - 사용자: {}, 일정 ID: {}",
184-
userId, calendarId);
185176

186177
try {
187-
Calendar calendar = calendarService.getCalendarById(calendarId, userId);
188-
CalendarResponseDTO response = CalendarResponseDTO.from(calendar);
178+
CalendarResponseDTO calendar = calendarService.getCalendarById(calendarId, userId);
189179

190-
return ResponseEntity.ok(ApiResponse.success(response));
191-
192-
} catch (IllegalArgumentException e) {
193-
log.warn("일정 조회 실패 - 권한 없음: 사용자 {}, 일정 ID: {}",
194-
userId, calendarId);
195-
return ResponseEntity.status(HttpStatus.FORBIDDEN)
196-
.body(ApiResponse.error("해당 일정에 접근할 권한이 없습니다."));
180+
return ResponseEntity.ok(ApiResponse.success(calendar));
197181

182+
} catch (CustomException e) {
183+
log.warn("일정 조회 실패 - 권한 없음: 사용자 {}, 일정 ID: {}", userId, calendarId);
184+
throw new CustomException(ErrorCode.CALENDAR_ACCESS_DENIED);
198185
} catch (Exception e) {
199186
log.error("일정 조회 실패 - 일정 ID: {}, 에러: {}", calendarId, e.getMessage());
200-
return ResponseEntity.status(HttpStatus.NOT_FOUND)
201-
.body(ApiResponse.error("일정을 찾을 수 없습니다."));
187+
throw new CustomException(ErrorCode.CALENDAR_FOUND_FAILED);
202188
}
203189
}
204190

@@ -242,25 +228,18 @@ public ResponseEntity<ApiResponse<CalendarResponseDTO>> updateCalendar(
242228

243229
UUID userId = user.getUserId();
244230

245-
log.info("일정 수정 요청 - 사용자: {}, 일정 ID: {}",
246-
userId, calendarId);
247-
248231
try {
249-
Calendar calendar = calendarService.updateCalendar(calendarId, request, userId);
250-
CalendarResponseDTO response = CalendarResponseDTO.from(calendar);
232+
CalendarResponseDTO calendar = calendarService.updateCalendar(calendarId, request, userId);
251233

252-
return ResponseEntity.ok(ApiResponse.success(response, "일정이 성공적으로 수정되었습니다."));
234+
return ResponseEntity.ok(ApiResponse.success(calendar));
253235

254-
} catch (IllegalArgumentException e) {
255-
log.warn("일정 수정 실패 - 권한 없음: 사용자 {}, 일정 ID: {}",
256-
userId, calendarId);
257-
return ResponseEntity.status(HttpStatus.FORBIDDEN)
258-
.body(ApiResponse.error("해당 일정을 수정할 권한이 없습니다."));
236+
} catch (CustomException e) {
237+
log.warn("일정 수정 실패 - 권한 없음: 사용자 {}, 일정 ID: {}", userId, calendarId);
238+
throw new CustomException(ErrorCode.CALENDAR_ACCESS_DENIED);
259239

260240
} catch (Exception e) {
261241
log.error("일정 수정 실패 - 일정 ID: {}, 에러: {}", calendarId, e.getMessage());
262-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
263-
.body(ApiResponse.error("일정 수정에 실패했습니다: " + e.getMessage()));
242+
throw new CustomException(ErrorCode.CALENDAR_UPDATE_FAILED);
264243
}
265244
}
266245

@@ -299,32 +278,26 @@ public ResponseEntity<ApiResponse<CalendarResponseDTO>> updateCalendar(
299278
@DeleteMapping("/{calendarId}")
300279
public ResponseEntity<ApiResponse<Void>> deleteCalendar(
301280
@PathVariable Long calendarId,
302-
// @RequestParam(required = false, defaultValue = "all") String deleteType,
303281
@RequestParam(required = false)
304282
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
305283
LocalDateTime instanceDate,
306284
@AuthenticationPrincipal CustomOAuth2User user) {
307-
System.out.println(instanceDate);
308-
UUID userId = user.getUserId();
309285

310-
log.info("일정 삭제 요청 - 사용자: {}, 일정 ID: {}",
311-
userId, calendarId);
286+
UUID userId = user.getUserId();
312287

313288
try {
314289
calendarService.deleteCalendar(calendarId, instanceDate, userId);
315290

316-
return ResponseEntity.ok(ApiResponse.success(null, "일정이 성공적으로 삭제되었습니다."));
291+
return ResponseEntity.ok(ApiResponse.success());
317292

318-
} catch (IllegalArgumentException e) {
293+
} catch (CustomException e) {
319294
log.warn("일정 삭제 실패 - 권한 없음: 사용자 {}, 일정 ID: {}",
320295
userId, calendarId);
321-
return ResponseEntity.status(HttpStatus.FORBIDDEN)
322-
.body(ApiResponse.error("해당 일정을 삭제할 권한이 없습니다."));
296+
throw new CustomException(ErrorCode.CALENDAR_ACCESS_DENIED);
323297

324298
} catch (Exception e) {
325299
log.error("일정 삭제 실패 - 일정 ID: {}, 에러: {}", calendarId, e.getMessage());
326-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
327-
.body(ApiResponse.error("일정 삭제에 실패했습니다: " + e.getMessage()));
300+
throw new CustomException(ErrorCode.CALENDAR_DELETE_FAILED);
328301
}
329302
}
330303

@@ -376,14 +349,9 @@ public ResponseEntity<ApiResponse<List<CalendarResponseDTO>>> getGroupCalendars(
376349
dateTime = LocalDateTime.now();
377350
}
378351

379-
log.info("그룹 일정 조회 - 사용자: {}, 그룹 ID: {}, 달력 종류: {}, 기준 날짜: {}",
380-
userId, groupId, viewType, dateTime);
381-
382352
try {
383-
// 그룹 멤버 권한 확인
384353
if (!calendarService.isGroupMember(groupId, userId)) {
385-
return ResponseEntity.status(HttpStatus.FORBIDDEN)
386-
.body(ApiResponse.error("해당 그룹에 접근할 권한이 없습니다."));
354+
throw new CustomException(ErrorCode.CALENDAR_ACCESS_DENIED);
387355
}
388356

389357
List<CalendarResponseDTO> responses = calendarService.getCalendarsByUser(
@@ -393,8 +361,7 @@ public ResponseEntity<ApiResponse<List<CalendarResponseDTO>>> getGroupCalendars(
393361

394362
} catch (Exception e) {
395363
log.error("그룹 일정 조회 실패 - 그룹 ID: {}, 에러: {}", groupId, e.getMessage());
396-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
397-
.body(ApiResponse.error("그룹 일정 조회에 실패했습니다."));
364+
throw new CustomException(ErrorCode.CALENDAR_FOUND_FAILED);
398365
}
399366
}
400367
}

src/main/java/store/lastdance/domain/calendar/Calendar.java

Lines changed: 11 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22

33
import lombok.*;
44
import jakarta.persistence.*;
5-
import store.lastdance.domain.group.Group;
6-
import store.lastdance.domain.user.User;
75
import store.lastdance.domain.common.BaseTimeEntity;
86
import java.time.LocalDateTime;
9-
import java.util.UUID;
7+
import store.lastdance.domain.group.Group;
8+
import store.lastdance.domain.user.User;
109

1110
@Getter
1211
@Entity
1312
@Table(name = "calendars")
1413
@NoArgsConstructor(access = AccessLevel.PROTECTED)
14+
@AllArgsConstructor
15+
@Builder
1516
public class Calendar extends BaseTimeEntity {
1617
@Id
1718
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -41,11 +42,13 @@ public class Calendar extends BaseTimeEntity {
4142
@Enumerated(EnumType.STRING)
4243
private CalendarCategory category;
4344

44-
@Column(name = "group_id")
45-
private UUID groupId;
45+
@ManyToOne(fetch = FetchType.LAZY)
46+
@JoinColumn(name = "group_id")
47+
private Group group;
4648

47-
@Column(name = "user_id", nullable = false)
48-
private UUID userId;
49+
@ManyToOne(fetch = FetchType.LAZY)
50+
@JoinColumn(name = "user_id", nullable = false)
51+
private User user;
4952

5053
@Column(name = "repeat_type", length = 20)
5154
@Enumerated(EnumType.STRING)
@@ -54,31 +57,6 @@ public class Calendar extends BaseTimeEntity {
5457
@Column(name = "repeat_end_date")
5558
private LocalDateTime repeatEndDate;
5659

57-
@Builder
58-
public Calendar(@NonNull String title,
59-
@NonNull String description,
60-
@NonNull LocalDateTime startDate,
61-
@NonNull LocalDateTime endDate,
62-
Boolean isAllDay,
63-
@NonNull CalendarType type,
64-
@NonNull CalendarCategory category,
65-
UUID groupId,
66-
@NonNull UUID userId,
67-
RepeatType repeatType,
68-
LocalDateTime repeatEndDate) {
69-
this.title = title;
70-
this.description = description;
71-
this.startDate = startDate;
72-
this.endDate = endDate;
73-
this.isAllDay = isAllDay;
74-
this.type = type;
75-
this.category = category;
76-
this.groupId = groupId;
77-
this.userId = userId;
78-
this.repeatType = repeatType;
79-
this.repeatEndDate = repeatEndDate;
80-
}
81-
8260
public void updateTitle(String title) {
8361
this.title = title;
8462
}
@@ -96,51 +74,21 @@ public void updateAllDay(Boolean isAllDay) {
9674
this.isAllDay = isAllDay != null ? isAllDay : false;
9775
}
9876

99-
public void updateType(CalendarType type) {
100-
this.type = type;
101-
}
102-
10377
public void updateCategory(CalendarCategory category) {
10478
this.category = category;
10579
}
10680

107-
public void setAsRepeating(RepeatType repeatType, LocalDateTime repeatEndDate) {
108-
validateRepeatSettings(repeatType, repeatEndDate);
81+
public void updateAsRepeating(RepeatType repeatType, LocalDateTime repeatEndDate) {
10982
this.repeatType = repeatType;
11083
this.repeatEndDate = repeatEndDate;
11184
}
11285

11386
public void updateRepeatEndDate(LocalDateTime newRepeatEndDate) {
114-
if (this.repeatType == null || this.repeatType == RepeatType.NONE) {
115-
throw new IllegalArgumentException("반복되지 않는 일정의 반복 종료일은 설정할 수 없습니다.");
116-
}
117-
validateRepeatEndDate(newRepeatEndDate);
11887
this.repeatEndDate = newRepeatEndDate;
11988
}
12089

121-
public void updateGroupId(UUID groupId) {
122-
this.groupId = groupId;
123-
}
124-
12590
public void removeRepeat() {
12691
this.repeatType = RepeatType.NONE;
12792
this.repeatEndDate = null;
12893
}
129-
130-
private void validateRepeatSettings(RepeatType repeatType, LocalDateTime repeatEndDate) {
131-
if (repeatType == null) {
132-
throw new IllegalArgumentException("반복 타입은 필수입니다.");
133-
}
134-
135-
if (repeatType != RepeatType.NONE && repeatEndDate != null) {
136-
validateRepeatEndDate(repeatEndDate);
137-
}
138-
}
139-
140-
private void validateRepeatEndDate(LocalDateTime repeatEndDate) {
141-
if (repeatEndDate != null && repeatEndDate.isBefore(this.startDate)) {
142-
throw new IllegalArgumentException("반복 종료일은 일정 시작일보다 이후여야 합니다.");
143-
}
144-
}
145-
14694
}

src/main/java/store/lastdance/dto/calender/request/CreateCalendarRequestDTO.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package store.lastdance.dto.calender.request;
22

3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.NoArgsConstructor;
36
import store.lastdance.domain.calendar.CalendarCategory;
47
import store.lastdance.domain.calendar.CalendarType;
58
import store.lastdance.domain.calendar.RepeatType;
@@ -13,6 +16,9 @@
1316
import java.util.UUID;
1417

1518
@Getter
19+
@Builder
20+
@NoArgsConstructor
21+
@AllArgsConstructor
1622
public class CreateCalendarRequestDTO {
1723

1824
@NotBlank(message = "제목은 필수입니다.")
@@ -22,22 +28,16 @@ public class CreateCalendarRequestDTO {
2228
@Size(max = 1000, message = "설명은 1000자 이내로 입력해주세요.")
2329
private String description;
2430

25-
@NotNull(message = "시작 날짜는 필수입니다.")
2631
private LocalDateTime startDate;
2732

28-
@NotNull(message = "종료 날짜는 필수입니다.")
2933
private LocalDateTime endDate;
3034

31-
private Boolean isAllDay = false;
32-
33-
@NotNull(message = "일정 타입은 필수입니다.")
34-
private CalendarType type;
35+
@NotNull(message = "종일 여부는 필수입니다.")
36+
private Boolean isAllDay;
3537

3638
@NotNull(message = "카테고리는 필수입니다.")
3739
private CalendarCategory category;
3840

39-
private UUID groupId;
40-
4141
private RepeatType repeatType = RepeatType.NONE;
4242

4343
private LocalDateTime repeatEndDate;

src/main/java/store/lastdance/dto/calender/request/UpdateCalendarRequestDTO.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package store.lastdance.dto.calender.request;
22

3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.NoArgsConstructor;
36
import store.lastdance.domain.calendar.CalendarCategory;
4-
import store.lastdance.domain.calendar.CalendarType;
57
import store.lastdance.domain.calendar.RepeatType;
68

79
import jakarta.validation.constraints.Size;
@@ -11,6 +13,9 @@
1113
import java.util.UUID;
1214

1315
@Getter
16+
@Builder
17+
@NoArgsConstructor
18+
@AllArgsConstructor
1419
public class UpdateCalendarRequestDTO {
1520

1621
@Size(max = 200, message = "제목은 200자 이내로 입력해주세요.")

0 commit comments

Comments
 (0)