Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEV-32] 커스텀 에러코드 적용 #281

Merged
merged 16 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@NoArgsConstructor
public class SignInRequest {

@NotBlank(message = "아아디를 입력해주세요.")
@NotBlank(message = "아이디를 입력해주세요.")
@Schema(name = "authId", example = "plzgraduate")
private String authId;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.plzgraduate.myongjigraduatebe.auth.security;

import static com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode.*;

import java.io.IOException;

import javax.servlet.ServletException;
Expand All @@ -12,6 +14,7 @@
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode;
import com.plzgraduate.myongjigraduatebe.core.exception.ExceptionResponse;

import lombok.RequiredArgsConstructor;
Expand All @@ -20,13 +23,13 @@
@RequiredArgsConstructor
public class JwtAccessDeniedHandler implements AccessDeniedHandler {

private static final ExceptionResponse E403 = ExceptionResponse.of(HttpStatus.FORBIDDEN, "Authentication error (cause: forbidden)");
private static final ExceptionResponse E403 = ExceptionResponse.from(AUTHENTICATION_FAIL_FORBIDDEN.toString());

private final ObjectMapper om;

@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setHeader("content-type", "application/json");
response.getWriter().write(om.writeValueAsString(E403));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.plzgraduate.myongjigraduatebe.auth.security;

import static com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode.*;

import java.io.IOException;

import javax.servlet.ServletException;
Expand All @@ -12,20 +14,21 @@
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode;
import com.plzgraduate.myongjigraduatebe.core.exception.ExceptionResponse;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint{
private static final ExceptionResponse E401 = ExceptionResponse.of(HttpStatus.UNAUTHORIZED, "Authentication error (cause: unauthorized)");
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final ExceptionResponse E401 = ExceptionResponse.from(AUTHENTICATION_FAIL_UNAUTHORIZED.toString());

private final ObjectMapper om;

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
AuthenticationException authException) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setHeader("content-type", "application/json");
response.getWriter().write(om.writeValueAsString(E401));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.plzgraduate.myongjigraduatebe.auth.security;

import static com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode.*;
import static org.hibernate.validator.internal.util.TypeHelper.isAssignable;

import java.util.Collections;
Expand All @@ -10,6 +11,7 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode;
import com.plzgraduate.myongjigraduatebe.core.exception.UnAuthorizedException;
import com.plzgraduate.myongjigraduatebe.user.application.usecase.find.FindUserUseCase;
import com.plzgraduate.myongjigraduatebe.user.domain.model.User;
Expand All @@ -35,14 +37,14 @@
}

private Authentication processAuthentication(JwtAuthenticationToken authenticationToken) {
User user = findUserUseCase.findUserByAuthId(String.valueOf(authenticationToken.getPrincipal()));

Check warning on line 40 in src/main/java/com/plzgraduate/myongjigraduatebe/auth/security/JwtAuthenticationProvider.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/plzgraduate/myongjigraduatebe/auth/security/JwtAuthenticationProvider.java#L40

Added line #L40 was not covered by tests
try {
User user = findUserUseCase.findUserByAuthId(String.valueOf(authenticationToken.getPrincipal()));
user.matchPassword(passwordEncoder, String.valueOf(authenticationToken.getCredentials()));
return new JwtAuthenticationToken(
user.getId(), null, Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"))
);
} catch (IllegalArgumentException e) {
throw new UnAuthorizedException("아이디 혹은 비밀번호가 일치하지 않습니다.");
throw new UnAuthorizedException(INCORRECT_PASSWORD.toString());

Check warning on line 47 in src/main/java/com/plzgraduate/myongjigraduatebe/auth/security/JwtAuthenticationProvider.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/plzgraduate/myongjigraduatebe/auth/security/JwtAuthenticationProvider.java#L47

Added line #L47 was not covered by tests
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.plzgraduate.myongjigraduatebe.core.exception;

public enum ErrorCode {

INTERNAL_SEVER_ERROR,
INVALIDATED_GRADUATION_CATEGORY,
UNFITTED_GRADUATION_CATEGORY,
UNREGISTERED_USER,
INVALIDATED_STUDENT_NUMBER_TYPE,
INVALIDATED_PASSWORD_TYPE,
MISMATCHED_PASSWORD,
NOT_FOUND_AUTHID,
INVALIDATED_AUTHID_TYPE,
INCORRECT_PASSWORD,
DUPLICATED_STUDENT_NUMBER,
DUPLICATED_AUTHID,
NOT_FOUND_STUDENT_NUMBER,
INVALIDATED_AUTH_TOKEN,
INCORRECT_STUDENT_NUMBER,
NON_EXISTED_LECTURE,
UNSUPPORTED_STUDENT_CATEGORY,
UNSUPPORTED_STUDENT_NUMBER,
AUTHENTICATION_FAIL_FORBIDDEN,
AUTHENTICATION_FAIL_UNAUTHORIZED
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
package com.plzgraduate.myongjigraduatebe.core.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public class ExceptionResponse {

private final int status;
private final String message;
private final String errorCode;

private ExceptionResponse(
int status,
String message
) {
this.status = status;
this.message = message;
private ExceptionResponse(String errorCode) {
this.errorCode = errorCode;
}

public static ExceptionResponse of(
HttpStatus httpStatus,
String message
) {
return new ExceptionResponse(httpStatus.value(), message);
public static ExceptionResponse from(String errorCode) {
return new ExceptionResponse(errorCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,62 +31,56 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionResponse handleBadRequestException(Exception e) {
log.debug("Bad request exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.BAD_REQUEST, getMessage(e));
return ExceptionResponse.from(e.getMessage());
}

@ExceptionHandler(NoSuchElementException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ExceptionResponse handleNotFoundException(Exception e) {
log.debug("Not Found exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.NOT_FOUND, getMessage(e));
return ExceptionResponse.from(e.getMessage());
}

@ExceptionHandler(UnAuthorizedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ExceptionResponse handleUnAuthorizedException(Exception e) {
log.debug("unauthorized exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.UNAUTHORIZED, getMessage(e));
return ExceptionResponse.from(e.getMessage());
}

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionResponse handleValidationException(ConstraintViolationException e) {
log.info("validated exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.BAD_REQUEST, getViolationErrorMessage(e));
return ExceptionResponse.from(getViolationErrorMessage(e));
}



@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.debug("validation exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.BAD_REQUEST, getBindingErrorMessage(e));
return ExceptionResponse.from(getBindingErrorMessage(e));
}

@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionResponse handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
log.debug("graduation category mismatch exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.BAD_REQUEST, getMethodArgumentTypeMismatchErrorMessage(e));
log.debug("graduation category mismatch exception occurred: {}", getMethodArgumentTypeMismatchErrorMessage(e));
return ExceptionResponse.from(ErrorCode.INVALIDATED_GRADUATION_CATEGORY.toString());
}

@ExceptionHandler({PdfParsingException.class, InvalidPdfException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExceptionResponse handlePdfException(Exception e) {
log.warn("pdf exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.BAD_REQUEST, getMessage(e));
return ExceptionResponse.from(e.getMessage());
}

@ExceptionHandler({RuntimeException.class, Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ExceptionResponse handleRuntimeException(RuntimeException e) {
log.error("Unexpected exception occurred: {}", e.getMessage(), e);
return ExceptionResponse.of(HttpStatus.INTERNAL_SERVER_ERROR, getMessage(e));
}

private String getMessage(Exception e) {
return Optional.ofNullable(e.getCause()).map(Throwable::getMessage).orElse(e.getMessage());
return ExceptionResponse.from(ErrorCode.INTERNAL_SEVER_ERROR.toString());
}

private String getViolationErrorMessage(ConstraintViolationException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class CalculateSingleDetailGraduationService implements CalculateSingleDe
@Override
public DetailGraduationResult calculateSingleDetailGraduation(Long userId, GraduationCategory graduationCategory) {
User user = findUserUseCase.findUserById(userId);
user.getStudentCategory().validateGraduationCategoryInclusion(graduationCategory);
TakenLectureInventory takenLectures = findTakenLectureUseCase.findTakenLectures(userId);
CalculateDetailGraduationUseCase calculateDetailGraduationUseCase = determineCalculateDetailGraduationUseCase(
graduationCategory);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.plzgraduate.myongjigraduatebe.parsing.application.service;

import static com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode.*;
import static com.plzgraduate.myongjigraduatebe.user.domain.model.StudentCategory.ASSOCIATED_MAJOR;
import static com.plzgraduate.myongjigraduatebe.user.domain.model.StudentCategory.DOUBLE_SUB;

Expand All @@ -9,6 +10,7 @@
import org.springframework.transaction.annotation.Transactional;

import com.plzgraduate.myongjigraduatebe.completedcredit.application.usecase.GenerateOrModifyCompletedCreditUseCase;
import com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode;
import com.plzgraduate.myongjigraduatebe.core.exception.InvalidPdfException;
import com.plzgraduate.myongjigraduatebe.core.exception.PdfParsingException;
import com.plzgraduate.myongjigraduatebe.core.meta.UseCase;
Expand Down Expand Up @@ -81,7 +83,7 @@

private void validateStudentNumber(User user, ParsingInformation parsingInformation) {
if (!user.compareStudentNumber(parsingInformation.getStudentNumber())) {
throw new InvalidPdfException("본인의 학번과 PDF 학번이 일치하지 않습니다.");
throw new InvalidPdfException(INCORRECT_STUDENT_NUMBER.toString());
}
}

Expand All @@ -100,7 +102,7 @@
private void checkUnSupportedUser(ParsingInformation parsingInformation) {
if (parsingInformation.getStudentCategory() == ASSOCIATED_MAJOR
|| parsingInformation.getStudentCategory() == DOUBLE_SUB) {
throw new IllegalArgumentException("연계전공, 복수+부전공은 참여가 어렵습니다. 빠른 시일 내에 업데이트하도록 하겠습니다.");
throw new IllegalArgumentException(ErrorCode.UNSUPPORTED_STUDENT_CATEGORY.toString());

Check warning on line 105 in src/main/java/com/plzgraduate/myongjigraduatebe/parsing/application/service/ParsingTextService.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/plzgraduate/myongjigraduatebe/parsing/application/service/ParsingTextService.java#L105

Added line #L105 was not covered by tests
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.springframework.transaction.annotation.Transactional;

import com.plzgraduate.myongjigraduatebe.core.exception.ErrorCode;
import com.plzgraduate.myongjigraduatebe.core.meta.UseCase;
import com.plzgraduate.myongjigraduatebe.lecture.application.usecase.FindLecturesUseCase;
import com.plzgraduate.myongjigraduatebe.lecture.domain.model.Lecture;
Expand All @@ -18,10 +19,12 @@
import com.plzgraduate.myongjigraduatebe.user.domain.model.User;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@UseCase
@Transactional
@RequiredArgsConstructor
@Slf4j
class SaveTakenLectureFromParsingTextService implements SaveTakenLectureFromParsingTextUseCase {

private final SaveTakenLecturePort saveTakenLecturePort;
Expand All @@ -38,18 +41,20 @@ private List<TakenLecture> makeTakenLectures(User user, List<TakenLectureInforma
Map<String, Lecture> lectureMap) {
return takenLectureInformationList.stream()
.map(takenLectureInformation -> {
Lecture lecture = getLectureFromLectureMap(lectureMap, takenLectureInformation);
return TakenLecture.of(user, lecture, takenLectureInformation.getYear(),
takenLectureInformation.getSemester());
}
).collect(Collectors.toList());
Lecture lecture = getLectureFromLectureMap(lectureMap, takenLectureInformation);
return TakenLecture.of(user, lecture, takenLectureInformation.getYear(),
takenLectureInformation.getSemester());
}
).collect(Collectors.toList());
}

private Lecture getLectureFromLectureMap(Map<String, Lecture> lectureMap,
TakenLectureInformation takenLectureInformation) {
return Optional.ofNullable(lectureMap.get(takenLectureInformation.getLectureCode()))
.orElseThrow(
() -> new IllegalArgumentException(takenLectureInformation.getLectureCode() + "이 데이터베이스에 존재하지 않습니다."));
.orElseThrow(() -> {
log.warn("Not Found Lecture in Database: {}", takenLectureInformation.getLectureCode());
return new IllegalArgumentException(ErrorCode.NON_EXISTED_LECTURE.toString());
});
}

private Map<String, Lecture> makeLectureMapByLectureCodes(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.plzgraduate.myongjigraduatebe.user.api.findauthid;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

import org.springframework.web.bind.annotation.PathVariable;

import com.plzgraduate.myongjigraduatebe.user.api.findauthid.dto.response.UserAuthIdResponse;
Expand All @@ -12,5 +15,5 @@
public interface FindAuthIdApiPresentation {

UserAuthIdResponse findUserAuthId(
@Parameter(name = "studentNumber", description = "학번", in = ParameterIn.PATH) @PathVariable String studentNumber);
@Parameter(name = "studentNumber", description = "학번", in = ParameterIn.PATH) @PathVariable @Pattern(regexp = "^60\\d{6}$", message = "INVALIDATED_STUDENT_NUMBER_TYPE") String studentNumber);
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
package com.plzgraduate.myongjigraduatebe.user.api.findauthid;

import javax.validation.constraints.Pattern;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.plzgraduate.myongjigraduatebe.core.meta.WebAdapter;
import com.plzgraduate.myongjigraduatebe.user.application.usecase.find.FindUserAuthIdUseCase;
import com.plzgraduate.myongjigraduatebe.user.api.findauthid.dto.response.UserAuthIdResponse;
import com.plzgraduate.myongjigraduatebe.user.application.usecase.find.FindUserAuthIdUseCase;

import lombok.RequiredArgsConstructor;

@WebAdapter
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Validated
public class FindAuthIdController implements FindAuthIdApiPresentation {

private final FindUserAuthIdUseCase findUserAuthIdUseCase;

@GetMapping("/{studentNumber}/auth-id")
public UserAuthIdResponse findUserAuthId(@PathVariable String studentNumber) {
public UserAuthIdResponse findUserAuthId(
@PathVariable @Pattern(regexp = "^60\\d{6}$", message = "INVALIDATED_STUDENT_NUMBER_TYPE") String studentNumber) {
String foundUserAuthId = findUserAuthIdUseCase.findUserAuthId(studentNumber);
return UserAuthIdResponse.of(foundUserAuthId, studentNumber);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.plzgraduate.myongjigraduatebe.user.api.resetpassword;

import javax.validation.Valid;
import javax.validation.constraints.Pattern;

import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -22,7 +23,7 @@ public interface ResetPasswordApiPresentation {
@Parameter(name = "auth-id", description = "아이디")
ValidateUserResponse validateUser(
@Parameter(name = "studentNumber", description = "학번", in = ParameterIn.PATH)
@PathVariable String studentNumber,
@PathVariable @Pattern(regexp = "^60\\d{6}$", message = "INVALIDATED_STUDENT_NUMBER_TYPE") String studentNumber,
@RequestParam("auth-id") String authId);

@PatchMapping("/password")
Expand Down
Loading
Loading