Skip to content

Commit

Permalink
Merge pull request #72 from team-crews/refactor/#70-validate-entity-f…
Browse files Browse the repository at this point in the history
…ield

커스텀 예외 메세지 보완, 엔티티 문자열 필드 검증 추가
  • Loading branch information
jongmee authored Sep 7, 2024
2 parents 643d1cf + 2d3f311 commit 2f1b9ed
Show file tree
Hide file tree
Showing 26 changed files with 310 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import com.server.crews.auth.domain.Applicant;
import com.server.crews.auth.repository.ApplicantRepository;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import com.server.crews.global.exception.NotFoundException;
import com.server.crews.recruitment.domain.Choice;
import com.server.crews.recruitment.domain.NarrativeQuestion;
import com.server.crews.recruitment.domain.Recruitment;
Expand Down Expand Up @@ -52,9 +53,9 @@ public class ApplicationService {
@Transactional
public ApplicationDetailsResponse saveApplication(Long applicantId, ApplicationSaveRequest request) {
Recruitment recruitment = recruitmentRepository.findByCode(request.recruitmentCode())
.orElseThrow(() -> new CrewsException(ErrorCode.RECRUITMENT_NOT_FOUND));
.orElseThrow(() -> new NotFoundException("모집 공고 코드", "모집 공고"));
Applicant applicant = applicantRepository.findById(applicantId)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));

validateNarrativeQuestions(request);
validateSelectiveQuestions(request);
Expand Down Expand Up @@ -85,7 +86,7 @@ private void validateSelectiveQuestions(ApplicationSaveRequest request) {
.collect(toSet());
List<Choice> savedChoices = choiceRepository.findAllByIdIn(choiceIds);
if (savedChoices.size() != choiceIds.size()) {
throw new CrewsException(ErrorCode.CHOICE_NOT_FOUND);
throw new NotFoundException("선택지 id", "선택지");
}
}

Expand All @@ -104,7 +105,7 @@ private Set<Long> extractQuestionIds(List<AnswerSaveRequest> answerSaveRequests)

private void validateQuestionIds(List<?> savedQuestions, Set<Long> questionIds) {
if (savedQuestions.size() != questionIds.size()) {
throw new CrewsException(ErrorCode.QUESTION_NOT_FOUND);
throw new NotFoundException("질문 id", "질문");
}
}

