Skip to content

Commit

Permalink
Merge pull request #165 from Team-HMH/refactor/#164-validation-use-an…
Browse files Browse the repository at this point in the history
…notation

refactor: request dto에서 validation을 진행할 수 있도록 변경
  • Loading branch information
kseysh authored Jun 18, 2024
2 parents f219314 + fd415d3 commit 2622309
Show file tree
Hide file tree
Showing 25 changed files with 102 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class AppConstants {
public static final Long MINIMUM_APP_TIME = 0L;
public static final Long MAXIMUM_APP_TIME = 21_600_000L; // 6시간
public static final Long MAXIMUM_APP_TIME = 7_200_000L; // 2시간
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ 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, "앱 시간을 입력해주세요"),
INVALID_GOAL_TIME(HttpStatus.BAD_REQUEST, "앱 목표 시간이 유효하지 않습니다."),
;

private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package sopt.org.hmh.domain.app.dto.request;

import jakarta.validation.constraints.NotNull;

public record AppRemoveRequest(
@NotNull(message = "앱 코드는 null일 수 없습니다.")
String appCode
) {
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package sopt.org.hmh.domain.app.dto.request;

import jakarta.validation.Valid;
import java.util.List;

public record ChallengeAppArrayRequest(
List<ChallengeAppRequest> apps
List<@Valid ChallengeAppRequest> apps
) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
package sopt.org.hmh.domain.app.dto.request;

import jakarta.validation.constraints.NotNull;
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;

public record ChallengeAppRequest(
@NotNull(message = "앱 코드는 null일 수 없습니다.")
String appCode,
@NotNull(message = "앱 시간은 null일 수 없습니다.")
Long goalTime
) {
public ChallengeAppRequest {
if (goalTime > AppConstants.MAXIMUM_APP_TIME || goalTime < AppConstants.MINIMUM_APP_TIME) {
throw new AppException(AppError.INVALID_GOAL_TIME);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package sopt.org.hmh.domain.app.dto.request;

import jakarta.validation.constraints.NotNull;

public record HistoryAppRequest(
@NotNull(message = "앱 코드는 null일 수 없습니다.")
String appCode,
@NotNull(message = "앱 사용시간은 null일 수 없습니다.")
Long usageTime
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sopt.org.hmh.domain.auth.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
Expand Down Expand Up @@ -39,7 +40,7 @@ public ResponseEntity<BaseResponse<?>> orderLogin(
public ResponseEntity<BaseResponse<?>> orderSignup(
@RequestHeader("Authorization") final String socialAccessToken,
@RequestHeader("OS") final String os,
@RequestBody final SocialSignUpRequest request
@RequestBody @Valid final SocialSignUpRequest request
) {
return ResponseEntity
.status(AuthSuccess.SIGNUP_SUCCESS.getHttpStatus())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package sopt.org.hmh.domain.auth.dto.request;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import sopt.org.hmh.domain.challenge.dto.request.ChallengeRequest;
import sopt.org.hmh.domain.challenge.dto.request.ChallengeSignUpRequest;
import sopt.org.hmh.global.auth.social.SocialPlatform;

public record SocialSignUpRequest(
@NotNull(message = "소셜 플랫폼은 null일 수 없습니다.")
SocialPlatform socialPlatform,
String name,
@JsonProperty(value = "onboarding")
OnboardingRequest onboardingRequest,
@Valid
@JsonProperty(value = "challenge")
ChallengeSignUpRequest challengeSignUpRequest
) {
public ChallengeRequest toChallengeRequest() {
return new ChallengeRequest(challengeSignUpRequest.period(), challengeSignUpRequest.goalTime());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
public enum AuthError implements ErrorBase {

// 400 BAD REQUEST
INVALID_USER(HttpStatus.BAD_REQUEST, "Principle 객체가 없습니다."),
DUPLICATE_USER(HttpStatus.BAD_REQUEST, "이미 회원가입된 유저입니다."),

// 403 FORBIDDEN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ public LoginResponse signup(String socialAccessToken, SocialSignUpRequest reques

User user = userService.addUser(socialPlatform, socialId, request.name());

Challenge challenge = challengeService.addChallenge(user.getId(), request.challengeSignUpRequest().period(),
request.challengeSignUpRequest().goalTime(), os);
Challenge challenge = challengeService.addChallenge(user.getId(), request.toChallengeRequest() , os);
challengeService.addApps(challenge, request.challengeSignUpRequest().apps(), os);

userService.registerOnboardingInfo(request);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sopt.org.hmh.domain.challenge.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -27,8 +28,8 @@ public class ChallengeController implements ChallengeApi {
@Override
public ResponseEntity<BaseResponse<?>> orderAddChallenge(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody final ChallengeRequest request) {
challengeService.addChallenge(userId, request.period(), request.goalTime(), os);
@RequestBody @Valid final ChallengeRequest request) {
challengeService.addChallenge(userId, request, os);

return ResponseEntity
.status(ChallengeSuccess.ADD_CHALLENGE_SUCCESS.getHttpStatus())
Expand Down Expand Up @@ -59,7 +60,7 @@ public ResponseEntity<BaseResponse<DailyChallengeResponse>> orderGetDailyChallen
@Override
public ResponseEntity<BaseResponse<?>> orderAddApps(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody final ChallengeAppArrayRequest requests) {
@RequestBody @Valid final ChallengeAppArrayRequest requests) {
Challenge challenge = challengeService.findCurrentChallengeByUserId(userId);
challengeService.addApps(challenge, requests.apps(), os);

Expand All @@ -73,7 +74,7 @@ public ResponseEntity<BaseResponse<?>> orderAddApps(@UserId final Long userId,
@Override
public ResponseEntity<BaseResponse<?>> orderRemoveApp(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody final AppRemoveRequest request) {
@RequestBody @Valid final AppRemoveRequest request) {
Challenge challenge = challengeService.findCurrentChallengeByUserId(userId);
challengeService.removeApp(challenge, request, os);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sopt.org.hmh.domain.challenge.domain;

import java.util.List;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

Expand All @@ -9,5 +10,5 @@ public abstract class ChallengeConstants {
public static final Long MAXIMUM_GOAL_TIME = 21_600_000L; // 6시간
public static final Integer USAGE_POINT = 100;
public static final Integer EARNED_POINT = 20;

public static final List<Integer> AVAILABLE_CHALLENGE_PERIODS = List.of(7, 14, 20, 30);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
public enum ChallengeError implements ErrorBase {

CHALLENGE_NOT_FOUND(HttpStatus.NOT_FOUND, "챌린지를 찾을 수 없습니다."),
INVALID_PERIOD_NULL(HttpStatus.BAD_REQUEST, "챌린지 기간은 null일 수 없습니다."),
INVALID_PERIOD_NUMERIC(HttpStatus.BAD_REQUEST, "유효한 숫자의 챌린지 기간을 입력해주세요."),
INVALID_GOAL_TIME_NULL(HttpStatus.BAD_REQUEST, "목표시간은 null일 수 없습니다."),
INVALID_GOAL_TIME_NUMERIC(HttpStatus.BAD_REQUEST, "유효한 숫자의 목표 시간을 입력해주세요."),
CHALLENGE_ALREADY_FAILED_TODAY(HttpStatus.BAD_REQUEST, "이미 실패 처리 된 챌린지입니다."),
INVALID_PERIOD_NUMERIC(HttpStatus.BAD_REQUEST, "유효한 챌린지 기간이 아닙니다."),
INVALID_GOAL_TIME(HttpStatus.BAD_REQUEST, "챌린지 목표 시간이 유효하지 않습니다."),
;

private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package sopt.org.hmh.domain.challenge.dto.request;

import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;

public record ChallengeDateRequest(
@NotNull(message = "챌린지 날짜는 null일 수 없습니다.")
LocalDate challengeDate
) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
package sopt.org.hmh.domain.challenge.dto.request;

import jakarta.validation.constraints.NotNull;
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.challenge.domain.ChallengeConstants;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeError;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeException;

public record ChallengeRequest(
@NotNull(message = "챌린지 기간은 null일 수 없습니다.")
Integer period,
@NotNull(message = "챌린지 목표시간은 null일 수 없습니다.")
Long goalTime
) {
}

public ChallengeRequest {
if (!ChallengeConstants.AVAILABLE_CHALLENGE_PERIODS.contains(period)) {
throw new ChallengeException(ChallengeError.INVALID_PERIOD_NUMERIC);
}
if (goalTime > ChallengeConstants.MAXIMUM_GOAL_TIME || goalTime < ChallengeConstants.MINIMUM_GOAL_TIME) {
throw new ChallengeException(ChallengeError.INVALID_GOAL_TIME);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
package sopt.org.hmh.domain.challenge.dto.request;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import sopt.org.hmh.domain.app.dto.request.ChallengeAppRequest;

import java.util.List;
import sopt.org.hmh.domain.challenge.domain.ChallengeConstants;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeError;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeException;

public record ChallengeSignUpRequest(
@NotNull(message = "챌린지 기간은 null일 수 없습니다.")
Integer period,
@NotNull(message = "챌린지 목표시간은 null일 수 없습니다.")
Long goalTime,
List<ChallengeAppRequest> apps
List<@Valid ChallengeAppRequest> apps
) {
public ChallengeSignUpRequest {
if (goalTime > ChallengeConstants.MAXIMUM_GOAL_TIME || goalTime < ChallengeConstants.MINIMUM_GOAL_TIME) {
throw new ChallengeException(ChallengeError.INVALID_GOAL_TIME);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sopt.org.hmh.domain.app.domain.AppConstants;
import sopt.org.hmh.domain.app.domain.ChallengeApp;
import sopt.org.hmh.domain.app.domain.exception.AppError;
import sopt.org.hmh.domain.app.domain.exception.AppException;
Expand All @@ -12,10 +11,9 @@
import sopt.org.hmh.domain.app.dto.response.ChallengeAppResponse;
import sopt.org.hmh.domain.app.repository.ChallengeAppRepository;
import sopt.org.hmh.domain.challenge.domain.Challenge;
import sopt.org.hmh.domain.challenge.domain.ChallengeConstants;
import sopt.org.hmh.domain.challenge.domain.ChallengeDay;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeError;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeException;
import sopt.org.hmh.domain.challenge.dto.request.ChallengeRequest;
import sopt.org.hmh.domain.challenge.dto.response.ChallengeResponse;
import sopt.org.hmh.domain.challenge.dto.response.DailyChallengeResponse;
import sopt.org.hmh.domain.challenge.repository.ChallengeRepository;
Expand All @@ -40,9 +38,9 @@ public class ChallengeService {
private final UserService userService;

@Transactional
public Challenge addChallenge(Long userId, Integer period, Long goalTime, String os) {
validateChallengePeriod(period);
validateChallengeGoalTime(goalTime);
public Challenge addChallenge(Long userId, ChallengeRequest challengeRequest, String os) {
Integer period = challengeRequest.period();
Long goalTime = challengeRequest.goalTime();

Challenge challenge = challengeRepository.save(Challenge.builder()
.userId(userId)
Expand Down Expand Up @@ -107,7 +105,6 @@ public DailyChallengeResponse getDailyChallenge(Long userId) {

@Transactional
public void removeApp(Challenge challenge, AppRemoveRequest request, String os) {
validateAppCode(request.appCode());
ChallengeApp appToRemove = challengeAppRepository
.findFirstByChallengeIdAndAppCodeAndOsOrElseThrow(challenge.getId(), request.appCode(), os);
challengeAppRepository.delete(appToRemove);
Expand All @@ -118,8 +115,6 @@ public void addApps(Challenge challenge, List<ChallengeAppRequest> requests, Str
List<ChallengeApp> appsToUpdate = requests.stream()
.map(request -> {
validateAppExist(challenge.getId(), request.appCode(), os);
validateAppCode(request.appCode());
validateAppTime(request.goalTime());
return ChallengeApp.builder()
.challenge(challenge)
.appCode(request.appCode())
Expand All @@ -140,44 +135,12 @@ private Integer calculateTodayIndex(LocalDateTime challengeCreateAt, int period)
return (daysBetween >= period) ? -1 : daysBetween;
}

private void validateChallengePeriod(Integer period) {
if (period == null) {
throw new ChallengeException(ChallengeError.INVALID_PERIOD_NULL);
}
if (period != ChallengeDay.DAYS7.getValue() && period != ChallengeDay.DAYS14.getValue() && period != ChallengeDay.DAYS20.getValue() && period != ChallengeDay.DAYS30.getValue()) {
throw new ChallengeException(ChallengeError.INVALID_PERIOD_NUMERIC);
}
}

private void validateChallengeGoalTime(Long goalTime) {
if (goalTime == null) {
throw new ChallengeException(ChallengeError.INVALID_GOAL_TIME_NULL);
}
if (goalTime < ChallengeConstants.MINIMUM_GOAL_TIME || goalTime > ChallengeConstants.MAXIMUM_GOAL_TIME) {
throw new ChallengeException(ChallengeError.INVALID_GOAL_TIME_NUMERIC);
}
}

private void validateAppExist(Long challengeId, String appCode, String os) {
if (challengeAppRepository.existsByChallengeIdAndAppCodeAndOs(challengeId, appCode, os)) {
throw new AppException(AppError.APP_EXIST_ALREADY);
}
}

private void validateAppCode(String appCode) {
if (appCode.isEmpty()) {
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);
}

public Challenge findByIdOrElseThrow(Long challengeId) {
return challengeRepository.findById(challengeId).orElseThrow(
() -> new ChallengeException(ChallengeError.CHALLENGE_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sopt.org.hmh.domain.dailychallenge.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -25,7 +26,7 @@ public class DailyChallengeController implements DailyChallengeApi {
public ResponseEntity<BaseResponse<EmptyJsonResponse>> orderAddHistoryDailyChallenge(
@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody final FinishedDailyChallengeListRequest request
@RequestBody @Valid final FinishedDailyChallengeListRequest request
) {
dailyChallengeFacade.addFinishedDailyChallengeHistory(userId, request, os);
return ResponseEntity
Expand Down
Loading

0 comments on commit 2622309

Please sign in to comment.