Skip to content

Commit

Permalink
Merge pull request #70 from makevook/issue/69
Browse files Browse the repository at this point in the history
feat: 온보딩 완료 API 수정
  • Loading branch information
seungyeop-lee authored Jun 9, 2024
2 parents 88ebb08 + b83e4d4 commit 4489a33
Show file tree
Hide file tree
Showing 17 changed files with 189 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package vook.server.api.app.common;

import lombok.Getter;

@Getter
public abstract class AppException extends RuntimeException {
public abstract String contents();
}
5 changes: 5 additions & 0 deletions api/src/main/java/vook/server/api/app/user/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import vook.server.api.app.user.data.CompleteOnboardingCommand;
import vook.server.api.app.user.data.RegisterCommand;
import vook.server.api.app.user.data.SignUpFromSocialCommand;
import vook.server.api.app.user.exception.NotReadyToOnboardingException;
import vook.server.api.app.user.repo.SocialUserRepository;
import vook.server.api.app.user.repo.UserInfoRepository;
import vook.server.api.app.user.repo.UserRepository;
Expand Down Expand Up @@ -57,6 +58,10 @@ public void register(RegisterCommand command) {

public void completeOnboarding(CompleteOnboardingCommand command) {
User user = repository.findByUid(command.getUserUid()).orElseThrow();
if (!user.isReadyToOnboarding()) {
throw new NotReadyToOnboardingException();
}

user.onboardingCompleted();

user.getUserInfo().addOnboardingInfo(command.getFunnel(), command.getJob());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package vook.server.api.app.user.data;

import lombok.Getter;
import vook.server.api.model.user.Funnel;
import vook.server.api.model.user.Job;

@Getter
public class CompleteOnboardingCommand {

public String userUid;
public String funnel;
public String job;
public Funnel funnel;
public Job job;

public static CompleteOnboardingCommand of(
String userUid,
String funnel,
String job
Funnel funnel,
Job job
) {
CompleteOnboardingCommand command = new CompleteOnboardingCommand();
command.userUid = userUid;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package vook.server.api.app.user.exception;

import vook.server.api.app.common.AppException;

public class NotReadyToOnboardingException extends AppException {

@Override
public String contents() {
return "NotReadyToOnboarding";
}
}
24 changes: 24 additions & 0 deletions api/src/main/java/vook/server/api/model/user/Funnel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package vook.server.api.model.user;

public enum Funnel {
//X
X,

//페이스북
FACEBOOK,

//링크드인
LINKEDIN,

//인스타그램
INSTAGRAM,

//네이버 블로그
NAVER_BLOG,

//친구/지인 추천
RECOMMENDATION,

//기타
OTHER
}
24 changes: 24 additions & 0 deletions api/src/main/java/vook/server/api/model/user/Job.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package vook.server.api.model.user;

public enum Job {
//기획자
PLANNER,

//디자이너
DESIGNER,

//개발자
DEVELOPER,

//마케터
MARKETER,

//CEO
CEO,

//HR
HR,

//기타
OTHER
}
4 changes: 4 additions & 0 deletions api/src/main/java/vook/server/api/model/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ public void registered() {
public void onboardingCompleted() {
this.status = UserStatus.ONBOARDING_COMPLETED;
}

public boolean isReadyToOnboarding() {
return status == UserStatus.REGISTERED;
}
}
8 changes: 5 additions & 3 deletions api/src/main/java/vook/server/api/model/user/UserInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ public class UserInfo {

private Boolean marketingEmailOptIn;

private String funnel;
@Enumerated(EnumType.STRING)
private Funnel funnel;

private String job;
@Enumerated(EnumType.STRING)
private Job job;

@OneToOne
@JoinColumn(name = "user_id")
Expand All @@ -36,7 +38,7 @@ public static UserInfo forRegisterOf(
return result;
}

public void addOnboardingInfo(String funnel, String job) {
public void addOnboardingInfo(Funnel funnel, Job job) {
this.funnel = funnel;
this.job = job;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ public String code() {

enum BadRequest implements ApiResponseCode {

INVALID_PARAMETER;
INVALID_PARAMETER,
VIOLATION_BUSINESS_RULE,
;

@Override
public String code() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,43 @@
package vook.server.api.web.common;

public class CommonApiException {
public static abstract class Exception extends RuntimeException {
public class CommonApiException extends RuntimeException {

protected ApiResponseCode code;
private final ApiResponseCode code;
private final int statusCode;
private final String message;

public Exception(ApiResponseCode code, Throwable cause) {
super(code.code(), cause);
this.code = code;
}

abstract CommonApiResponse<?> response();

abstract int statusCode();
CommonApiException(ApiResponseCode code, int statusCode, Throwable cause) {
this(code, statusCode, cause, null);
}

public static class BadRequest extends Exception {

public BadRequest(ApiResponseCode code, Throwable cause) {
super(code, cause);
}
CommonApiException(ApiResponseCode code, int statusCode, Throwable cause, String message) {
super(code.code(), cause);
this.code = code;
this.statusCode = statusCode;
this.message = message;
}

@Override
public CommonApiResponse<?> response() {
public CommonApiResponse<?> response() {
if (message == null) {
return CommonApiResponse.noResult(code);
}

@Override
int statusCode() {
return 400;
} else {
return CommonApiResponse.withResult(code, message);
}
}

public static class ServerError extends Exception {
public int statusCode() {
return statusCode;
}

public ServerError(ApiResponseCode code, Throwable cause) {
super(code, cause);
}
public static CommonApiException badRequest(ApiResponseCode code, Throwable cause) {
return new CommonApiException(code, 400, cause);
}

@Override
public CommonApiResponse<?> response() {
return CommonApiResponse.noResult(code);
}
public static CommonApiException badRequest(ApiResponseCode code, Throwable cause, String message) {
return new CommonApiException(code, 400, cause, message);
}

@Override
int statusCode() {
return 500;
}
public static CommonApiException serverError(ApiResponseCode code, Throwable cause) {
return new CommonApiException(code, 500, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,47 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import vook.server.api.app.common.AppException;

@Slf4j
@RestControllerAdvice
public class GlobalRestControllerAdvice {

@ExceptionHandler(CommonApiException.Exception.class)
public ResponseEntity<?> handleCommonApiException(CommonApiException.Exception e) {
@ExceptionHandler(AppException.class)
public ResponseEntity<?> handleAppException(AppException e) {
log.error(e.getMessage(), e);
CommonApiException badRequest = CommonApiException.badRequest(ApiResponseCode.BadRequest.VIOLATION_BUSINESS_RULE, e, e.contents());
return ResponseEntity.status(badRequest.statusCode()).body(badRequest.response());
}

@ExceptionHandler(CommonApiException.class)
public ResponseEntity<?> handleCommonApiException(CommonApiException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(e.statusCode()).body(e.response());
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
CommonApiException.BadRequest badRequest = new CommonApiException.BadRequest(ApiResponseCode.BadRequest.INVALID_PARAMETER, e);
log.debug(e.getMessage(), e);
CommonApiException badRequest = CommonApiException.badRequest(ApiResponseCode.BadRequest.INVALID_PARAMETER, e);
return ResponseEntity.status(badRequest.statusCode()).body(badRequest.response());
}

@ExceptionHandler(HttpMessageConversionException.class)
public ResponseEntity<?> handleHttpMessageConversionException(HttpMessageConversionException e) {
log.debug(e.getMessage(), e);
CommonApiException badRequest = CommonApiException.badRequest(ApiResponseCode.BadRequest.INVALID_PARAMETER, e);
return ResponseEntity.status(badRequest.statusCode()).body(badRequest.response());
}

@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleException(Exception e) {
log.error(e.getMessage(), e);
CommonApiException.ServerError serverError = new CommonApiException.ServerError(ApiResponseCode.ServerError.UNHANDLED_ERROR, e);
CommonApiException serverError = CommonApiException.serverError(ApiResponseCode.ServerError.UNHANDLED_ERROR, e);
return ResponseEntity.status(serverError.statusCode()).body(serverError.response());
}
}
13 changes: 13 additions & 0 deletions api/src/main/java/vook/server/api/web/routes/user/UserApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,18 @@ class UserApiUerInfoResponse extends CommonApiResponse<UserInfoResponse> {
@SecurityRequirement(name = "AccessToken")
}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "400",
content = @Content(
mediaType = "application/json",
schema = @Schema(ref = ComponentRefConsts.Schema.COMMON_API_RESPONSE),
examples = {
@ExampleObject(name = "유효하지 않은 파라미터", ref = ComponentRefConsts.Example.INVALID_PARAMETER),
@ExampleObject(name = "비즈니스 규칙 위반", ref = ComponentRefConsts.Example.VIOLATION_BUSINESS_RULE)
}
)
),
})
CommonApiResponse<Void> onboardingComplete(VookLoginUser user, UserOnboardingCompleteRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import lombok.Data;
import vook.server.api.app.user.data.CompleteOnboardingCommand;
import vook.server.api.model.user.Funnel;
import vook.server.api.model.user.Job;

@Data
public class UserOnboardingCompleteRequest {

public String funnel;
public String job;
public Funnel funnel;
public Job job;

public CompleteOnboardingCommand toCommand(String uid) {
return CompleteOnboardingCommand.of(uid, funnel, job);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ public static class Example {
public static final String SUCCESS = "#/components/examples/Success";
public static final String INVALID_PARAMETER = "#/components/examples/InvalidParameter";
public static final String UNHANDLED_ERROR = "#/components/examples/UnhandledError";
public static final String VIOLATION_BUSINESS_RULE = "#/components/examples/ViolationBusinessRule";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ private static void applyCommonApiResponseSchema(OpenAPI openApi) {
"code": "%s"
}""", ApiResponseCode.BadRequest.INVALID_PARAMETER.code()))
)
.addExamples(getKey(ComponentRefConsts.Example.VIOLATION_BUSINESS_RULE), new Example()
.description("비즈니스 규칙 위반")
.value(String.format("""
{
"code": "%s",
"result": "규칙 위반 내용 (ex. NotReadyToOnboarding)"
}""", ApiResponseCode.BadRequest.VIOLATION_BUSINESS_RULE.code()))
)
.addExamples(getKey(ComponentRefConsts.Example.UNHANDLED_ERROR), new Example()
.description("처리되지 않은 서버 에러")
.value(String.format("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import vook.server.api.app.user.data.CompleteOnboardingCommand;
import vook.server.api.app.user.data.RegisterCommand;
import vook.server.api.app.user.data.SignUpFromSocialCommand;
import vook.server.api.model.user.Funnel;
import vook.server.api.model.user.Job;
import vook.server.api.model.user.SocialUser;
import vook.server.api.model.user.User;
import vook.server.api.web.auth.app.TokenService;
Expand Down Expand Up @@ -35,7 +37,7 @@ public User createRegisteredUser() {

public User createCompletedOnboardingUser() {
User user = createRegisteredUser();
userService.completeOnboarding(CompleteOnboardingCommand.of(user.getUid(), "testFunnel", "testJob"));
userService.completeOnboarding(CompleteOnboardingCommand.of(user.getUid(), Funnel.OTHER, Job.OTHER));
return userService.findByUid(user.getUid()).orElseThrow();
}

Expand Down
Loading

0 comments on commit 4489a33

Please sign in to comment.