diff --git a/src/main/java/sopt/org/HMH/domain/app/domain/AppConstants.java b/src/main/java/sopt/org/HMH/domain/app/domain/AppConstants.java new file mode 100644 index 00000000..45d79d2d --- /dev/null +++ b/src/main/java/sopt/org/HMH/domain/app/domain/AppConstants.java @@ -0,0 +1,6 @@ +package sopt.org.HMH.domain.app.domain; + +public abstract class AppConstants { + public static final Long MINIMUM_APP_TIME = 0L; + public static final Long MAXIMUM_APP_TIME = 3659000L; +} \ No newline at end of file diff --git a/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppError.java b/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppError.java new file mode 100644 index 00000000..cdd4dc24 --- /dev/null +++ b/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppError.java @@ -0,0 +1,34 @@ +package sopt.org.HMH.domain.app.domain.exception; + +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; +import sopt.org.HMH.global.common.exception.base.ErrorBase; + +@AllArgsConstructor +public enum AppError implements ErrorBase { + + APP_NOT_FOUND(HttpStatus.NOT_FOUND, "앱을 찾을 수 없습니다."), + APP_EXIST_ALREADY(HttpStatus.CONFLICT, "이미 추가된 앱입니다."), + INVALID_APP_CODE_NULL(HttpStatus.BAD_REQUEST, "앱 코드 값이 비어있습니다"), + INVALID_TIME_RANGE(HttpStatus.BAD_REQUEST, "앱 시간의 범위가 유효한지 확인해주세요"), + INVALID_TIME_NULL(HttpStatus.BAD_REQUEST, "앱 시간을 입력해주세요"), + ; + + private final HttpStatus status; + private final String errorMessage; + + @Override + public int getHttpStatusCode() { + return status.value(); + } + + @Override + public HttpStatus getHttpStatus() { + return this.status; + } + + @Override + public String getErrorMessage() { + return this.errorMessage; + } +} \ No newline at end of file diff --git a/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppException.java b/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppException.java new file mode 100644 index 00000000..0445c339 --- /dev/null +++ b/src/main/java/sopt/org/HMH/domain/app/domain/exception/AppException.java @@ -0,0 +1,10 @@ +package sopt.org.HMH.domain.app.domain.exception; + +import sopt.org.HMH.global.common.exception.base.ExceptionBase; + +public class AppException extends ExceptionBase { + + public AppException(AppError error) { + super(error); + } +} \ No newline at end of file diff --git a/src/main/java/sopt/org/HMH/domain/app/repository/AppRepository.java b/src/main/java/sopt/org/HMH/domain/app/repository/AppRepository.java index 243f6007..5d585cf7 100644 --- a/src/main/java/sopt/org/HMH/domain/app/repository/AppRepository.java +++ b/src/main/java/sopt/org/HMH/domain/app/repository/AppRepository.java @@ -2,8 +2,19 @@ import org.springframework.data.jpa.repository.JpaRepository; import sopt.org.HMH.domain.app.domain.App; +import sopt.org.HMH.domain.app.domain.exception.AppError; +import sopt.org.HMH.domain.app.domain.exception.AppException; + +import java.util.Optional; public interface AppRepository extends JpaRepository { - App findByDailyChallengeIdAndAppCodeAndOs(Long dailyChallengeId, String appCode, String os); + Optional findFirstByDailyChallengeIdAndAppCodeAndOs(Long dailyChallengeId, String appCode, String os); + + default App findFirstByDailyChallengeIdAndAppCodeAndOsOrElseThrow(Long dailyChallengeId, String appCode, String os) { + return findFirstByDailyChallengeIdAndAppCodeAndOs(dailyChallengeId, appCode, os).orElseThrow(() -> new AppException( + AppError.APP_NOT_FOUND)); + } + + boolean existsByDailyChallengeIdAndAppCodeAndOs(Long dailyChallengeId, String appCode, String os); } \ No newline at end of file diff --git a/src/main/java/sopt/org/HMH/domain/app/service/AppService.java b/src/main/java/sopt/org/HMH/domain/app/service/AppService.java index 01d239a3..8c631621 100644 --- a/src/main/java/sopt/org/HMH/domain/app/service/AppService.java +++ b/src/main/java/sopt/org/HMH/domain/app/service/AppService.java @@ -4,6 +4,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import sopt.org.HMH.domain.app.domain.App; +import sopt.org.HMH.domain.app.domain.AppConstants; +import sopt.org.HMH.domain.app.domain.exception.AppError; +import sopt.org.HMH.domain.app.domain.exception.AppException; import sopt.org.HMH.domain.app.dto.request.AppDeleteRequest; import sopt.org.HMH.domain.app.dto.request.AppGoalTimeRequest; import sopt.org.HMH.domain.app.repository.AppRepository; @@ -15,27 +18,26 @@ @Service @RequiredArgsConstructor public class AppService { - private final AppRepository appRepository; private final DailyChallengeService dailyChallengeService; @Transactional public void addAppsAndUpdateRemainingDailyChallenge(Long userId, List requests, String os) { - dailyChallengeService.getRemainingDailyChallengesByUserId(userId).stream() + dailyChallengeService.getRemainingDailyChallengesByUserId(userId) .forEach(dailyChallenge -> addApps(dailyChallenge, requests, os)); } @Transactional public void removeAppAndUpdateRemainingDailyChallenge(Long userId, AppDeleteRequest request, String os) { - dailyChallengeService.getRemainingDailyChallengesByUserId(userId).stream() + dailyChallengeService.getRemainingDailyChallengesByUserId(userId) .forEach(dailyChallenge -> removeApp(dailyChallenge, request, os)); } - @Transactional public void removeApp(DailyChallenge dailyChallenge, AppDeleteRequest request, String os) { - appRepository.delete(appRepository.findByDailyChallengeIdAndAppCodeAndOs( + validateAppCode(request.appCode()); + appRepository.delete(appRepository.findFirstByDailyChallengeIdAndAppCodeAndOsOrElseThrow( dailyChallenge.getId(), request.appCode(), os)); @@ -44,12 +46,38 @@ public void removeApp(DailyChallenge dailyChallenge, AppDeleteRequest request, S @Transactional public List addApps(DailyChallenge dailyChallenge, List requests, String os) { List appStream = requests.stream() - .map(request -> App.builder().dailyChallenge(dailyChallenge) - .appCode(request.appCode()) - .goalTime(request.goalTime()) - .os(os).build() - ).toList(); + .map(request -> { + validateAppExist(dailyChallenge.getId(), request.appCode(), os); + validateAppCode(request.appCode()); + validateAppTime(request.goalTime()); + return App.builder() + .dailyChallenge(dailyChallenge) + .appCode(request.appCode()) + .goalTime(request.goalTime()) + .os(os) + .build(); + }).toList(); return appRepository.saveAll(appStream); } + + private void validateAppExist(Long dailyChallengeId, String appCode, String os) { + if (appRepository.existsByDailyChallengeIdAndAppCodeAndOs(dailyChallengeId, appCode, os)) { + throw new AppException(AppError.APP_EXIST_ALREADY); + } + } + + private void validateAppCode(String appCode) { + if (appCode == "") { + throw new AppException(AppError.INVALID_APP_CODE_NULL); + } + } + + private void validateAppTime(Long appTime) { + if (appTime == null) { + throw new AppException(AppError.INVALID_TIME_NULL); + } + if (appTime > AppConstants.MAXIMUM_APP_TIME || appTime < AppConstants.MINIMUM_APP_TIME) + throw new AppException(AppError.INVALID_TIME_RANGE); + } } \ No newline at end of file diff --git a/src/main/java/sopt/org/HMH/domain/dailychallenge/service/DailyChallengeService.java b/src/main/java/sopt/org/HMH/domain/dailychallenge/service/DailyChallengeService.java index decc74d0..96204452 100644 --- a/src/main/java/sopt/org/HMH/domain/dailychallenge/service/DailyChallengeService.java +++ b/src/main/java/sopt/org/HMH/domain/dailychallenge/service/DailyChallengeService.java @@ -4,6 +4,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import sopt.org.HMH.domain.app.domain.App; +import sopt.org.HMH.domain.app.domain.AppConstants; +import sopt.org.HMH.domain.app.domain.exception.AppError; +import sopt.org.HMH.domain.app.domain.exception.AppException; import sopt.org.HMH.domain.app.dto.request.AppUsageTimeRequest; import sopt.org.HMH.domain.app.repository.AppRepository; import sopt.org.HMH.domain.challenge.domain.Challenge; @@ -49,7 +52,8 @@ public void modifyDailyChallengeStatus(Long userId, List re DailyChallenge todayDailyChallenge = getTodayDailyChallengeByUserId(userId); long successCount = requests.stream() .filter(request -> { - App app = appRepository.findByDailyChallengeIdAndAppCodeAndOs( + validateModifyDailyChallenge(request.appCode(), request.usageTime()); + App app = appRepository.findFirstByDailyChallengeIdAndAppCodeAndOsOrElseThrow( todayDailyChallenge.getId(), request.appCode(), os); app.setUsageTime(request.usageTime()); return (request.usageTime() <= app.getGoalTime()); @@ -58,6 +62,17 @@ public void modifyDailyChallengeStatus(Long userId, List re todayDailyChallenge.setStatus(status); } + private void validateModifyDailyChallenge(String appCode, Long usageTime) { + if (appCode == "") { + throw new AppException(AppError.INVALID_APP_CODE_NULL); + } + if (usageTime == null) { + throw new AppException(AppError.INVALID_TIME_NULL); + } + if (usageTime > AppConstants.MAXIMUM_APP_TIME || usageTime < AppConstants.MINIMUM_APP_TIME) + throw new AppException(AppError.INVALID_TIME_RANGE); + } + public DailyChallenge getTodayDailyChallengeByUserId(Long userId) { Challenge challenge = challengeRepository.findFirstByUserIdOrderByCreatedAtDescOrElseThrow(userId);