Expand All @@ -117,7 +118,7 @@ public List<ApplicationsResponse> findAllApplicationsByPublisher(Long publisherI

public ApplicationDetailsResponse findApplicationDetails(Long applicationId, Long publisherId) {
Application application = applicationRepository.findByIdWithRecruitmentAndPublisher(applicationId)
.orElseThrow(() -> new CrewsException(ErrorCode.APPLICATION_NOT_FOUND));
.orElseThrow(() -> new NotFoundException("지원서 id", "지원서"));
checkPermission(application, publisherId);
List<NarrativeAnswer> narrativeAnswers = narrativeAnswerRepository.findAllByApplication(application);
List<SelectiveAnswer> selectiveAnswers = selectiveAnswerRepository.findAllByApplication(application);
Expand All @@ -128,7 +129,7 @@ public ApplicationDetailsResponse findApplicationDetails(Long applicationId, Lon

private void checkPermission(Application application, Long publisherId) {
if (!application.canBeAccessedBy(publisherId)) {
throw new CrewsException(ErrorCode.UNAUTHORIZED_USER);
throw new CrewsException(GeneralErrorCode.UNAUTHORIZED_USER);
}
}

Expand Down Expand Up @@ -163,7 +164,7 @@ public void decideOutcome(EvaluationRequest request, Long publisherId) {

private void checkRecruitmentAnnouncedProgress(Recruitment recruitment) {
if (recruitment.isAnnounced()) {
throw new CrewsException(ErrorCode.ALREADY_ANNOUNCED);
throw new CrewsException(GeneralErrorCode.ALREADY_ANNOUNCED);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -34,7 +35,8 @@ public class NarrativeAnswer {
@ManyToOne(fetch = FetchType.LAZY)
private NarrativeQuestion narrativeQuestion;

@Column(name = "content", nullable = false)
@Size(max = 1500, message = "서술형 답안 내용은 1500자 이하입니다.")
@Column(name = "content", nullable = false, length = 1500)
private String content;

public NarrativeAnswer(Long id, NarrativeQuestion narrativeQuestion, String content) {
Expand Down
16 changes: 8 additions & 8 deletions src/main/java/com/server/crews/auth/application/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.server.crews.auth.repository.AdministratorRepository;
import com.server.crews.auth.repository.ApplicantRepository;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -71,7 +71,7 @@ private Applicant createApplicant(String email, String password) {

private void validatePassword(String password, String encodedPassword) {
if (!passwordEncoder.matches(password, encodedPassword)) {
throw new CrewsException(ErrorCode.WRONG_PASSWORD);
throw new CrewsException(GeneralErrorCode.WRONG_PASSWORD);
}
}

Expand All @@ -80,14 +80,14 @@ public LoginUser findAdminAuthentication(String accessToken) {
validateAdminAuthorization(accessToken);
String clubName = jwtTokenProvider.getPayload(accessToken);
Administrator administrator = administratorRepository.findByClubName(clubName)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
return new LoginUser(administrator.getId(), Role.ADMIN);
}

private void validateAdminAuthorization(String accessToken) {
Role role = jwtTokenProvider.getRole(accessToken);
if (role != Role.ADMIN) {
throw new CrewsException(ErrorCode.UNAUTHORIZED_USER);
throw new CrewsException(GeneralErrorCode.UNAUTHORIZED_USER);
}
}

Expand All @@ -96,14 +96,14 @@ public LoginUser findApplicantAuthentication(String accessToken) {
validateApplicantAuthorization(accessToken);
String email = jwtTokenProvider.getPayload(accessToken);
Applicant applicant = applicantRepository.findByEmail(email)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
return new LoginUser(applicant.getId(), Role.APPLICANT);
}

private void validateApplicantAuthorization(String accessToken) {
Role role = jwtTokenProvider.getRole(accessToken);
if (role != Role.APPLICANT) {
throw new CrewsException(ErrorCode.UNAUTHORIZED_USER);
throw new CrewsException(GeneralErrorCode.UNAUTHORIZED_USER);
}
}

Expand All @@ -113,11 +113,11 @@ public LoginUser findAuthentication(String accessToken) {
String payload = jwtTokenProvider.getPayload(accessToken);
if (role == Role.APPLICANT) {
Applicant applicant = applicantRepository.findByEmail(payload)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
return new LoginUser(applicant.getId(), Role.APPLICANT);
}
Administrator administrator = administratorRepository.findByClubName(payload)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
return new LoginUser(administrator.getId(), Role.ADMIN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import com.server.crews.auth.domain.Role;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
Expand Down Expand Up @@ -84,13 +84,13 @@ public Role getRole(String token) {

public void validateAccessToken(String token) {
if (!validateToken(token).equals(ACCESS_TOKEN_ALGORITHM)) {
throw new CrewsException(ErrorCode.INVALID_ACCESS_TOKEN);
throw new CrewsException(GeneralErrorCode.INVALID_ACCESS_TOKEN);
}
}

public void validateRefreshToken(String token) {
if (!validateToken(token).equals(REFRESH_TOKEN_ALGORITHM)) {
throw new CrewsException(ErrorCode.INVALID_REFRESH_TOKEN);
throw new CrewsException(GeneralErrorCode.INVALID_REFRESH_TOKEN);
}
}

Expand All @@ -104,13 +104,13 @@ private SignatureAlgorithm validateToken(String token) {
.getAlgorithm();
return SignatureAlgorithm.forName(algorithm);
} catch (MalformedJwtException e) {
throw new CrewsException(ErrorCode.MALFORMED_JWT);
throw new CrewsException(GeneralErrorCode.MALFORMED_JWT);
} catch (ExpiredJwtException e) {
throw new CrewsException(ErrorCode.EXPIRED_JWT);
throw new CrewsException(GeneralErrorCode.EXPIRED_JWT);
} catch (UnsupportedJwtException e) {
throw new CrewsException(ErrorCode.UNSUPPORTED_JWT);
throw new CrewsException(GeneralErrorCode.UNSUPPORTED_JWT);
} catch (IllegalArgumentException e) {
throw new CrewsException(ErrorCode.INVALID_JWT);
throw new CrewsException(GeneralErrorCode.INVALID_JWT);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import com.server.crews.auth.repository.ApplicantRepository;
import com.server.crews.auth.repository.RefreshTokenRepository;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -34,9 +34,9 @@ public TokenRefreshResponse renew(String refreshToken) {
jwtTokenProvider.validateRefreshToken(refreshToken);
String username = jwtTokenProvider.getPayload(refreshToken);
RefreshToken savedRefreshToken = refreshTokenRepository.findByUsername(username)
.orElseThrow(() -> new CrewsException(ErrorCode.REFRESH_TOKEN_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.REFRESH_TOKEN_NOT_FOUND));
if (!savedRefreshToken.isSameToken(refreshToken)) {
throw new CrewsException(ErrorCode.INVALID_REFRESH_TOKEN);
throw new CrewsException(GeneralErrorCode.INVALID_REFRESH_TOKEN);
}

Role role = jwtTokenProvider.getRole(refreshToken);
Expand All @@ -47,12 +47,12 @@ public TokenRefreshResponse renew(String refreshToken) {
public void delete(Long userId, Role role) {
if (role == Role.ADMIN) {
Administrator administrator = administratorRepository.findById(userId)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
refreshTokenRepository.deleteByUsername(administrator.getClubName());
return;
}
Applicant applicant = applicantRepository.findById(userId)
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
.orElseThrow(() -> new CrewsException(GeneralErrorCode.USER_NOT_FOUND));
refreshTokenRepository.deleteByUsername(applicant.getEmail());
}
}
6 changes: 4 additions & 2 deletions src/main/java/com/server/crews/auth/domain/Administrator.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -20,10 +21,11 @@ public class Administrator {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "club_name", nullable = false, unique = true)
@Size(max = 30, message = "동아리 이름은 30자 이하입니다.")
@Column(name = "club_name", nullable = false, unique = true, length = 30)
private String clubName;

@Column(name = "password", nullable = false)
@Column(name = "password", nullable = false, length = 100)
private String password;

public Administrator(String clubName, String password) {
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/com/server/crews/auth/domain/Applicant.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.server.crews.auth.domain;

import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.Getter;
Expand All @@ -24,10 +25,11 @@ public class Applicant {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "email", nullable = false, unique = true)
@Size(max = 30, message = "이메일은 30자 이하입니다.")
@Column(name = "email", nullable = false, unique = true, length = 30)
private String email;

@Column(name = "password", nullable = false)
@Column(name = "password", nullable = false, length = 100)
private String password;

public Applicant(String email, String password) {
Expand All @@ -38,7 +40,7 @@ public Applicant(String email, String password) {

private void validateEmail(String email) {
if (!Pattern.matches(EMAIL_PATTERN, email)) {
throw new CrewsException(ErrorCode.INVALID_EMAIL_PATTERN);
throw new CrewsException(GeneralErrorCode.INVALID_EMAIL_PATTERN);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.server.crews.auth.presentation;

import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import com.server.crews.global.exception.GeneralErrorCode;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;
import org.springframework.http.HttpHeaders;
Expand All @@ -12,7 +12,7 @@ public class AuthorizationExtractor {
public static String extract(final HttpServletRequest request) {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (Objects.isNull(authorizationHeader)) {
throw new CrewsException(ErrorCode.NO_TOKEN);
throw new CrewsException(GeneralErrorCode.NO_TOKEN);
}

validateAuthorizationFormat(authorizationHeader);
Expand All @@ -21,7 +21,7 @@ public static String extract(final HttpServletRequest request) {

private static void validateAuthorizationFormat(final String authorizationHeader) {
if (!authorizationHeader.toLowerCase().startsWith(BEARER_TYPE.toLowerCase())) {
throw new CrewsException(ErrorCode.INVALID_TOKEN);
throw new CrewsException(GeneralErrorCode.INVALID_TOKEN);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ public class CrewsException extends RuntimeException {
private final HttpStatus httpStatus;
private final String message;

public CrewsException(final ErrorCode errorCode) {
super(errorCode.getMessage());
this.httpStatus = errorCode.getHttpStatus();
this.message = errorCode.getMessage();
public CrewsException(GeneralErrorCode generalErrorCode) {
this(generalErrorCode.getHttpStatus(), generalErrorCode.getMessage());
}

public CrewsException(final String errorMessage) {
super(errorMessage);
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
this.message = errorMessage;
public CrewsException(HttpStatus httpStatus, String message) {
super(message);
this.httpStatus = httpStatus;
this.message = message;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@Getter
@AllArgsConstructor
public enum ErrorCode {
public enum GeneralErrorCode {
DUPLICATE_SECRET_CODE(HttpStatus.BAD_REQUEST, "중복된 코드입니다."),
NO_PARAMETER(HttpStatus.BAD_REQUEST, "%s 파라미터가 없습니다."),
INVALID_EMAIL_PATTERN(HttpStatus.BAD_REQUEST, "유효하지 않은 이메일 형식입니다."),
Expand All @@ -15,6 +15,7 @@ public enum ErrorCode {
RECRUITMENT_ALREADY_STARTED(HttpStatus.BAD_REQUEST, "모집이 이미 시작되었습니다."),
RECRUITMENT_NOT_STARTED(HttpStatus.BAD_REQUEST, "모집이 시작되지 않았습니다."),
INVALID_MODIFIED_DEADLINE(HttpStatus.BAD_REQUEST, "수정된 모집 마감 기한은 기존 기한 이후이며 모집 진행 중에만 수정할 수 있습니다."),
INVALID_SELECTION_COUNT(HttpStatus.BAD_REQUEST, "선택형 문항의 최대 선택 개수는 최소 선택 개수보다 크거나 같습니다."),

NO_TOKEN(HttpStatus.UNAUTHORIZED, "토큰이 존재하지 않습니다."),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "토큰 형식이 잘못 되었습니다."),
Expand All @@ -27,12 +28,7 @@ public enum ErrorCode {
USER_NOT_FOUND(HttpStatus.UNAUTHORIZED, "존재하지 않는 사용자입니다."),
UNAUTHORIZED_USER(HttpStatus.UNAUTHORIZED, "권한이 없는 사용자입니다."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "존재하지 않는 리프레시 토큰입니다."),
WRONG_PASSWORD(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다."),

RECRUITMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 모집 지원서 양식입니다."),
APPLICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 지원서입니다."),
QUESTION_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 문항입니다."),
CHOICE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 선택지입니다.");
WRONG_PASSWORD(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Loading

0 comments on commit 2f1b9ed

Please sign in to comment.