Skip to content
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 @@ -41,6 +41,7 @@ public CreateApplicationResponse apply(Long userId, ApplicationRequest request)

Set<Subject> subjects = request.getSubjects();

validator.ExamDateNotPassed(examIds);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider calling the validator method with a lowercase starting letter to adhere to Java naming conventions.

Suggested change
validator.ExamDateNotPassed(examIds);
validator.examDateNotPassed(examIds);

validator.RequestNoDuplicateExams(examIds);
validator.ExamIdsAndLunchSelection(request.examApplication());
validator.NoDuplicateApplication(userId, examIds);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package life.mosu.mosuserver.application.application.vaildator;

import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -66,4 +67,14 @@ public void NoDuplicateApplication(Long userId, List<Long> examIds) {
throw new CustomRuntimeException(ErrorCode.APPLICATION_SCHOOL_DUPLICATED);
}
}

public void ExamDateNotPassed(List<Long> examIds) {
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now()));

if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}
Comment on lines +71 to +79

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to Java naming conventions, method names should start with a lowercase letter and be in camelCase. Please rename ExamDateNotPassed to examDateNotPassed to follow this convention.

Suggested change
public void ExamDateNotPassed(List<Long> examIds) {
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now()));
if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}
public void examDateNotPassed(List<Long> examIds) {
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now()));
if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public LoginCommandResponse login(final LoginRequest request) {
Boolean isProfileRegistered = profileJpaRepository.existsByUserId(user.getId());

return LoginCommandResponse.of(authTokenManager.generateAuthToken(user),
isProfileRegistered);
isProfileRegistered, user);
} catch (final Exception e) {
throw new CustomRuntimeException(ErrorCode.INCORRECT_ID_OR_PASSWORD);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,14 @@ public class UserJpaEntity extends BaseTimeEntity {

@Builder
public UserJpaEntity(String loginId, String password, Gender gender, String name,
String phoneNumber,
LocalDate birth, boolean agreedToTermsOfService, boolean agreedToPrivacyPolicy,
boolean agreedToMarketing, UserRole userRole, AuthProvider provider) {
this.loginId = loginId;
this.password = password;
this.gender = gender;
this.name = name;
this.phoneNumber = phoneNumber;
this.birth = birth;
this.customerKey = generateUUIDCustomerKey();
this.agreedToTermsOfService = agreedToTermsOfService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public enum ErrorCode {

// 시험 관련 에러
EXAM_NOT_FOUND(HttpStatus.NOT_FOUND, "시험 정보를 찾을 수 없습니다."),
EXAM_DATE_PASSED(HttpStatus.BAD_REQUEST, "이미 지난 시험입니다."),

//lunch 관련
LUNCH_NOT_FOUND(HttpStatus.NOT_FOUND, "점심 정보를 찾을 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void onAuthenticationSuccess(
response.addHeader(HttpHeaders.SET_COOKIE, accessTokenCookie.toString());
response.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());

LoginResponse loginResponse = LoginResponse.from(oAuthUser.getIsProfileRegistered());
LoginResponse loginResponse = LoginResponse.from(oAuthUser);
String jsonResponse = objectMapper.writeValueAsString(loginResponse);

response.setStatus(HttpServletResponse.SC_OK);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package life.mosu.mosuserver.global.util;

import lombok.NoArgsConstructor;
import org.springframework.http.ResponseCookie;

@NoArgsConstructor
public class CookieBuilderUtil {

private CookieBuilderUtil() {
throw new UnsupportedOperationException("Utility class cannot be instantiated");
}

public static String createCookie(String name, String value, Long maxAge) {
return ResponseCookie.from(name, value)
.httpOnly(true)
Expand All @@ -16,4 +18,24 @@ public static String createCookie(String name, String value, Long maxAge) {
.toString();
}

public static String createCookie(String name, String value) {
return ResponseCookie.from(name, value)
.httpOnly(true)
.secure(false)
.path("/")
.build()
.toString();
}

public static String temporaryCookie(String name, String value, Long maxAge) {
return ResponseCookie.from(name, value)
.httpOnly(true)
.secure(true)
.path("/")
.domain(".mosuedu.com")
.sameSite("None")
.maxAge(maxAge)
.build()
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.validation.Valid;
import life.mosu.mosuserver.application.auth.AuthService;
import life.mosu.mosuserver.global.util.ApiResponseWrapper;
import life.mosu.mosuserver.global.util.CookieBuilderUtil;
import life.mosu.mosuserver.presentation.admin.annotation.RefreshTokenHeader;
import life.mosu.mosuserver.presentation.auth.dto.LoginCommandResponse;
import life.mosu.mosuserver.presentation.auth.dto.LoginRequest;
Expand All @@ -11,7 +12,6 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -23,6 +23,8 @@
@RequestMapping("/auth")
public class AuthController implements AuthControllerDocs {

private static final String ACCESS_TOKEN_COOKIE_NAME = "accessToken";
private static final String REFRESH_TOKEN_COOKIE_NAME = "refreshToken";
private final AuthService authService;

/**
Expand All @@ -36,34 +38,13 @@ public ResponseEntity<ApiResponseWrapper<LoginResponse>> login(
@RequestBody @Valid final LoginRequest request) {
final LoginCommandResponse command = authService.login(request);

final ResponseCookie accessTokenCookie = ResponseCookie.from("accessToken",
command.token().accessToken())
.httpOnly(true)
.secure(true)
.path("/")
.domain(".mosuedu.com")
.sameSite("None")
.maxAge(command.token().accessTokenExpireTime())
.build();

final ResponseCookie refreshTokenCookie = ResponseCookie.from("refreshToken",
command.token().refreshToken())
.httpOnly(true)
.secure(true)
.path("/")
.domain(".mosuedu.com")
.sameSite("None")
.maxAge(command.token().refreshTokenExpireTime())
.build();

return ResponseEntity.status(HttpStatus.CREATED)
.header(HttpHeaders.SET_COOKIE, accessTokenCookie.toString())
.header(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString())
.headers(applyTokenHeader(command.token()))
.body(ApiResponseWrapper.success(HttpStatus.CREATED,
LoginResponse.from(command.isProfileRegistered())));
LoginResponse.from(command.isProfileRegistered(), command.user())
));
}


@PostMapping("/reissue")
public ResponseEntity<ApiResponseWrapper<Token>> reissueAccessToken(
@RefreshTokenHeader final String refreshTokenHeader) {
Expand All @@ -73,4 +54,20 @@ public ResponseEntity<ApiResponseWrapper<Token>> reissueAccessToken(
.header(HttpHeaders.AUTHORIZATION, authorization)
.body(ApiResponseWrapper.success(HttpStatus.CREATED, token));
}

private HttpHeaders applyTokenHeader(Token token) {
HttpHeaders headers = new HttpHeaders();

headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.temporaryCookie(
ACCESS_TOKEN_COOKIE_NAME,
token.accessToken(),
token.accessTokenExpireTime()
));
headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.temporaryCookie(
REFRESH_TOKEN_COOKIE_NAME,
token.refreshToken(),
token.refreshTokenExpireTime()
));
return headers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ private HttpHeaders applyTokenHeader(Token token) {
HttpHeaders headers = new HttpHeaders(

);
headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.createCookie(
headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.temporaryCookie(
ACCESS_TOKEN_COOKIE_NAME,
token.accessToken(),
token.accessTokenExpireTime()
));
headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.createCookie(
headers.add(HttpHeaders.SET_COOKIE, CookieBuilderUtil.temporaryCookie(
REFRESH_TOKEN_COOKIE_NAME,
token.refreshToken(),
token.refreshTokenExpireTime()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package life.mosu.mosuserver.presentation.auth.dto;

import life.mosu.mosuserver.domain.user.UserJpaEntity;

public record LoginCommandResponse(
Token token,
Boolean isProfileRegistered
Boolean isProfileRegistered,
UserJpaEntity user
) {

public static LoginCommandResponse of(final Token token, final Boolean isProfileRegistered) {
return new LoginCommandResponse(token, isProfileRegistered);
public static LoginCommandResponse of(final Token token, final Boolean isProfileRegistered,
final UserJpaEntity user) {
return new LoginCommandResponse(token, isProfileRegistered, user);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package life.mosu.mosuserver.presentation.auth.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import life.mosu.mosuserver.application.oauth.OAuthUser;
import life.mosu.mosuserver.domain.user.UserJpaEntity;

public record LoginResponse(
Boolean isProfileRegistered
Boolean isProfileRegistered,
@JsonInclude(Include.NON_NULL) LoginUserResponse oauthUser
) {

public static LoginResponse from(final Boolean isProfileRegistered) {
return new LoginResponse(isProfileRegistered);
public static LoginResponse from(final OAuthUser user) {
return from(user.getIsProfileRegistered(), user.getUser());
}

public static LoginResponse from(Boolean isProfileRegistered, final UserJpaEntity user) {
if (Boolean.TRUE.equals(isProfileRegistered)) {
return new LoginResponse(true, null);
}
return new LoginResponse(false, LoginUserResponse.from(user));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package life.mosu.mosuserver.presentation.auth.dto;

import java.time.LocalDate;
import java.util.Optional;
import life.mosu.mosuserver.domain.user.UserJpaEntity;

public record LoginUserResponse(
String gender,
String name,
LocalDate birth,
String phoneNumber
) {

public static LoginUserResponse from(UserJpaEntity user) {
return Optional.ofNullable(user)
.map(userEntity -> {
String gender = Optional.ofNullable(userEntity.getGender())
.map(Enum::name)
.orElse(null);

return new LoginUserResponse(
gender,
userEntity.getName(),
userEntity.getBirth(),
userEntity.getPhoneNumber()
);
})
.orElse(null);
}
Comment on lines +14 to +29

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of nested Optional makes this factory method more complex than necessary and can be difficult to read. A simple null check would be more straightforward and achieve the same result with better readability.

    public static LoginUserResponse from(UserJpaEntity user) {
        if (user == null) {
            return null;
        }

        String gender = (user.getGender() != null) ? user.getGender().name() : null;

        return new LoginUserResponse(
                gender,
                user.getName(),
                user.getBirth(),
                user.getPhoneNumber()
        );
    }

}
Loading