diff --git a/backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java b/backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java index bfd0626..5df2874 100644 --- a/backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java +++ b/backend/ongi/src/main/java/ongi/health/controller/HealthRecordController.java @@ -5,44 +5,71 @@ import ongi.health.entity.ExerciseRecord; import ongi.health.service.HealthRecordService; import ongi.security.CustomUserDetails; -import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -import java.time.LocalDate; import java.util.List; import java.util.UUID; import ongi.health.dto.PainRecordResponse; import ongi.health.dto.ExerciseRecordResponse; +import ongi.family.service.FamilyService; +import ongi.family.dto.FamilyInfo; +import ongi.temperature.service.TemperatureService; +import ongi.health.dto.PainRecordRequest; +import ongi.health.dto.ExerciseRecordRequest; @RestController @RequestMapping("/health") @RequiredArgsConstructor public class HealthRecordController { private final HealthRecordService healthRecordService; + private final FamilyService familyService; + private final TemperatureService temperatureService; // 통증 기록 추가 - @PostMapping("/pain") + @PostMapping("/pain/record") public ResponseEntity addPainRecord( @AuthenticationPrincipal CustomUserDetails userDetails, - @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @RequestParam PainRecord.PainArea area, - @RequestParam PainRecord.PainLevel level + @RequestBody PainRecordRequest request ) { - PainRecord record = healthRecordService.addPainRecord(userDetails.getUser().getUuid(), date, area, level); + + FamilyInfo familyInfo = familyService.getFamily(userDetails.getUser()); + String familyId = familyInfo.code(); + + PainRecord record = healthRecordService.addPainRecord( + userDetails.getUser().getUuid(), + request.date(), + PainRecord.PainArea.valueOf(request.painArea()), + PainRecord.PainLevel.valueOf(request.painLevel()) + ); + + // 온도 상승 + temperatureService.increaseTemperatureForParentPainInput(userDetails.getUser().getUuid(), familyId); + PainRecordResponse response = new PainRecordResponse(record); return ResponseEntity.ok(response); } // 운동 기록 추가 - @PostMapping("/exercise") + @PostMapping("/exercise/record") public ResponseEntity addExerciseRecord( @AuthenticationPrincipal CustomUserDetails userDetails, - @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, - @RequestParam int duration + @RequestBody ExerciseRecordRequest request ) { - ExerciseRecord record = healthRecordService.addExerciseRecord(userDetails.getUser().getUuid(), date, duration); + + FamilyInfo familyInfo = familyService.getFamily(userDetails.getUser()); + String familyId = familyInfo.code(); + + ExerciseRecord record = healthRecordService.addExerciseRecord( + userDetails.getUser().getUuid(), + request.date(), + request.duration() + ); + + // 온도 상승 + temperatureService.increaseTemperatureForParentExerciseInput(userDetails.getUser().getUuid(), familyId); + ExerciseRecordResponse response = new ExerciseRecordResponse(record); return ResponseEntity.ok(response); } @@ -50,9 +77,17 @@ public ResponseEntity addExerciseRecord( // 최근 7일간 통증 기록 조회 @GetMapping("/pain/view") public ResponseEntity> getParentPainRecordsForLast7Days( - @RequestParam UUID parentId + @RequestParam UUID parentId, + @AuthenticationPrincipal CustomUserDetails userDetails ) { - List response = healthRecordService.getPainRecordsForLast7Days(parentId).stream() + + FamilyInfo familyInfo = familyService.getFamily(userDetails.getUser()); + String familyId = familyInfo.code(); + + // 온도 상승 + temperatureService.increaseTemperatureForChildPainView(userDetails.getUser().getUuid(), familyId); + + List response = healthRecordService.getParentPainRecordsForLast7Days(parentId).stream() .map(PainRecordResponse::new) .toList(); return ResponseEntity.ok(response); @@ -61,9 +96,17 @@ public ResponseEntity> getParentPainRecordsForLast7Days // 최근 7일간 운동 기록 조회 @GetMapping("/exercise/view") public ResponseEntity> getParentExerciseRecordsForLast7Days( - @RequestParam UUID parentId + @RequestParam UUID parentId, + @AuthenticationPrincipal CustomUserDetails userDetails ) { - List response = healthRecordService.getExerciseRecordsForLast7Days(parentId).stream() + + FamilyInfo familyInfo = familyService.getFamily(userDetails.getUser()); + String familyId = familyInfo.code(); + + // 온도 상승 + temperatureService.increaseTemperatureForChildExerciseView(userDetails.getUser().getUuid(), familyId); + + List response = healthRecordService.getParentExerciseRecordsForLast7Days(parentId).stream() .map(ExerciseRecordResponse::new) .toList(); return ResponseEntity.ok(response); diff --git a/backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordRequest.java b/backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordRequest.java new file mode 100644 index 0000000..be34559 --- /dev/null +++ b/backend/ongi/src/main/java/ongi/health/dto/ExerciseRecordRequest.java @@ -0,0 +1,8 @@ +package ongi.health.dto; + +import java.time.LocalDate; + +public record ExerciseRecordRequest( + LocalDate date, + int duration +) {} \ No newline at end of file diff --git a/backend/ongi/src/main/java/ongi/health/dto/PainRecordRequest.java b/backend/ongi/src/main/java/ongi/health/dto/PainRecordRequest.java new file mode 100644 index 0000000..de167ab --- /dev/null +++ b/backend/ongi/src/main/java/ongi/health/dto/PainRecordRequest.java @@ -0,0 +1,9 @@ +package ongi.health.dto; + +import java.time.LocalDate; + +public record PainRecordRequest( + LocalDate date, + String painArea, + String painLevel +) {} \ No newline at end of file diff --git a/backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java b/backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java index b304c95..dd51c73 100644 --- a/backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java +++ b/backend/ongi/src/main/java/ongi/health/service/HealthRecordService.java @@ -30,13 +30,6 @@ public PainRecord addPainRecord(UUID parentId, LocalDate date, PainRecord.PainAr return painRecordRepository.save(record); } - // 최근 7일간 통증 기록 조회 - public List getPainRecordsForLast7Days(UUID parentId) { - LocalDate endDate = LocalDate.now(); - LocalDate startDate = endDate.minusDays(6); // 오늘 포함 7일 - return painRecordRepository.findByParentIdAndDateBetweenOrderByDateDesc(parentId, startDate, endDate); - } - // 운동 기록 추가 @Transactional public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int duration) { @@ -48,8 +41,15 @@ public ExerciseRecord addExerciseRecord(UUID parentId, LocalDate date, int durat return exerciseRecordRepository.save(record); } + // 최근 7일간 통증 기록 조회 + public List getParentPainRecordsForLast7Days(UUID parentId) { + LocalDate endDate = LocalDate.now(); + LocalDate startDate = endDate.minusDays(6); // 오늘 포함 7일 + return painRecordRepository.findByParentIdAndDateBetweenOrderByDateDesc(parentId, startDate, endDate); + } + // 최근 7일간 운동 기록 조회 - public List getExerciseRecordsForLast7Days(UUID parentId) { + public List getParentExerciseRecordsForLast7Days(UUID parentId) { LocalDate endDate = LocalDate.now(); LocalDate startDate = endDate.minusDays(6); // 오늘 포함 7일 return exerciseRecordRepository.findByParentIdAndDateBetweenOrderByDateDesc(parentId, startDate, endDate); diff --git a/backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java b/backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java index f0b6368..aca30ee 100644 --- a/backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java +++ b/backend/ongi/src/main/java/ongi/temperature/dto/FamilyTemperatureContributionResponse.java @@ -15,7 +15,7 @@ public class FamilyTemperatureContributionResponse { @AllArgsConstructor public static class Contribution { private LocalDate date; - private UUID userId; + private String userName; private Double contributed; } } \ No newline at end of file diff --git a/backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java b/backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java index 03b8c5a..60ae697 100644 --- a/backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java +++ b/backend/ongi/src/main/java/ongi/temperature/entity/Temperature.java @@ -36,6 +36,9 @@ @Column(nullable = false) private Double temperature; + @Column(nullable = false, length = 30) + private String reason; + @CreatedDate @Column(name = "created_at", nullable = false, updatable = false) private LocalDateTime createdAt; diff --git a/backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java b/backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java index 52db80e..c96f2e2 100644 --- a/backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java +++ b/backend/ongi/src/main/java/ongi/temperature/repository/TemperatureRepository.java @@ -16,15 +16,19 @@ public interface TemperatureRepository extends JpaRepository @Query("SELECT SUM(t.temperature) FROM Temperature t WHERE t.familyId = :familyId") Double getTotalTemperatureByFamilyId(@Param("familyId") String familyId); - // 최근 5일간 가족 온도 총합 (날짜별) - Object[]로 반환 + // 최근 5일간 가족 온도 총합 (날짜별) @Query("SELECT CAST(t.createdAt AS date), SUM(t.temperature) " + "FROM Temperature t WHERE t.familyId = :familyId AND t.createdAt >= :fromDate " + "GROUP BY CAST(t.createdAt AS date) ORDER BY CAST(t.createdAt AS date) DESC") List getFamilyTemperatureDailyRaw(@Param("familyId") String familyId, @Param("fromDate") java.time.LocalDateTime fromDate); - // 최근 5일간 가족 구성원별 온도 기여 내역 - Object[]로 반환 + // 최근 5일간 가족 구성원별 온도 기여 내역 @Query("SELECT CAST(t.createdAt AS date), t.userId, SUM(t.temperature) " + "FROM Temperature t WHERE t.familyId = :familyId AND t.createdAt >= :fromDate " + "GROUP BY CAST(t.createdAt AS date), t.userId ORDER BY CAST(t.createdAt AS date) DESC") List getFamilyTemperatureContributionsRaw(@Param("familyId") String familyId, @Param("fromDate") java.time.LocalDateTime fromDate); + + // 오늘 해당 유저가 특정 활동(reason)으로 온도 기록을 남겼는지 확인 (날짜 기준) + @Query("SELECT COUNT(t) > 0 FROM Temperature t WHERE t.userId = :userId AND t.familyId = :familyId AND t.reason = :reason AND FUNCTION('DATE', t.createdAt) = :date") + boolean existsByUserIdAndFamilyIdAndReasonAndDate(@Param("userId") java.util.UUID userId, @Param("familyId") String familyId, @Param("reason") String reason, @Param("date") java.time.LocalDate date); } \ No newline at end of file diff --git a/backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java b/backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java index 9dec710..b5dba39 100644 --- a/backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java +++ b/backend/ongi/src/main/java/ongi/temperature/service/TemperatureService.java @@ -12,22 +12,24 @@ import ongi.user.repository.UserRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.scheduling.annotation.Scheduled; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @Service @RequiredArgsConstructor -@Transactional(readOnly = true) +@Transactional public class TemperatureService { private final TemperatureRepository temperatureRepository; private final FamilyRepository familyRepository; private final UserRepository userRepository; private static final double BASE_TEMPERATURE = 36.5; - // 가족 온도 그래프 및 기여도 조회 + //// 가족 온도 그래프 및 기여도 조회 public FamilyTemperatureResponse getFamilyTemperatureSummary(String familyId) { familyRepository.findById(familyId) @@ -80,7 +82,7 @@ public FamilyTemperatureResponse getFamilyTemperatureSummary(String familyId) { .build(); } - // 최근 5일간 가족 온도 총합 조회 + //// 최근 5일간 가족 온도 총합 조회 public FamilyTemperatureDailyResponse getFamilyTemperatureDaily(String familyId) { familyRepository.findById(familyId) .orElseThrow(() -> new EntityNotFoundException("가족을 찾을 수 없습니다.")); @@ -95,18 +97,32 @@ public FamilyTemperatureDailyResponse getFamilyTemperatureDaily(String familyId) return new FamilyTemperatureDailyResponse(dailyList); } - // 최근 5일간 가족 구성원별 온도 기여 내역 조회 + //// 최근 5일간 가족 구성원별 온도 기여 내역 조회 public FamilyTemperatureContributionResponse getFamilyTemperatureContributions(String familyId) { familyRepository.findById(familyId) .orElseThrow(() -> new EntityNotFoundException("가족을 찾을 수 없습니다.")); java.time.LocalDateTime fromDate = java.time.LocalDate.now().minusDays(4).atStartOfDay(); // 최근 5일 List rawList = temperatureRepository.getFamilyTemperatureContributionsRaw(familyId, fromDate); + + Set userIds = rawList.stream() + .map(arr -> (UUID) arr[1]) + .collect(Collectors.toSet()); + Map userMap = userRepository.findAllById(userIds).stream() + .collect(Collectors.toMap(User::getUuid, user -> user)); + List contributions = rawList.stream() - .map(arr -> new FamilyTemperatureContributionResponse.Contribution( - (java.time.LocalDate) arr[0], - (java.util.UUID) arr[1], - (Double) arr[2] - )) + .map(arr -> { + LocalDate date = (LocalDate) arr[0]; + UUID userId = (UUID) arr[1]; + Double contributed = (Double) arr[2]; + String userName; + if (userId == null) { + userName = "우리 가족"; + } else { + userName = userMap.get(userId) != null ? userMap.get(userId).getName() : ""; + } + return new FamilyTemperatureContributionResponse.Contribution(date, userName, contributed); + }) .toList(); return new FamilyTemperatureContributionResponse(contributions); } @@ -114,46 +130,226 @@ public FamilyTemperatureContributionResponse getFamilyTemperatureContributions(S - // 온도 상승 메서드 + //// 온도 상승 메서드 + + // 활동별 reason 상수 정의 + private static final String REASON_EMOTION_UPLOAD = "EMOTION_UPLOAD"; + private static final String REASON_ALL_EMOTION_UPLOAD = "ALL_EMOTION_UPLOAD"; + private static final String REASON_STEP_GOAL = "STEP_GOAL"; + private static final String REASON_PARENT_PAIN_INPUT = "PARENT_PAIN_INPUT"; + private static final String REASON_PARENT_MED_INPUT = "PARENT_MED_INPUT"; + private static final String REASON_PARENT_EXERCISE_INPUT = "PARENT_EXERCISE_INPUT"; + private static final String REASON_CHILD_PAIN_VIEW = "CHILD_PAIN_VIEW"; + private static final String REASON_CHILD_MED_VIEW = "CHILD_MED_VIEW"; + private static final String REASON_CHILD_EXERCISE_VIEW = "CHILD_EXERCISE_VIEW"; + + private java.time.LocalDate getToday() { + return java.time.LocalDate.now(); + } + // 감정기록 업로드 시 온도 상승 (하루 1회만 적용) public void increaseTemperatureForEmotionUpload(UUID userId, String familyId) { - // TODO: 하루 1회 제한 및 온도 상승(+0.1도) 로직 구현 + java.time.LocalDate today = getToday(); + boolean alreadyIncreased = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_EMOTION_UPLOAD, today); + if (!alreadyIncreased) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_EMOTION_UPLOAD) + .build(); + temperatureRepository.save(temp); + } } - // 가족 모두 감정기록 업로드 시 온도 추가 상승 - public void increaseTemperatureForAllEmotionUpload(String familyId) { - // TODO: 가족 모두 업로드 확인 및 온도 추가 상승(+0.5도) 로직 구현 + // 부모 통증 부위 입력 오늘 1회만 온도 상승 + public void increaseTemperatureForParentPainInput(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_PARENT_PAIN_INPUT, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_PARENT_PAIN_INPUT) + .build(); + temperatureRepository.save(temp); + } } - - // 부모 건강 정보 입력 시 온도 상승 (최대 0.6도) - public void increaseTemperatureForParentHealthInput(UUID userId, String familyId) { - // TODO: 하루 최대 0.6도까지 온도 상승(+0.2도씩) 로직 구현 + // 부모 약 복용 입력 오늘 1회만 온도 상승 + public void increaseTemperatureForParentMedInput(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_PARENT_MED_INPUT, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_PARENT_MED_INPUT) + .build(); + temperatureRepository.save(temp); + } } - - // 자녀가 부모 건강 정보 열람 시 온도 상승 (최대 0.9도) - public void increaseTemperatureForChildHealthView(UUID userId, String familyId) { - // TODO: 하루 최대 0.9도까지 온도 상승(+0.3도씩) 로직 구현 + // 부모 운동 시간 입력 오늘 1회만 온도 상승 + public void increaseTemperatureForParentExerciseInput(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_PARENT_EXERCISE_INPUT, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_PARENT_EXERCISE_INPUT) + .build(); + temperatureRepository.save(temp); + } + } + // 자녀 통증 부위 확인 오늘 1회만 온도 상승 + public void increaseTemperatureForChildPainView(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_CHILD_PAIN_VIEW, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_CHILD_PAIN_VIEW) + .build(); + temperatureRepository.save(temp); + } + } + // 자녀 약 복용 확인 오늘 1회만 온도 상승 + public void increaseTemperatureForChildMedView(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_CHILD_MED_VIEW, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_CHILD_MED_VIEW) + .build(); + temperatureRepository.save(temp); + } + } + // 자녀 운동 시간 확인 오늘 1회만 온도 상승 + public void increaseTemperatureForChildExerciseView(UUID userId, String familyId) { + java.time.LocalDate today = getToday(); + boolean already = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_CHILD_EXERCISE_VIEW, today); + if (!already) { + Temperature temp = Temperature.builder() + .userId(userId) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_CHILD_EXERCISE_VIEW) + .build(); + temperatureRepository.save(temp); + } } - // 가족 만보기 걸음수 충족 시 온도 상승 - public void increaseTemperatureForStepGoal(String familyId) { - // TODO: 걸음수 충족 시 온도 상승(+0.2도) 로직 구현 + + // 매일 23:59:59에 당일의 가족별 보너스 온도 상승 처리 + @Scheduled(cron = "59 59 23 * * *") + @Transactional + public void processFamilyBonusTemperature() { + var families = familyRepository.findAll(); + java.time.LocalDate targetDate = getToday(); // 오늘 날짜 + for (var family : families) { + String familyId = family.getCode(); + var members = family.getMembers(); + + // 전체 가족 구성원이 감정기록 업로드 시 보너스 + boolean allEmotionUploaded = members.stream().allMatch( + userId -> temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(userId, familyId, REASON_EMOTION_UPLOAD, targetDate) + ); + boolean alreadyEmotionBonus = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(null, familyId, REASON_ALL_EMOTION_UPLOAD, targetDate); + if (allEmotionUploaded && !alreadyEmotionBonus) { + Temperature temp = Temperature.builder() + .userId(null) + .familyId(familyId) + .temperature(0.1) + .reason(REASON_ALL_EMOTION_UPLOAD) + .build(); + temperatureRepository.save(temp); + } + + // 만보기 걸음 수 충족 시 보너스 + boolean alreadyStepBonus = temperatureRepository.existsByUserIdAndFamilyIdAndReasonAndDate(null, familyId, REASON_STEP_GOAL, targetDate); + // TODO: 가족 만보기 총 걸음수가 하루 {(부모 수) x 7,000 + (자녀 수) x 10,000}보 이상인지 검사 필요 + boolean stepGoalMet = false; // 실제 조건으로 대체 필요 + if (stepGoalMet && !alreadyStepBonus) { + Temperature temp = Temperature.builder() + .userId(null) + .familyId(familyId) + .temperature(0.2) + .reason(REASON_STEP_GOAL) + .build(); + temperatureRepository.save(temp); + } + } } + // 매주 일요일 23:59:59 에 만보기 경쟁 결과 보너스 온도 상승 처리 (후순위! 일단 안만들어도 됨) + // TODO: 만보기 전체 경쟁 상위 10% -> +3도 + // TODO: 만보기 전체 경쟁 상위 20% -> +1도 + - // 온도 하락 메서드 - // 부모 1명 이상 일주일 미접속 시 온도 하락 + + // 매일 23:59:59에 당일의 가족별 온도 하락 처리 + @Scheduled(cron = "59 59 23 * * *") + @Transactional + public void processFamilyTemperatureDecrease() { + var families = familyRepository.findAll(); + for (var family : families) { + String familyId = family.getCode(); + decreaseTemperatureForInactiveParent(familyId); + decreaseTemperatureForInactiveChild(familyId); + decreaseTemperatureForNoLogin(familyId); + } + } + + // 부모 1명 이상 일주일 아무 활동 없을 시 온도 하락 public void decreaseTemperatureForInactiveParent(String familyId) { - // TODO: 부모 미접속 시 온도 하락(-15도) 로직 구현 + // TODO: 부모 미접속 판별 로직 필요 + boolean parentInactive = false; // 실제 판별로 대체 + if (parentInactive) { + Temperature temp = Temperature.builder() + .userId(null) + .familyId(familyId) + .temperature(-10.0) + .reason("INACTIVE_PARENT") + .build(); + temperatureRepository.save(temp); + } } - // 자녀 1명 이상 일주일 미접속 시 온도 하락 + // 자녀 1명 이상 일주일 아무 활동 없을 시 온도 하락 public void decreaseTemperatureForInactiveChild(String familyId) { - // TODO: 자녀 미접속 시 온도 하락(-15도) 로직 구현 + // TODO: 자녀 미접속 판별 로직 필요 + boolean childInactive = false; // 실제 판별로 대체 + if (childInactive) { + Temperature temp = Temperature.builder() + .userId(null) + .familyId(familyId) + .temperature(-10.0) + .reason("INACTIVE_CHILD") + .build(); + temperatureRepository.save(temp); + } } - // 하루 동안 아무도 미접속 시 온도 하락 + // 하루 동안 아무도 활동 없을 시 시 온도 하락 public void decreaseTemperatureForNoLogin(String familyId) { - // TODO: 하루 미접속 시 온도 하락(-1도) 로직 구현 + // TODO: 전체 미접속 판별 로직 필요 + boolean noLogin = false; // 실제 판별로 대체 + if (noLogin) { + Temperature temp = Temperature.builder() + .userId(null) + .familyId(familyId) + .temperature(-0.5) + .reason("NO_LOGIN") + .build(); + temperatureRepository.save(temp); + } } } \ No newline at end of file diff --git a/backend/ongi/src/test/java/ongi/HealthRecordControllerTest.java b/backend/ongi/src/test/java/ongi/HealthRecordControllerTest.java index 431222e..e69de29 100644 --- a/backend/ongi/src/test/java/ongi/HealthRecordControllerTest.java +++ b/backend/ongi/src/test/java/ongi/HealthRecordControllerTest.java @@ -1,131 +0,0 @@ -package ongi; - -import ongi.health.controller.HealthRecordController; -import ongi.health.entity.PainRecord; -import ongi.health.entity.ExerciseRecord; -import ongi.health.service.HealthRecordService; -import ongi.health.dto.PainRecordResponse; -import ongi.health.dto.ExerciseRecordResponse; -import ongi.security.CustomUserDetails; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import java.time.LocalDate; -import java.util.List; -import java.util.UUID; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.BDDMockito.given; - -@ExtendWith(MockitoExtension.class) -class HealthRecordControllerTest { - - @Mock - private HealthRecordService healthRecordService; - - @InjectMocks - private HealthRecordController healthRecordController; - - private UUID parentId; - private CustomUserDetails userDetails; - - @BeforeEach - void setUp() { - parentId = UUID.randomUUID(); - userDetails = Mockito.mock(CustomUserDetails.class, Mockito.RETURNS_DEEP_STUBS); - Mockito.when(userDetails.getUser().getUuid()).thenReturn(parentId); - } - - @Test - @DisplayName("통증 기록 추가 성공") - void addPainRecord() { - PainRecord record = PainRecord.builder() - .id(1L) - .parentId(parentId) - .date(LocalDate.of(2024, 7, 18)) - .painArea(PainRecord.PainArea.HEAD) - .painLevel(PainRecord.PainLevel.STRONG) - .build(); - given(healthRecordService.addPainRecord(any(), any(), any(), any())).willReturn(record); - - PainRecordResponse response = healthRecordController.addPainRecord( - userDetails, - LocalDate.of(2024, 7, 18), - PainRecord.PainArea.HEAD, - PainRecord.PainLevel.STRONG - ).getBody(); - - assertNotNull(response); - assertEquals(1L, response.id()); - assertEquals("HEAD", response.painArea()); - assertEquals("STRONG", response.painLevel()); - } - - @Test - @DisplayName("운동 기록 추가 성공") - void addExerciseRecord() { - ExerciseRecord record = ExerciseRecord.builder() - .id(1L) - .parentId(parentId) - .date(LocalDate.of(2024, 7, 18)) - .duration(60) - .build(); - given(healthRecordService.addExerciseRecord(any(), any(), anyInt())).willReturn(record); - - ExerciseRecordResponse response = healthRecordController.addExerciseRecord( - userDetails, - LocalDate.of(2024, 7, 18), - 60 - ).getBody(); - - assertNotNull(response); - assertEquals(1L, response.id()); - assertEquals(60, response.duration()); - } - - @Test - @DisplayName("통증 기록 최근 7일 조회") - void getPainRecordsForLast7Days() { - List records = List.of( - PainRecord.builder() - .id(1L) - .parentId(parentId) - .date(LocalDate.of(2024, 7, 18)) - .painArea(PainRecord.PainArea.HEAD) - .painLevel(PainRecord.PainLevel.STRONG) - .build() - ); - given(healthRecordService.getPainRecordsForLast7Days(any())).willReturn(records); - - List response = healthRecordController.getParentPainRecordsForLast7Days(parentId).getBody(); - - assertNotNull(response); - assertEquals(1, response.size()); - assertEquals("HEAD", response.get(0).painArea()); - } - - @Test - @DisplayName("운동 기록 최근 7일 조회") - void getExerciseRecordsForLast7Days() { - List records = List.of( - ExerciseRecord.builder() - .id(1L) - .parentId(parentId) - .date(LocalDate.of(2024, 7, 18)) - .duration(60) - .build() - ); - given(healthRecordService.getExerciseRecordsForLast7Days(any())).willReturn(records); - - List response = healthRecordController.getParentExerciseRecordsForLast7Days(parentId).getBody(); - - assertNotNull(response); - assertEquals(1, response.size()); - assertEquals(60, response.get(0).duration()); - } -} \ No newline at end of file diff --git a/backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java b/backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java index 30be9a3..e69de29 100644 --- a/backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java +++ b/backend/ongi/src/test/java/ongi/TemperatureControllerUnitTest.java @@ -1,161 +0,0 @@ -package ongi; - -import ongi.exception.EntityNotFoundException; -import ongi.temperature.controller.TemperatureController; -import ongi.temperature.dto.FamilyTemperatureDailyResponse; -import ongi.temperature.dto.FamilyTemperatureContributionResponse; -import ongi.temperature.service.TemperatureService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.context.ActiveProfiles; - -import java.util.UUID; -import ongi.temperature.dto.FamilyTemperatureResponse; -import static org.mockito.BDDMockito.given; -import static org.junit.jupiter.api.Assertions.*; - -@ExtendWith(MockitoExtension.class) -@ActiveProfiles("test") -class TemperatureControllerUnitTest { - - @Mock - private TemperatureService temperatureService; - - @InjectMocks - private TemperatureController temperatureController; - - private String testFamilyId; - - @BeforeEach - void setUp() { - testFamilyId = "FAM123"; - } - - @Test - @DisplayName("가족 온도 요약 - 여러 가족, 구성원, 기여도 포함 성공") - void getFamilyTemperatureSummary_MultipleFamiliesAndMembers_Success() { - // given - UUID userId1 = UUID.randomUUID(); - UUID userId2 = UUID.randomUUID(); - UUID userId3 = UUID.randomUUID(); - FamilyTemperatureResponse.MemberTemperatureInfo m1 = FamilyTemperatureResponse.MemberTemperatureInfo.builder() - .userId(userId1).userName("홍길동").contributedTemperature(1.2).percentage(30.0).build(); - FamilyTemperatureResponse.MemberTemperatureInfo m2 = FamilyTemperatureResponse.MemberTemperatureInfo.builder() - .userId(userId2).userName("김철수").contributedTemperature(2.8).percentage(70.0).build(); - FamilyTemperatureResponse.MemberTemperatureInfo m3 = FamilyTemperatureResponse.MemberTemperatureInfo.builder() - .userId(userId3).userName("이영희").contributedTemperature(0.0).percentage(0.0).build(); - FamilyTemperatureResponse response = FamilyTemperatureResponse.builder() - .familyTemperature(36.5) - .totalContributedTemperature(4.0) - .memberTemperatures(java.util.Arrays.asList(m1, m2, m3)) - .build(); - given(temperatureService.getFamilyTemperatureSummary(testFamilyId)).willReturn(response); - - // when - FamilyTemperatureResponse result = temperatureController.getFamilyTemperatureSummary(testFamilyId).getBody(); - - // then - assertNotNull(result); - assertEquals(36.5, result.getFamilyTemperature()); - assertEquals(4.0, result.getTotalContributedTemperature()); - assertEquals("홍길동", result.getMemberTemperatures().get(0).getUserName()); - assertEquals("김철수", result.getMemberTemperatures().get(1).getUserName()); - assertEquals("이영희", result.getMemberTemperatures().get(2).getUserName()); - } - - @Test - @DisplayName("가족 온도 요약 - 존재하지 않는 가족") - void getFamilyTemperatureSummary_FamilyNotFound() { - // given - given(temperatureService.getFamilyTemperatureSummary(testFamilyId)) - .willThrow(new EntityNotFoundException("가족을 찾을 수 없습니다.")); - - // when & then - assertThrows(EntityNotFoundException.class, () -> - temperatureController.getFamilyTemperatureSummary(testFamilyId) - ); - } - - @Test - @DisplayName("가족 온도 일별 로그 - 여러 가족, 여러 일자 온도 로그 포함 성공") - void getFamilyTemperatureDaily_MultipleFamiliesAndLogs_Success() { - // given - FamilyTemperatureDailyResponse.DailyTemperature daily1 = new FamilyTemperatureDailyResponse.DailyTemperature( - java.time.LocalDate.now().minusDays(2), 36.6); - FamilyTemperatureDailyResponse.DailyTemperature daily2 = new FamilyTemperatureDailyResponse.DailyTemperature( - java.time.LocalDate.now().minusDays(1), 36.7); - FamilyTemperatureDailyResponse.DailyTemperature daily3 = new FamilyTemperatureDailyResponse.DailyTemperature( - java.time.LocalDate.now(), 36.8); - FamilyTemperatureDailyResponse response = new FamilyTemperatureDailyResponse( - java.util.Arrays.asList(daily1, daily2, daily3)); - given(temperatureService.getFamilyTemperatureDaily(testFamilyId)).willReturn(response); - - // when - FamilyTemperatureDailyResponse result = temperatureController.getFamilyTemperatureDaily(testFamilyId).getBody(); - - // then - assertNotNull(result); - assertEquals(3, result.getDailyTemperatures().size()); - assertEquals(36.6, result.getDailyTemperatures().get(0).getTotalTemperature()); - assertEquals(36.7, result.getDailyTemperatures().get(1).getTotalTemperature()); - assertEquals(36.8, result.getDailyTemperatures().get(2).getTotalTemperature()); - } - - @Test - @DisplayName("가족 온도 일별 로그 - 존재하지 않는 가족") - void getFamilyTemperatureDaily_FamilyNotFound() { - // given - given(temperatureService.getFamilyTemperatureDaily(testFamilyId)) - .willThrow(new EntityNotFoundException("가족을 찾을 수 없습니다.")); - - // when & then - assertThrows(EntityNotFoundException.class, () -> - temperatureController.getFamilyTemperatureDaily(testFamilyId) - ); - } - - @Test - @DisplayName("가족 온도 기여도 - 여러 가족, 여러 구성원, 여러 일자 기여도 포함 성공") - void getFamilyTemperatureContributions_MultipleFamiliesMembersLogs_Success() { - // given - java.util.UUID userId1 = java.util.UUID.randomUUID(); - java.util.UUID userId2 = java.util.UUID.randomUUID(); - FamilyTemperatureContributionResponse.Contribution c1 = new FamilyTemperatureContributionResponse.Contribution( - java.time.LocalDate.now().minusDays(2), userId1, 1.1); - FamilyTemperatureContributionResponse.Contribution c2 = new FamilyTemperatureContributionResponse.Contribution( - java.time.LocalDate.now().minusDays(1), userId2, 2.2); - FamilyTemperatureContributionResponse.Contribution c3 = new FamilyTemperatureContributionResponse.Contribution( - java.time.LocalDate.now(), userId1, 3.3); - FamilyTemperatureContributionResponse response = new FamilyTemperatureContributionResponse( - java.util.Arrays.asList(c1, c2, c3)); - given(temperatureService.getFamilyTemperatureContributions(testFamilyId)).willReturn(response); - - // when - FamilyTemperatureContributionResponse result = temperatureController.getFamilyTemperatureContributions(testFamilyId).getBody(); - - // then - assertNotNull(result); - assertEquals(3, result.getContributions().size()); - assertEquals(1.1, result.getContributions().get(0).getContributed()); - assertEquals(2.2, result.getContributions().get(1).getContributed()); - assertEquals(3.3, result.getContributions().get(2).getContributed()); - } - - @Test - @DisplayName("가족 온도 기여도 - 존재하지 않는 가족") - void getFamilyTemperatureContributions_FamilyNotFound() { - // given - given(temperatureService.getFamilyTemperatureContributions(testFamilyId)) - .willThrow(new EntityNotFoundException("가족을 찾을 수 없습니다.")); - - // when & then - assertThrows(EntityNotFoundException.class, () -> - temperatureController.getFamilyTemperatureContributions(testFamilyId) - ); - } -}