diff --git a/src/main/java/Devroup/hidaddy/controller/CommunityController.java b/src/main/java/Devroup/hidaddy/controller/CommunityController.java index 2742ef5..c7eafbf 100644 --- a/src/main/java/Devroup/hidaddy/controller/CommunityController.java +++ b/src/main/java/Devroup/hidaddy/controller/CommunityController.java @@ -1,4 +1,4 @@ -package Devroup.hidaddy.controller.community; +package Devroup.hidaddy.controller; import Devroup.hidaddy.dto.community.*; import Devroup.hidaddy.entity.User; diff --git a/src/main/java/Devroup/hidaddy/controller/EmotionDiaryController.java b/src/main/java/Devroup/hidaddy/controller/EmotionDiaryController.java index f80f05f..fb985e9 100644 --- a/src/main/java/Devroup/hidaddy/controller/EmotionDiaryController.java +++ b/src/main/java/Devroup/hidaddy/controller/EmotionDiaryController.java @@ -1,10 +1,14 @@ -package Devroup.hidaddy.controller.emotionDiary; +package Devroup.hidaddy.controller; import Devroup.hidaddy.dto.emotionDiary.*; -import Devroup.hidaddy.entity.User; +import Devroup.hidaddy.entity.User; +import Devroup.hidaddy.security.UserDetailsImpl; import Devroup.hidaddy.service.EmotionDiaryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.XSlf4j; +import org.springframework.cglib.core.Local; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -17,60 +21,70 @@ @RestController @RequestMapping("/api/emotion-diaries") @RequiredArgsConstructor +@Tag(name = "Emotion-Diary", description = "감정일기 API") public class EmotionDiaryController { private final EmotionDiaryService emotionDiaryService; // 감정일기 생성 (create) + @Operation(summary = "감정일기 생성", description = "특정 날짜의 감정일기를 생성합니다.") @PostMapping public ResponseEntity createEmotionDiary( - @AuthenticationPrincipal User currentUser, + @AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody EmotionDiaryCreateRequest dto ) { + User currentUser = userDetails.getUser(); emotionDiaryService.create(dto, currentUser); return ResponseEntity.ok().build(); } // 감정일기 조회 (read) // 감정일기 목록 조회 + @Operation(summary = "감정일기 목록 조회", description = "캘린더 표시를 위해 선택한 날짜 범위의 감정일기를 날짜 오름차순으로 조회합니다.") @GetMapping - public ResponseEntity> readEmotionDiary( + public List readEmotionDiary( // 범위 지정하여 범위 내의 감정일기 조회 - @RequestParam("start") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDate start, - @RequestParam("end") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDate end, - @AuthenticationPrincipal User currentUser + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate, + @AuthenticationPrincipal UserDetailsImpl userDetails ) { - List responses = emotionDiaryService.readEmotionDiary(currentUser, start, end); - return ResponseEntity.ok(responses); + User currentUser = userDetails.getUser(); + return emotionDiaryService.readEmotionDiary(currentUser, startDate, endDate); } // 특정 날짜의 감정일기에 접근 + @Operation(summary = "개별 감정일기 조회", description = "특정 날짜의 감정일기를 조회합니다.") @GetMapping("/{date}") public ResponseEntity readEmotionDiaryByDate( // 특정 날짜로 감정일기에 접근 후 조회 @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @AuthenticationPrincipal User currentUser + @AuthenticationPrincipal UserDetailsImpl userDetails ) { + User currentUser = userDetails.getUser(); EmotionDiaryResponse response = emotionDiaryService.readEmotionDiaryByDate(currentUser, date); return ResponseEntity.ok(response); } // 감정일기 수정 (update) + @Operation(summary = "특정 감정일기 수정", description = "해당하는 날짜의 감정일기를 수정합니다.") @PutMapping("/{date}") public ResponseEntity updateEmotionDiary( - @AuthenticationPrincipal User currentUser, + @AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestBody EmotionDiaryUpdateRequest request ) { + User currentUser = userDetails.getUser(); EmotionDiaryResponse response = emotionDiaryService.updateEmotionDiary(currentUser, date, request); return ResponseEntity.ok(response); } // 감정일기 삭제 (delete) + @Operation(summary = "특정 감정일기 삭제", description = "해당하는 날짜의 감정일기를 삭제합니다.") @DeleteMapping("/{date}") public ResponseEntity deleteEmotionDiary( - @AuthenticationPrincipal User currentUser, + @AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date ) { + User currentUser = userDetails.getUser(); emotionDiaryService.deleteEmotionDiary(currentUser, date); return ResponseEntity.ok().build(); } diff --git a/src/main/java/Devroup/hidaddy/controller/WeeklyContent.java b/src/main/java/Devroup/hidaddy/controller/WeeklyContent.java new file mode 100644 index 0000000..f22700f --- /dev/null +++ b/src/main/java/Devroup/hidaddy/controller/WeeklyContent.java @@ -0,0 +1,38 @@ +package Devroup.hidaddy.controller; + +import Devroup.hidaddy.dto.weeklycontent.WeeklyContentResponse; +import Devroup.hidaddy.dto.weeklycontent.WeeklyContentSimpleResponse; +import Devroup.hidaddy.entity.User; +import Devroup.hidaddy.service.WeeklyContentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/weekly") +@RequiredArgsConstructor +@Tag(name = "WeeklyContent", description = "주차별 정보 조회 API") +public class WeeklyContent { + private final WeeklyContentService service; + private final WeeklyContentService weeklyContentService; + + @Operation(summary = "현재 주차의 정보 조회", description = "아이의 출산 예정일로 현재 주차를 계산하고 정보를 조회합니다.") + @GetMapping("/current") + public ResponseEntity getCurrentWeeklyContent( + @RequestParam Long babyId, + @AuthenticationPrincipal User user + ) { + return ResponseEntity.ok(weeklyContentService.getWeeklyContent(babyId)); + } + + @Operation(summary = "특정 주차의 정보 조회", description = "원하는 특정 주차의 정보를 조회합니다.") + @GetMapping("/{week}") + public ResponseEntity getWeeklyContent( + @PathVariable int week + ) { + return ResponseEntity.ok(weeklyContentService.getWeeklyContentSimple(week)); + } +} diff --git a/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryCreateRequest.java b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryCreateRequest.java index 1be5462..7fd4270 100644 --- a/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryCreateRequest.java +++ b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryCreateRequest.java @@ -6,7 +6,7 @@ import lombok.NoArgsConstructor; import org.antlr.v4.runtime.misc.NotNull; -import java.time.LocalDateTime; +import java.time.LocalDate; @Getter @NoArgsConstructor @@ -17,7 +17,7 @@ public class EmotionDiaryCreateRequest { private String content; @NotNull - private LocalDateTime date; + private LocalDate date; private String imageUrl; } diff --git a/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryMonthResponse.java b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryMonthResponse.java new file mode 100644 index 0000000..a4c23e9 --- /dev/null +++ b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryMonthResponse.java @@ -0,0 +1,19 @@ +package Devroup.hidaddy.dto.emotionDiary; + +import lombok.Builder; +import lombok.Getter; +import Devroup.hidaddy.entity.EmotionDiary; + +import java.time.LocalDate; + +@Getter +@Builder +public class EmotionDiaryMonthResponse { + private LocalDate date; + + public static EmotionDiaryMonthResponse from(EmotionDiary emotionDiary) { + return EmotionDiaryMonthResponse.builder() + .date(emotionDiary.getDate()) + .build(); + } +} diff --git a/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryResponse.java b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryResponse.java index 598c5ab..71ae856 100644 --- a/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryResponse.java +++ b/src/main/java/Devroup/hidaddy/dto/emotionDiary/EmotionDiaryResponse.java @@ -1,6 +1,7 @@ package Devroup.hidaddy.dto.emotionDiary; import Devroup.hidaddy.entity.EmotionDiary; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -13,6 +14,7 @@ @NoArgsConstructor @AllArgsConstructor @Builder +@JsonInclude(JsonInclude.Include.NON_NULL) public class EmotionDiaryResponse { private Long id; private String content; diff --git a/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentResponse.java b/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentResponse.java new file mode 100644 index 0000000..75f1c79 --- /dev/null +++ b/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentResponse.java @@ -0,0 +1,26 @@ +package Devroup.hidaddy.dto.weeklycontent; + +import Devroup.hidaddy.entity.User; +import Devroup.hidaddy.entity.WeeklyContent; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor +public class WeeklyContentResponse { + private int currentWeek; + private String babyContent; + private String momContent; + private String healthContent; + + public static WeeklyContentResponse from(int currentWeek, WeeklyContent weeklyContent) { + return WeeklyContentResponse.builder() + .currentWeek(currentWeek) + .babyContent(weeklyContent.getBabyContent()) + .momContent(weeklyContent.getMomContent()) + .healthContent(weeklyContent.getHealthContent()) + .build(); + } +} diff --git a/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentSimpleResponse.java b/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentSimpleResponse.java new file mode 100644 index 0000000..f9a4a7f --- /dev/null +++ b/src/main/java/Devroup/hidaddy/dto/weeklycontent/WeeklyContentSimpleResponse.java @@ -0,0 +1,25 @@ +package Devroup.hidaddy.dto.weeklycontent; + +import Devroup.hidaddy.entity.WeeklyContent; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +@AllArgsConstructor +public class WeeklyContentSimpleResponse { + private int week; + private String babyContent; + private String momContent; + private String healthContent; + + public static WeeklyContentSimpleResponse from(WeeklyContent weeklyContent) { + return WeeklyContentSimpleResponse.builder() + .week(weeklyContent.getWeek()) + .babyContent(weeklyContent.getBabyContent()) + .momContent(weeklyContent.getMomContent()) + .healthContent(weeklyContent.getHealthContent()) + .build(); + } +} diff --git a/src/main/java/Devroup/hidaddy/entity/EmotionDiary.java b/src/main/java/Devroup/hidaddy/entity/EmotionDiary.java index 9e40ee7..818871f 100644 --- a/src/main/java/Devroup/hidaddy/entity/EmotionDiary.java +++ b/src/main/java/Devroup/hidaddy/entity/EmotionDiary.java @@ -9,11 +9,16 @@ import java.time.LocalDateTime; @Entity -@Table(name = "emotion_diary") @Getter @NoArgsConstructor @AllArgsConstructor @Builder +@Table( + name = "emotion_diary", + uniqueConstraints = { + @UniqueConstraint(columnNames = {"user_id", "date"}) + } +) public class EmotionDiary { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/Devroup/hidaddy/entity/WeeklyContent.java b/src/main/java/Devroup/hidaddy/entity/WeeklyContent.java index 91bf9fe..34133b0 100644 --- a/src/main/java/Devroup/hidaddy/entity/WeeklyContent.java +++ b/src/main/java/Devroup/hidaddy/entity/WeeklyContent.java @@ -19,8 +19,12 @@ public class WeeklyContent { private Integer week; - private String title; + @Lob + private String babyContent; + + @Lob + private String momContent; @Lob - private String content; + private String healthContent; } \ No newline at end of file diff --git a/src/main/java/Devroup/hidaddy/repository/emotionDiary/EmotionDiaryRepository.java b/src/main/java/Devroup/hidaddy/repository/emotionDiary/EmotionDiaryRepository.java index 9bb9e33..a126edc 100644 --- a/src/main/java/Devroup/hidaddy/repository/emotionDiary/EmotionDiaryRepository.java +++ b/src/main/java/Devroup/hidaddy/repository/emotionDiary/EmotionDiaryRepository.java @@ -12,7 +12,7 @@ @Repository public interface EmotionDiaryRepository extends JpaRepository { - List findAllByUserIdAndDateBetween(Long id, LocalDate start, LocalDate end); + List findAllByUserIdAndDateBetweenOrderByDateAsc(Long id, LocalDate start, LocalDate end); - Optional findByUserIdAndDate(User currentUser, LocalDate date); + Optional findByUserIdAndDate(Long currentUser, LocalDate date); } \ No newline at end of file diff --git a/src/main/java/Devroup/hidaddy/repository/user/BabyRepository.java b/src/main/java/Devroup/hidaddy/repository/user/BabyRepository.java index 7472fd4..ffde494 100644 --- a/src/main/java/Devroup/hidaddy/repository/user/BabyRepository.java +++ b/src/main/java/Devroup/hidaddy/repository/user/BabyRepository.java @@ -15,4 +15,6 @@ public interface BabyRepository extends JpaRepository { void deleteAllByUser(User user); Optional findByIdAndUserId(Long babyId, Long userId); + + Optional findById(Long babyId); } diff --git a/src/main/java/Devroup/hidaddy/repository/weeklycontent/WeeklyContentRepository.java b/src/main/java/Devroup/hidaddy/repository/weeklycontent/WeeklyContentRepository.java new file mode 100644 index 0000000..2f11f6d --- /dev/null +++ b/src/main/java/Devroup/hidaddy/repository/weeklycontent/WeeklyContentRepository.java @@ -0,0 +1,11 @@ +package Devroup.hidaddy.repository.weeklycontent; + +import Devroup.hidaddy.entity.WeeklyContent; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface WeeklyContentRepository extends JpaRepository { + + Optional findByWeek(int week); +} diff --git a/src/main/java/Devroup/hidaddy/service/EmotionDiaryService.java b/src/main/java/Devroup/hidaddy/service/EmotionDiaryService.java index 694355f..6dfe968 100644 --- a/src/main/java/Devroup/hidaddy/service/EmotionDiaryService.java +++ b/src/main/java/Devroup/hidaddy/service/EmotionDiaryService.java @@ -4,6 +4,7 @@ import Devroup.hidaddy.entity.EmotionDiary; import Devroup.hidaddy.entity.User; import Devroup.hidaddy.repository.emotionDiary.*; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,17 +20,19 @@ public class EmotionDiaryService { private final EmotionDiaryRepository diaryRepository; public void create(EmotionDiaryCreateRequest dto, User currentUser) { + LocalDate dataToSave = (dto.getDate() == null) ? LocalDate.now() : dto.getDate(); EmotionDiary diary = EmotionDiary.builder() + .user(currentUser) .content(dto.getContent()) .imageUrl(dto.getImageUrl()) - .date(dto.getDate().toLocalDate()) + .date(dataToSave) .build(); diaryRepository.save(diary); } // 공통 조회 로직 실패 시 오류 발생 - private EmotionDiary findDiaryOrThrow(User currentUser, LocalDate date) { + private EmotionDiary findDiaryOrThrow(Long currentUser, LocalDate date) { return diaryRepository.findByUserIdAndDate(currentUser, date) .orElseThrow(()-> new IllegalArgumentException("해당 날짜에 작성된 감정일기가 없습니다.")); } @@ -37,24 +40,25 @@ private EmotionDiary findDiaryOrThrow(User currentUser, LocalDate date) { // 감정일기 조회(read) // 캘린더 용 목록 조회 @Transactional(readOnly = true) - public List readEmotionDiary(User currentUser, LocalDate start, LocalDate end) + public List readEmotionDiary(User currentUser, LocalDate start, LocalDate end) { - List diaries = diaryRepository.findAllByUserIdAndDateBetween( + List diaries = diaryRepository.findAllByUserIdAndDateBetweenOrderByDateAsc( currentUser.getId(), start, end ); return diaries.stream() - .map(EmotionDiaryResponse::from) + .map(EmotionDiaryMonthResponse::from) .toList(); } // 개별 감정일기에 접근 @Transactional(readOnly = true) public EmotionDiaryResponse readEmotionDiaryByDate(User currentUser, LocalDate date) { - EmotionDiary diary = findDiaryOrThrow(currentUser, date); - return EmotionDiaryResponse.from(diary); + return diaryRepository.findByUserIdAndDate(currentUser.getId(), date) + .map(EmotionDiaryResponse::from) + .orElseGet(EmotionDiaryResponse::new); } // 감정일기 수정 (update) @@ -64,7 +68,7 @@ public EmotionDiaryResponse updateEmotionDiary( LocalDate date, EmotionDiaryUpdateRequest dto ) { - EmotionDiary diary = findDiaryOrThrow(currentUser, date); + EmotionDiary diary = findDiaryOrThrow(currentUser.getId(), date); diary.update(dto.getContent(), dto.getImageUrl()); return EmotionDiaryResponse.from(diary); @@ -72,7 +76,7 @@ public EmotionDiaryResponse updateEmotionDiary( // 감정일기 삭제 (delete) public void deleteEmotionDiary(User currentUser, LocalDate date) { - EmotionDiary diary = findDiaryOrThrow(currentUser, date); + EmotionDiary diary = findDiaryOrThrow(currentUser.getId(), date); diaryRepository.delete(diary); } diff --git a/src/main/java/Devroup/hidaddy/service/WeeklyContentService.java b/src/main/java/Devroup/hidaddy/service/WeeklyContentService.java new file mode 100644 index 0000000..37b1056 --- /dev/null +++ b/src/main/java/Devroup/hidaddy/service/WeeklyContentService.java @@ -0,0 +1,50 @@ +package Devroup.hidaddy.service; + +import Devroup.hidaddy.dto.weeklycontent.WeeklyContentResponse; +import Devroup.hidaddy.dto.weeklycontent.WeeklyContentSimpleResponse; +import Devroup.hidaddy.entity.Baby; +import Devroup.hidaddy.entity.WeeklyContent; +import Devroup.hidaddy.repository.user.BabyRepository; +import Devroup.hidaddy.repository.weeklycontent.WeeklyContentRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class WeeklyContentService { + private final BabyRepository babyRepository; + private final WeeklyContentRepository weeklyContentRepository; + + // 출산 예정일로부터 현재 날짜 계산하여 해당 주차 컨텐츠 출력 + public WeeklyContentResponse getWeeklyContent(Long babyId) { + Baby baby = babyRepository.findById(babyId) + .orElseThrow(() -> new IllegalArgumentException("아이를 찾을 수 없습니다.")); + + int currentweek = caculateCurrentWeek(baby.getDueDate().toLocalDate()); + + WeeklyContent weeklyContent = weeklyContentRepository.findByWeek(currentweek) + .orElseThrow(() -> new IllegalArgumentException(currentweek + "주차 데이터가 없습니다.")); + + return WeeklyContentResponse.from(currentweek, weeklyContent); + } + + // 화살표로 특정 주차 넘어갈 경우 특정 주차의 컨텐츠 출력 + public WeeklyContentSimpleResponse getWeeklyContentSimple(int week) { + WeeklyContent weeklyContent = weeklyContentRepository.findByWeek(week) + .orElseThrow(() -> new IllegalArgumentException(week + "주차 데이터가 없습니다.")); + + return WeeklyContentSimpleResponse.from(weeklyContent); + } + + // 현재 날짜를 기준으로 출산 예정일로부터 주차 계산 + private int caculateCurrentWeek(LocalDate dueDate) { + long daysLeft = ChronoUnit.DAYS.between(LocalDate.now(), dueDate); + long weeksLeft = daysLeft / 7; + return (int) (40 - weeksLeft); + } +}