Skip to content

Commit c8bd77a

Browse files
authored
[FU-346] 날짜별 스케줄 API 개발 (#90)
* FU-346 feat: 날짜별 스케줄 entity 구현 * FU-346 feat: 날짜별 스케줄 CRUD 기능 개발 * FU-346 feat: 중복되는 날짜별 스케줄 검증 쿼리 보완 - 기존: 시간대만 비교 - 수정: 날짜가 동일한 경우 start time, end time 비교 * FU-346 feat: 날짜별 스케줄 조회 요청에 대한 응답 형식 보완 scheduleId를 추가로 반환 * FU-346 feat: 날짜별 스케줄 중복 및 현시점 이후의 데이터 검증 로직 보완 - 날짜별 스케줄 수정 시, 기존 로직에서는 동일한 스케줄과 시간대가 중복되는 경우를 처리하지 못하였음. 이를 보완하는 오버로딩 함수 정의하였음 - 날짜별 스케줄 조회 시 현시점 이후의 데이터만 조회해옴. 등록 및 수정 시에도 현시점 이후의 데이터만 등록할 수 있도록 검증함 * FU-346 feat: 테스트 작성 시 현재시간 모킹을 위한 clock 객체 Bean 등록 테스트 코드 작성 시 LocalDateTime.now()를 모킹하기 위해 Clock을 빈으로 등록하였음 * FU-346 feat: 날짜별 스케줄의 비즈니스 로직 검증 용 테스트코드 작성 * FU-346 feat: 날짜별스케줄 조회 가능 범위 변경 기존: 현시점 이후의 스케줄만 조회 가능 변경: 과거 데이터를 포함한 월별 스케줄 조회 가능 * FU-346 feat: 날짜별 스케줄 월별 조회 시 year 정보도 포함 * FU-346 feat: 날짜별 스케줄 등록/수정 시 시간대 검증 추가 시작시간이 종료시간과 같거나, 종료시간이 시작시간보다 더 앞인 경우 예외 발생 * FU-346 chore: qodana_code_quality.yml 파일 제거
1 parent 5a426e5 commit c8bd77a

13 files changed

Lines changed: 637 additions & 52 deletions

File tree

.github/workflows/qodana_code_quality.yml

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.foru.freebe.config;
2+
3+
import java.time.Clock;
4+
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
@Configuration
9+
public class ClockConfig {
10+
@Bean
11+
public Clock clock() {
12+
return Clock.systemDefaultZone();
13+
}
14+
}

src/main/java/com/foru/freebe/errors/errorcode/ScheduleErrorCode.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
@Getter
77
@RequiredArgsConstructor
88
public enum ScheduleErrorCode implements ErrorCode {
9-
9+
DAILY_SCHEDULE_NOT_FOUND(500, "해당하는 날짜별 스케줄을 찾을 수 없습니다."),
10+
DAILY_SCHEDULE_OVERLAP(400, "해당 일정에 이미 등록된 스케줄이 있습니다."),
11+
DAILY_SCHEDULE_IN_PAST(400, "현재 시점 이전의 스케줄은 등록할 수 없습니다."),
1012
START_TIME_AFTER_END_TIME(400, "시작시간과 종료시간이 올바르지 않습니다.");
1113

12-
1314
private final int httpStatus;
1415
private final String message;
15-
}
16+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.foru.freebe.schedule.controller;
2+
3+
import java.util.List;
4+
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
8+
import org.springframework.web.bind.annotation.DeleteMapping;
9+
import org.springframework.web.bind.annotation.GetMapping;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.PutMapping;
13+
import org.springframework.web.bind.annotation.RequestBody;
14+
import org.springframework.web.bind.annotation.RequestMapping;
15+
import org.springframework.web.bind.annotation.RestController;
16+
17+
import com.foru.freebe.auth.model.MemberAdapter;
18+
import com.foru.freebe.common.dto.ResponseBody;
19+
import com.foru.freebe.member.entity.Member;
20+
import com.foru.freebe.schedule.dto.DailyScheduleAddResponse;
21+
import com.foru.freebe.schedule.dto.DailyScheduleMonthlyRequest;
22+
import com.foru.freebe.schedule.dto.DailyScheduleRequest;
23+
import com.foru.freebe.schedule.dto.DailyScheduleResponse;
24+
import com.foru.freebe.schedule.service.DailyScheduleService;
25+
26+
import jakarta.validation.Valid;
27+
import jakarta.validation.constraints.Positive;
28+
import lombok.RequiredArgsConstructor;
29+
30+
@RestController
31+
@RequiredArgsConstructor
32+
@RequestMapping("/photographer")
33+
public class DailyScheduleController {
34+
private final DailyScheduleService dailyScheduleService;
35+
36+
@GetMapping("/schedule/daily")
37+
public ResponseEntity<ResponseBody<List<DailyScheduleResponse>>> getDailySchedules(
38+
@AuthenticationPrincipal MemberAdapter memberAdapter, @Valid @RequestBody DailyScheduleMonthlyRequest request) {
39+
40+
Member photographer = memberAdapter.getMember();
41+
List<DailyScheduleResponse> responses = dailyScheduleService.getDailySchedules(photographer, request);
42+
43+
ResponseBody<List<DailyScheduleResponse>> responseBody = ResponseBody.<List<DailyScheduleResponse>>builder()
44+
.message("Successfully get daily schedules")
45+
.data(responses)
46+
.build();
47+
48+
return ResponseEntity.status(HttpStatus.OK.value())
49+
.body(responseBody);
50+
}
51+
52+
@PostMapping("/schedule/daily")
53+
public ResponseEntity<ResponseBody<DailyScheduleAddResponse>> addDailySchedule(
54+
@AuthenticationPrincipal MemberAdapter memberAdapter, @Valid @RequestBody DailyScheduleRequest request) {
55+
56+
Member photographer = memberAdapter.getMember();
57+
DailyScheduleAddResponse response = dailyScheduleService.addDailySchedule(photographer, request);
58+
59+
ResponseBody<DailyScheduleAddResponse> responseBody = ResponseBody.<DailyScheduleAddResponse>builder()
60+
.message("Successfully add daily schedule")
61+
.data(response)
62+
.build();
63+
64+
return ResponseEntity.status(HttpStatus.OK.value())
65+
.body(responseBody);
66+
}
67+
68+
@PutMapping("/schedule/daily/{scheduleId}")
69+
public ResponseEntity<ResponseBody<Void>> updateDailySchedule(@AuthenticationPrincipal MemberAdapter memberAdapter,
70+
@Positive @PathVariable("scheduleId") Long scheduleId, @Valid @RequestBody DailyScheduleRequest request) {
71+
72+
Member photographer = memberAdapter.getMember();
73+
dailyScheduleService.updateDailySchedule(photographer, scheduleId, request);
74+
75+
ResponseBody<Void> responseBody = ResponseBody.<Void>builder()
76+
.message("Successfully update daily schedule")
77+
.data(null)
78+
.build();
79+
80+
return ResponseEntity.status(HttpStatus.OK.value())
81+
.body(responseBody);
82+
}
83+
84+
@DeleteMapping("/schedule/daily/{scheduleId}")
85+
public ResponseEntity<ResponseBody<Void>> deleteDailySchedule(
86+
@AuthenticationPrincipal MemberAdapter memberAdapter, @Positive @PathVariable("scheduleId") Long scheduleId) {
87+
88+
Member photographer = memberAdapter.getMember();
89+
dailyScheduleService.deleteDailySchedule(photographer, scheduleId);
90+
91+
ResponseBody<Void> responseBody = ResponseBody.<Void>builder()
92+
.message("Successfully delete daily schedule")
93+
.data(null)
94+
.build();
95+
96+
return ResponseEntity.status(HttpStatus.OK.value())
97+
.body(responseBody);
98+
}
99+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.foru.freebe.schedule.dto;
2+
3+
import jakarta.validation.constraints.NotNull;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@AllArgsConstructor
9+
public class DailyScheduleAddResponse {
10+
@NotNull
11+
private Long scheduleID;
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.foru.freebe.schedule.dto;
2+
3+
import jakarta.validation.constraints.NotNull;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@AllArgsConstructor
9+
public class DailyScheduleMonthlyRequest {
10+
@NotNull(message = "Year must not be null")
11+
private int year;
12+
13+
@NotNull(message = "Month value must not be null")
14+
private int monthValue;
15+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.foru.freebe.schedule.dto;
2+
3+
import java.time.LocalDate;
4+
import java.time.LocalTime;
5+
6+
import com.foru.freebe.schedule.entity.ScheduleStatus;
7+
8+
import jakarta.validation.constraints.NotNull;
9+
import lombok.Builder;
10+
import lombok.Getter;
11+
import lombok.NoArgsConstructor;
12+
13+
@Getter
14+
@NoArgsConstructor
15+
public class DailyScheduleRequest {
16+
@NotNull(message = "ScheduleStatus must not be null")
17+
private ScheduleStatus scheduleStatus;
18+
19+
@NotNull(message = "Date must not be null")
20+
private LocalDate date;
21+
22+
@NotNull(message = "Start time must not be null")
23+
private LocalTime startTime;
24+
25+
@NotNull(message = "End time must not be null")
26+
private LocalTime endTime;
27+
28+
@Builder
29+
public DailyScheduleRequest(ScheduleStatus scheduleStatus, LocalDate date, LocalTime startTime, LocalTime endTime) {
30+
this.scheduleStatus = scheduleStatus;
31+
this.date = date;
32+
this.startTime = startTime;
33+
this.endTime = endTime;
34+
}
35+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.foru.freebe.schedule.dto;
2+
3+
import java.time.LocalDate;
4+
import java.time.LocalTime;
5+
6+
import com.foru.freebe.schedule.entity.ScheduleStatus;
7+
8+
import jakarta.validation.constraints.NotNull;
9+
import lombok.Builder;
10+
import lombok.Getter;
11+
import lombok.NoArgsConstructor;
12+
13+
@Getter
14+
@NoArgsConstructor
15+
public class DailyScheduleResponse {
16+
@NotNull(message = "Daily schedule id must not be null")
17+
private Long scheduleId;
18+
19+
@NotNull(message = "ScheduleStatus must not be null")
20+
private ScheduleStatus scheduleStatus;
21+
22+
@NotNull(message = "Date must not be null")
23+
private LocalDate date;
24+
25+
@NotNull(message = "Start time must not be null")
26+
private LocalTime startTime;
27+
28+
@NotNull(message = "End time must not be null")
29+
private LocalTime endTime;
30+
31+
@Builder
32+
public DailyScheduleResponse(Long scheduleId, ScheduleStatus scheduleStatus, LocalDate date, LocalTime startTime,
33+
LocalTime endTime) {
34+
this.scheduleId = scheduleId;
35+
this.scheduleStatus = scheduleStatus;
36+
this.date = date;
37+
this.startTime = startTime;
38+
this.endTime = endTime;
39+
}
40+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.foru.freebe.schedule.entity;
2+
3+
import java.time.LocalDate;
4+
import java.time.LocalTime;
5+
6+
import com.foru.freebe.common.entity.BaseEntity;
7+
import com.foru.freebe.member.entity.Member;
8+
9+
import jakarta.persistence.Column;
10+
import jakarta.persistence.Entity;
11+
import jakarta.persistence.EnumType;
12+
import jakarta.persistence.Enumerated;
13+
import jakarta.persistence.FetchType;
14+
import jakarta.persistence.GeneratedValue;
15+
import jakarta.persistence.GenerationType;
16+
import jakarta.persistence.Id;
17+
import jakarta.persistence.JoinColumn;
18+
import jakarta.persistence.ManyToOne;
19+
import jakarta.validation.constraints.NotNull;
20+
import lombok.AccessLevel;
21+
import lombok.Builder;
22+
import lombok.Getter;
23+
import lombok.NoArgsConstructor;
24+
25+
@Entity
26+
@Getter
27+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
28+
public class DailySchedule extends BaseEntity {
29+
@Id
30+
@GeneratedValue(strategy = GenerationType.IDENTITY)
31+
@Column(name = "daily_schedule_id")
32+
private Long id;
33+
34+
@ManyToOne(fetch = FetchType.LAZY)
35+
@JoinColumn(name = "member_id")
36+
private Member member;
37+
38+
@Enumerated(EnumType.STRING)
39+
@NotNull(message = "ScheduleStatus must not be null")
40+
private ScheduleStatus scheduleStatus;
41+
42+
@NotNull(message = "Date must not be null")
43+
private LocalDate date;
44+
45+
@NotNull(message = "Start time must not be null")
46+
private LocalTime startTime;
47+
48+
@NotNull(message = "End time must not be null")
49+
private LocalTime endTime;
50+
51+
@Builder
52+
public DailySchedule(Member member, ScheduleStatus scheduleStatus, LocalDate date, LocalTime startTime,
53+
LocalTime endTime) {
54+
this.member = member;
55+
this.scheduleStatus = scheduleStatus;
56+
this.date = date;
57+
this.startTime = startTime;
58+
this.endTime = endTime;
59+
}
60+
61+
public void updateScheduleStatus(ScheduleStatus newScheduleStatus) {
62+
this.scheduleStatus = newScheduleStatus;
63+
}
64+
65+
public void updateDate(LocalDate date) {
66+
this.date = date;
67+
}
68+
69+
public void updateStartTime(LocalTime startTime) {
70+
this.startTime = startTime;
71+
}
72+
73+
public void updateEndTime(LocalTime endTime) {
74+
this.endTime = endTime;
75+
}
76+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.foru.freebe.schedule.entity;
2+
3+
public enum ScheduleStatus {
4+
OPEN,
5+
CLOSED,
6+
CONFIRMED
7+
}

0 commit comments

Comments
 (0)