diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/member/entity/Member.java b/src/main/java/com/tantanmen/carbofootprint/domain/member/entity/Member.java index 002c96b..fb20f11 100644 --- a/src/main/java/com/tantanmen/carbofootprint/domain/member/entity/Member.java +++ b/src/main/java/com/tantanmen/carbofootprint/domain/member/entity/Member.java @@ -4,6 +4,7 @@ import com.tantanmen.carbofootprint.domain.community.entity.mapping.ChatMessage; import com.tantanmen.carbofootprint.domain.community.entity.mapping.MemberChatRoom; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -51,6 +52,9 @@ public class Member { @OneToMany(mappedBy = "sender", cascade = CascadeType.ALL, orphanRemoval = true) private List chatMessageList; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) + private List scheduleList; + // 연관 관계 편의 메서드 public void addAuthority(Authority authority) { authority.changeMember(this); @@ -66,4 +70,9 @@ public void addChatMessage(ChatMessage chatMessage) { chatMessage.changeSender(this); chatMessageList.add(chatMessage); } + + public void addSchedule(Schedule schedule){ + schedule.changeMember(this); + scheduleList.add(schedule); + } } diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/convertor/ScheduleConvertor.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/convertor/ScheduleConvertor.java new file mode 100644 index 0000000..c2ac08f --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/convertor/ScheduleConvertor.java @@ -0,0 +1,131 @@ +package com.tantanmen.carbofootprint.domain.schedule.convertor; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.FirstMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.OtherMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.SecondMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.ThirdMeal; +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleRequestDto; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleResponseDto; + +public class ScheduleConvertor { + /** + * 요청 DTO -> Schedule 객체 + * 식단 정보는 따로 연관관계 매핑 + */ + public static Schedule toSchedule(ScheduleRequestDto.AddScheduleRequestDto request){ + Schedule schedule = Schedule.builder() + .totalKcal(request.getCalorie()) + .exerciseDuration(request.getWorkoutTime()) + .stepCount(request.getStepCount()) + .firstMealList(new ArrayList<>()) + .secondMealList(new ArrayList<>()) + .thirdMealList(new ArrayList<>()) + .otherMealList(new ArrayList<>()) + .month(request.getMonth()) + .day(request.getDay()) + .build(); + + addMealList(request, schedule); + + return schedule; + } + + + + + /** + * FoodType 요청 List -> 식단 데이터로 변경 + */ + + public static void addMealList(ScheduleRequestDto.AddScheduleRequestDto request, Schedule schedule){ + toFirstMealList(request.getFirstMeal(), schedule); + toSecondMealList(request.getSecondMeal(), schedule); + toThirdMealList(request.getThirdMeal(), schedule); + toOtherMealList(request.getExtraMeal(), schedule); + } + + private static void toFirstMealList(List request, Schedule schedule){ + request.stream().forEach(foodType -> { + FirstMeal firstMeal = FirstMeal.builder() + .foodType(foodType) + .build(); + + schedule.addFirstMeal(firstMeal); + }); + } + + private static void toSecondMealList(List request, Schedule schedule){ + request.stream().forEach(foodType -> { + SecondMeal secondMeal = SecondMeal.builder() + .foodType(foodType) + .build(); + + schedule.addSecondMeal(secondMeal); + }); + } + + private static void toThirdMealList(List request, Schedule schedule){ + request.stream().forEach(foodType -> { + ThirdMeal thirdMeal = ThirdMeal.builder() + .foodType(foodType) + .build(); + + schedule.addThirdMeal(thirdMeal); + }); + } + + private static void toOtherMealList(List request, Schedule schedule){ + request.stream().forEach(foodType -> { + OtherMeal otherMeal = OtherMeal.builder() + .foodType(foodType) + .build(); + + schedule.addOtherMeal(otherMeal); + }); + } + + /** + * List => List로 변환 + */ + public static ScheduleResponseDto.FindAllScheduleResponseDto toFindAllScheduleResponseDto(List scheduleList){ + List august_schedule_list = new ArrayList<>(); + List september_schedule_list = new ArrayList<>(); + + for (Schedule schedule : scheduleList) { + ScheduleResponseDto.SchedulePreviewResponseDto result = toSchedulePreviewResponseDto( + schedule); + if (schedule.getMonth() == 8){ + august_schedule_list.add(result); + } + else september_schedule_list.add(result); + } + + return ScheduleResponseDto.FindAllScheduleResponseDto.builder() + .august_schedule_list(august_schedule_list) + .september_schedule_list(september_schedule_list) + .build(); + } + + /** + * Schedule => DTO로 변환 + */ + private static ScheduleResponseDto.SchedulePreviewResponseDto toSchedulePreviewResponseDto(Schedule schedule){ + return ScheduleResponseDto.SchedulePreviewResponseDto.builder() + .title(schedule.getTitle()) + .calorie(schedule.getTotalKcal()) + .workoutTime(schedule.getExerciseDuration()) + .stepCount(schedule.getStepCount()) + .firstMeal(schedule.getFirstMealList().stream().map(FirstMeal::getFoodType).collect(Collectors.toList())) + .secondMeal(schedule.getSecondMealList().stream().map(SecondMeal::getFoodType).collect(Collectors.toList())) + .thirdMeal(schedule.getThirdMealList().stream().map(ThirdMeal::getFoodType).collect(Collectors.toList())) + .extraMeal(schedule.getOtherMealList().stream().map(OtherMeal::getFoodType).collect(Collectors.toList())) + .day(schedule.getDay()) + .build(); + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/Schedule.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/Schedule.java new file mode 100644 index 0000000..3c3e8e9 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/Schedule.java @@ -0,0 +1,123 @@ +package com.tantanmen.carbofootprint.domain.schedule.entity; + +import java.util.List; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.schedule.convertor.ScheduleConvertor; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.FirstMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.OtherMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.SecondMeal; +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.ThirdMeal; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleRequestDto; +import com.tantanmen.carbofootprint.global.entity.BaseEntity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 탄수 발자국 일정 Entity + */ +@Entity +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "schedule") +public class Schedule extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "title") + private String title; + + @Column(name = "total_kcal") + private Long totalKcal; + + @Column(name = "exercise_duration") + private Long exerciseDuration; + + @Column(name = "step_count") + private Long stepCount; + + @Column(name = "month") + private Long month; + + @Column(name = "day") + private Long day; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, orphanRemoval = true) + private List firstMealList; + + @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, orphanRemoval = true) + private List secondMealList; + + @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, orphanRemoval = true) + private List thirdMealList; + + @OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, orphanRemoval = true) + private List otherMealList; + + + // 연관 관계 편의 메서드 + public void addFirstMeal(FirstMeal firstMeal){ + firstMeal.changeSchedule(this); + firstMealList.add(firstMeal); + } + + public void addSecondMeal(SecondMeal secondMeal){ + secondMeal.changeSchedule(this); + secondMealList.add(secondMeal); + } + + public void addThirdMeal(ThirdMeal thirdMeal){ + thirdMeal.changeSchedule(this); + thirdMealList.add(thirdMeal); + } + + public void addOtherMeal(OtherMeal otherMeal){ + otherMeal.changeSchedule(this); + otherMealList.add(otherMeal); + } + + public void changeMember(Member member){ + this.member = member; + } + + /** + * Schedule 내부 데이터 변경 + */ + public void updateData(ScheduleRequestDto.AddScheduleRequestDto request){ + this.totalKcal = request.getCalorie(); + this.title = request.getTitle(); + this.exerciseDuration = request.getWorkoutTime(); + this.stepCount = request.getStepCount(); + this.month = request.getMonth(); + this.day = request.getDay(); + + this.firstMealList.clear(); + this.secondMealList.clear(); + this.thirdMealList.clear(); + this.otherMealList.clear(); + + ScheduleConvertor.addMealList(request, this); + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/FirstMeal.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/FirstMeal.java new file mode 100644 index 0000000..367cc73 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/FirstMeal.java @@ -0,0 +1,48 @@ +package com.tantanmen.carbofootprint.domain.schedule.entity.meal; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 첫 끼 Entity + */ +@Entity +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "first_meal") +public class FirstMeal { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Enumerated(EnumType.STRING) + private FoodType foodType; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "schedule_id") + private Schedule schedule; + + // 연관 관계 편의 메서드 + public void changeSchedule(Schedule schedule){ + this.schedule = schedule; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/OtherMeal.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/OtherMeal.java new file mode 100644 index 0000000..77cc42d --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/OtherMeal.java @@ -0,0 +1,48 @@ +package com.tantanmen.carbofootprint.domain.schedule.entity.meal; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 더먹 끼 Entity + */ +@Entity +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "other_meal") +public class OtherMeal { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Enumerated(EnumType.STRING) + private FoodType foodType; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "schedule_id") + private Schedule schedule; + + // 연관 관계 편의 메서드 + public void changeSchedule(Schedule schedule){ + this.schedule = schedule; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/SecondMeal.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/SecondMeal.java new file mode 100644 index 0000000..2d27418 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/SecondMeal.java @@ -0,0 +1,48 @@ +package com.tantanmen.carbofootprint.domain.schedule.entity.meal; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 두 끼 Entity + */ +@Entity +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "second_meal") +public class SecondMeal { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Enumerated(EnumType.STRING) + private FoodType foodType; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "schedule_id") + private Schedule schedule; + + // 연관 관계 편의 메서드 + public void changeSchedule(Schedule schedule){ + this.schedule = schedule; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/ThirdMeal.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/ThirdMeal.java new file mode 100644 index 0000000..2604e2b --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/entity/meal/ThirdMeal.java @@ -0,0 +1,48 @@ +package com.tantanmen.carbofootprint.domain.schedule.entity.meal; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 세 끼 Entity + */ +@Entity +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "third_meal") +public class ThirdMeal { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Enumerated(EnumType.STRING) + private FoodType foodType; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "schedule_id") + private Schedule schedule; + + // 연관 관계 편의 메서드 + public void changeSchedule(Schedule schedule){ + this.schedule = schedule; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/enums/FoodType.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/enums/FoodType.java new file mode 100644 index 0000000..c0985da --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/enums/FoodType.java @@ -0,0 +1,8 @@ +package com.tantanmen.carbofootprint.domain.schedule.enums; + +/** + * 일정 기록 음식 종류 Enum + */ +public enum FoodType { + 중식, 일식, 한식, 양식, 샐러드, 빵, 과일, 기타 +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/exception/ScheduleNotFoundException.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/exception/ScheduleNotFoundException.java new file mode 100644 index 0000000..27fba25 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/exception/ScheduleNotFoundException.java @@ -0,0 +1,14 @@ +package com.tantanmen.carbofootprint.domain.schedule.exception; + +import com.tantanmen.carbofootprint.global.enums.statuscode.BaseCode; +import com.tantanmen.carbofootprint.global.enums.statuscode.ErrorStatus; +import com.tantanmen.carbofootprint.global.exception.GeneralException; + +/** + * 존재하지 않는 일정 예외 + */ +public class ScheduleNotFoundException extends GeneralException { + public ScheduleNotFoundException() { + super(ErrorStatus._SCHEDULE_NOT_FOUND); + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/FirstMealRepository.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/FirstMealRepository.java new file mode 100644 index 0000000..2e0c396 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/FirstMealRepository.java @@ -0,0 +1,13 @@ +package com.tantanmen.carbofootprint.domain.schedule.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.FirstMeal; + +/** + * 첫 끼 repository + */ +@Repository +public interface FirstMealRepository extends JpaRepository { +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/OtherMealRepository.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/OtherMealRepository.java new file mode 100644 index 0000000..c143d8d --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/OtherMealRepository.java @@ -0,0 +1,13 @@ +package com.tantanmen.carbofootprint.domain.schedule.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.OtherMeal; + +/** + * 더먹 끼 repository + */ +@Repository +public interface OtherMealRepository extends JpaRepository { +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ScheduleRepository.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ScheduleRepository.java new file mode 100644 index 0000000..60e9e99 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ScheduleRepository.java @@ -0,0 +1,17 @@ +package com.tantanmen.carbofootprint.domain.schedule.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; + +/** + * 일정 repository + */ + +@Repository +public interface ScheduleRepository extends JpaRepository { + List findByMemberId(Long memberId); +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/SecondMealRepository.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/SecondMealRepository.java new file mode 100644 index 0000000..657ff98 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/SecondMealRepository.java @@ -0,0 +1,13 @@ +package com.tantanmen.carbofootprint.domain.schedule.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.SecondMeal; + +/** + * 두 끼 repository + */ +@Repository +public interface SecondMealRepository extends JpaRepository { +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ThirdMealRepository.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ThirdMealRepository.java new file mode 100644 index 0000000..4c7dec3 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/repository/ThirdMealRepository.java @@ -0,0 +1,13 @@ +package com.tantanmen.carbofootprint.domain.schedule.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.tantanmen.carbofootprint.domain.schedule.entity.meal.ThirdMeal; + +/** + * 세 끼 repository + */ +@Repository +public interface ThirdMealRepository extends JpaRepository { +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandService.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandService.java new file mode 100644 index 0000000..59d62da --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandService.java @@ -0,0 +1,12 @@ +package com.tantanmen.carbofootprint.domain.schedule.service; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleRequestDto; + +public interface ScheduleCommandService { + Schedule addSchedule(ScheduleRequestDto.AddScheduleRequestDto request, Member member); + Schedule updateSchedule(ScheduleRequestDto.AddScheduleRequestDto request, Long scheduleId, Member member); + Long deleteSchedule(Long scheduleId, Member member); +} + diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandServiceImpl.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandServiceImpl.java new file mode 100644 index 0000000..ef8bf77 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleCommandServiceImpl.java @@ -0,0 +1,74 @@ +package com.tantanmen.carbofootprint.domain.schedule.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.schedule.convertor.ScheduleConvertor; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.exception.ScheduleNotFoundException; +import com.tantanmen.carbofootprint.domain.schedule.repository.ScheduleRepository; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleRequestDto; +import com.tantanmen.carbofootprint.global.enums.statuscode.ErrorStatus; +import com.tantanmen.carbofootprint.global.exception.GeneralException; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class ScheduleCommandServiceImpl implements ScheduleCommandService{ + private final ScheduleRepository scheduleRepository; + + /** + * 일정 데이터 저장 + */ + @Override + public Schedule addSchedule(ScheduleRequestDto.AddScheduleRequestDto request, Member member){ + // Schedule 객체 변환 후 저장 + Schedule schedule = ScheduleConvertor.toSchedule(request); + + member.addSchedule(schedule); + + scheduleRepository.save(schedule); + + return schedule; + } + + /** + * 일정 데이터 수정 + */ + @Override + public Schedule updateSchedule(ScheduleRequestDto.AddScheduleRequestDto request, Long scheduleId, Member member){ + // 일정 검색, 없는 경우 예외 + Schedule schedule = scheduleRepository.findById(scheduleId).orElseThrow(() -> new ScheduleNotFoundException()); + + // 사용자가 작성한 일정이 아닌 경우 예외 처리 + if(schedule.getMember().getId() != member.getId()){ + throw new GeneralException(ErrorStatus._SCHEDULE_FORBIDDEN); + } + + schedule.updateData(request); + + return scheduleRepository.save(schedule); + } + + /** + * 일정 데이터 삭제 + */ + @Override + public Long deleteSchedule(Long scheduleId, Member member){ + // 일정 검색, 없는 경우 예외 + Schedule schedule = scheduleRepository.findById(scheduleId).orElseThrow(() -> new ScheduleNotFoundException()); + + // 사용자가 작성한 일정이 아닌 경우 예외 처리 + if(schedule.getMember().getId() != member.getId()){ + throw new GeneralException(ErrorStatus._SCHEDULE_FORBIDDEN); + } + + scheduleRepository.delete(schedule); + return scheduleId; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryService.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryService.java new file mode 100644 index 0000000..4ce6f5f --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryService.java @@ -0,0 +1,10 @@ +package com.tantanmen.carbofootprint.domain.schedule.service; + +import java.util.List; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; + +public interface ScheduleQueryService { + List getAllSchedules(Member member); +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryServiceImpl.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryServiceImpl.java new file mode 100644 index 0000000..f0dbbcc --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/service/ScheduleQueryServiceImpl.java @@ -0,0 +1,29 @@ +package com.tantanmen.carbofootprint.domain.schedule.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.repository.ScheduleRepository; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ScheduleQueryServiceImpl implements ScheduleQueryService{ + private final ScheduleRepository scheduleRepository; + + /** + * 사용자가 설정한 일정 모두 조회 + */ + @Override + public List getAllSchedules(Member member){ + return scheduleRepository.findByMemberId(member.getId()); + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/controller/ScheduleRestController.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/controller/ScheduleRestController.java new file mode 100644 index 0000000..9d25330 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/controller/ScheduleRestController.java @@ -0,0 +1,194 @@ +package com.tantanmen.carbofootprint.domain.schedule.web.controller; + +import java.util.List; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.tantanmen.carbofootprint.domain.member.entity.Member; +import com.tantanmen.carbofootprint.domain.recommend.web.dto.RecommendResponseDto; +import com.tantanmen.carbofootprint.domain.schedule.convertor.ScheduleConvertor; +import com.tantanmen.carbofootprint.domain.schedule.entity.Schedule; +import com.tantanmen.carbofootprint.domain.schedule.service.ScheduleCommandService; +import com.tantanmen.carbofootprint.domain.schedule.service.ScheduleQueryService; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleRequestDto; +import com.tantanmen.carbofootprint.domain.schedule.web.dto.ScheduleResponseDto; +import com.tantanmen.carbofootprint.global.annotation.LoginMember; +import com.tantanmen.carbofootprint.global.response.ApiResponse; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 탄수 발자국 일정 관련 Rest API + */ +@Tag(name = "탄수 발자국 일정 API", description = "탄수 발자국 일정 API") +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/schedules") +public class ScheduleRestController { + private final ScheduleCommandService scheduleCommandService; + private final ScheduleQueryService scheduleQueryService; + + /** + * 일정 생성 요청 API + */ + @Operation(summary = "일정 생성 요청 API", description = "일정 생성 요청 API") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "COMMON200", + description = "요청 성공", + content = { + @Content( + schema = @Schema( + implementation = ScheduleResponseDto.AddScheduleResponseDto.class + ) + ) + } + ) + }) + @PostMapping("") + public ApiResponse addSchedule(@Valid @RequestBody ScheduleRequestDto.AddScheduleRequestDto request, @Parameter(hidden = true) @LoginMember Member member){ + Schedule schedule = scheduleCommandService.addSchedule(request, member); + ScheduleResponseDto.AddScheduleResponseDto result = ScheduleResponseDto.AddScheduleResponseDto.builder() + .schedule_id(schedule.getId()) + .build(); + return ApiResponse.onSuccess(result); + } + + /** + * 사용자 일정 전체 조회 API + */ + @Operation(summary = "일정 조회 요청 API", description = "사용자 일정 전체 조회 API") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "COMMON200", + description = "요청 성공", + content = { + @Content( + schema = @Schema( + implementation = ScheduleResponseDto.FindAllScheduleResponseDto.class + ) + ) + } + ) + }) + @GetMapping("") + public ApiResponse getAllSchedules(@Parameter(hidden = true) @LoginMember Member member){ + List scheduleList = scheduleQueryService.getAllSchedules(member); + return ApiResponse.onSuccess(ScheduleConvertor.toFindAllScheduleResponseDto(scheduleList)); + } + + /** + * 일정 변경 요청 API + */ + @Operation(summary = "일정 생성 요청 API", description = "일정 생성 요청 API") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "COMMON200", + description = "요청 성공", + content = { + @Content( + schema = @Schema( + implementation = ScheduleResponseDto.UpdateScheduleResponseDto.class + ) + ) + } + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "SCHEDULE4001", + description = "일정 데이터 고유 번호와 일치하는 일정 데이터가 없는 경우", + content = { + @Content( + schema = @Schema( + example = "존재하지 않는 일정입니다." + ) + ) + } + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "SCHEDULE4002", + description = "사용자가 작성하지 않은 일정 데이터를 변경하려는 경우", + content = { + @Content( + schema = @Schema( + example = "일정에 접근 권한이 없는 사용자입니다." + ) + ) + } + ) + }) + @PutMapping("/{scheduleId}") + public ApiResponse updateSchedule(@Valid @RequestBody + ScheduleRequestDto.AddScheduleRequestDto request, @PathVariable(name = "scheduleId") Long scheduleId, @Parameter(hidden = true) @LoginMember Member member){ + Schedule schedule = scheduleCommandService.updateSchedule(request, scheduleId, member); + ScheduleResponseDto.UpdateScheduleResponseDto result = ScheduleResponseDto.UpdateScheduleResponseDto.builder() + .update_schedule_id(schedule.getId()) + .build(); + + return ApiResponse.onSuccess(result); + } + + /** + * 일정 삭제 요청 API + */ + @Operation(summary = "일정 삭제 요청 API", description = "일정 삭제 요청 API") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "COMMON200", + description = "요청 성공", + content = { + @Content( + schema = @Schema( + implementation = ScheduleResponseDto.DeleteScheduleResponseDto.class + ) + ) + } + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "SCHEDULE4001", + description = "일정 데이터 고유 번호와 일치하는 일정 데이터가 없는 경우", + content = { + @Content( + schema = @Schema( + example = "존재하지 않는 일정입니다." + ) + ) + } + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "SCHEDULE4002", + description = "사용자가 작성하지 않은 일정 데이터를 변경하려는 경우", + content = { + @Content( + schema = @Schema( + example = "일정에 접근 권한이 없는 사용자입니다." + ) + ) + } + ) + }) + @DeleteMapping("/{scheduleId}") + public ApiResponse deleteSchedule(@PathVariable(name = "scheduleId") Long scheduleId, @Parameter(hidden = true) @LoginMember Member member){ + Long deletedScheduleId = scheduleCommandService.deleteSchedule(scheduleId, member); + ScheduleResponseDto.DeleteScheduleResponseDto result = ScheduleResponseDto.DeleteScheduleResponseDto + .builder() + .deleted_schedule_id(deletedScheduleId) + .build(); + return ApiResponse.onSuccess(result); + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleRequestDto.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleRequestDto.java new file mode 100644 index 0000000..14650ff --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleRequestDto.java @@ -0,0 +1,57 @@ +package com.tantanmen.carbofootprint.domain.schedule.web.dto; + +import java.util.List; + +import org.hibernate.validator.constraints.Length; + +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Schema(title = "SCHEDULE_REQ_01", description = "일정 요청 DTO") +public class ScheduleRequestDto { + @Setter + @Getter + @ToString + /** + * 일정 생성 요청 DTO + */ + public static class AddScheduleRequestDto{ + @Schema(description = "일정 이름", example = "무탄수운동 1일차") + @Length(max = 10, message = "일정 이름은 최대 10글자 입니다.") + @NotBlank(message = "일정 이름을 작성해주세요.") + private String title; + @Schema(description = "일정 월", example = "8") + @NotNull(message = "날짜를 입력해주세요.") + @Min(value = 8, message = "8월 이상의 데이터만 요청 가능합니다.") + @Max(value = 9, message = "최대 9월까지의 데이터만 요청 가능합니다.") + private Long month; + + @Schema(description = "일정 일", example = "30") + @NotNull(message = "날짜를 입력해주세요.") + @Min(value = 1, message = "날짜 입력이 잘못되었습니다.") + @Max(value = 31, message = "날짜 입력이 잘못되었습니다.") + private Long day; + @Schema(description = "첫 끼 목록", example = "[\"중식\", \"일식\"]") + private List firstMeal; + @Schema(description = "두 끼 목록", example = "[\"양식\", \"샐러드\"]") + private List secondMeal; + @Schema(description = "세 끼 목록", example = "[\"빵\", \"과일\", \"기타\"]") + private List thirdMeal; + @Schema(description = "더먹 끼 목록", example = "[]") + private List extraMeal; + @Schema(description = "총 섭취 칼로리", example = "2300") + private Long calorie; + @Schema(description = "운동 시간", example = "50") + private Long workoutTime; + @Schema(description = "걸음수", example = "23000") + private Long stepCount; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleResponseDto.java b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleResponseDto.java new file mode 100644 index 0000000..99a46e2 --- /dev/null +++ b/src/main/java/com/tantanmen/carbofootprint/domain/schedule/web/dto/ScheduleResponseDto.java @@ -0,0 +1,91 @@ +package com.tantanmen.carbofootprint.domain.schedule.web.dto; + +import java.util.List; + +import com.tantanmen.carbofootprint.domain.schedule.enums.FoodType; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +@Schema(title = "SCHEDULE_RES_01", description = "일정 응답 DTO") +public class ScheduleResponseDto { + + /** + * 일정 생성 응답 DTO + */ + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class AddScheduleResponseDto{ + @Schema(description = "생성된 일정 고유 번호", example = "10") + private Long schedule_id; + } + + /** + * 모든 일정 응답 DTO + */ + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class FindAllScheduleResponseDto{ + @Schema(description = "전체 일정 월별 목록") + private List august_schedule_list; + private List september_schedule_list; + } + + /** + * 모든 일정 응답 상세 DTO + */ + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class SchedulePreviewResponseDto{ + @Schema(description = "일정 이름", example = "무탄수운동 1일차") + private String title; + @Schema(description = "첫 끼 목록", example = "[\"중식\", \"일식\"]") + private List firstMeal; + @Schema(description = "두 끼 목록", example = "[\"양식\", \"샐러드\"]") + private List secondMeal; + @Schema(description = "세 끼 목록", example = "[\"빵\", \"과일\", \"기타\"]") + private List thirdMeal; + @Schema(description = "더먹 끼 목록", example = "[]") + private List extraMeal; + @Schema(description = "총 섭취 칼로리", example = "2300") + private Long calorie; + @Schema(description = "운동 시간", example = "50") + private Long workoutTime; + @Schema(description = "걸음수", example = "23000") + private Long stepCount; + @Schema(description = "날짜", example = "30") + private Long day; + } + + /** + * 일정 수정 응답 DTO + */ + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class UpdateScheduleResponseDto{ + @Schema(description = "변경한 일정 고유 번호 값 (요청한 값과 동일)", example = "15") + private Long update_schedule_id; + } + + /** + * 일정 삭제 응답 DTO + */ + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class DeleteScheduleResponseDto{ + @Schema(description = "삭제된 일정 고유 번호 값 (요청한 값과 동일)", example = "13") + private Long deleted_schedule_id; + } +} diff --git a/src/main/java/com/tantanmen/carbofootprint/global/enums/statuscode/ErrorStatus.java b/src/main/java/com/tantanmen/carbofootprint/global/enums/statuscode/ErrorStatus.java index d67a153..c753ac6 100644 --- a/src/main/java/com/tantanmen/carbofootprint/global/enums/statuscode/ErrorStatus.java +++ b/src/main/java/com/tantanmen/carbofootprint/global/enums/statuscode/ErrorStatus.java @@ -22,8 +22,11 @@ public enum ErrorStatus implements BaseCode { _CLASSIFICAION_REQUEST_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "CLASSIFICATION5001", "음식 사진 AI 요청 중 오류가 발생했습니다."), _CLASSIFICATION_FAIL(HttpStatus.BAD_REQUEST, "CLASSIFICATION4001", "음식 사진 인식에 실패했습니다."), - // chat + // schedule + _SCHEDULE_NOT_FOUND(HttpStatus.NOT_FOUND, "SCHEDULE4001", "존재하지 않는 일정입니다."), + _SCHEDULE_FORBIDDEN(HttpStatus.FORBIDDEN, "SCHEDULE4002", "일정에 접근 권한이 없는 사용자입니다."), + // chat _CHAT_ROOM_ENTRY_NOT_FOUND(HttpStatus.NOT_FOUND, "CHAT4001", "입장한 내역이 없는 채팅방입니다."), _CHAT_ROOM_NOT_EXIST(HttpStatus.NOT_FOUND, "CHAT4002", "존재하지 않는 채팅방입니다.");