Skip to content

Commit

Permalink
[BE] 회원가입 시 필요한 로직을 추가한다. (#856)
Browse files Browse the repository at this point in the history
  • Loading branch information
shin-jisong authored Oct 23, 2024
1 parent 662888a commit 585b16b
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
Expand All @@ -39,40 +38,60 @@ public class AuthService {

@Transactional
public Long register(RegisterRequestV1 request) {
try {
return userRepository.save(request.toUserEntity()).getId();
} catch (DataIntegrityViolationException e) {
throw new BangggoodException(ExceptionCode.USER_EMAIL_ALREADY_USED);
}
User user = processUser(LoginType.LOCAL, request.toUserEntity(), true);
return user.getId();
}

@Transactional
public void withdraw(User user) {
userRepository.deleteById(user.getId());
public AuthTokenResponse oauthLogin(OauthLoginRequest request) {
OauthInfoApiResponse oauthInfo = oauthClient.requestOauthInfo(request);
User user = processUser(LoginType.KAKAO, oauthInfo.toUserEntity(), false);
return createAuthTokenResponse(user);
}

@Transactional
public AuthTokenResponse oauthLogin(OauthLoginRequest request) {
OauthInfoApiResponse oauthInfoApiResponse = oauthClient.requestOauthInfo(request);
private User processUser(LoginType loginType, User user, boolean isRegistration) {
return userRepository.findByEmailAndLoginTypeWithDeleted(user.getEmail(), loginType)
.map(savedUser -> handleExistingUser(savedUser, loginType, isRegistration))
.orElseGet(() -> signUp(user));
}

private User handleExistingUser(User user, LoginType loginType, boolean isRegistrationRequest) {
validateRegister(user, isRegistrationRequest);
restoreUser(user, loginType);
return user;
}

User user = userRepository.findByEmailAndLoginType(new Email(oauthInfoApiResponse.kakao_account().email()),
LoginType.KAKAO)
.orElseGet(() -> signUp(oauthInfoApiResponse));
private void validateRegister(User user, boolean isRegistrationRequest) {
if (!user.isDeleted() && isRegistrationRequest) {
throw new BangggoodException(ExceptionCode.USER_EMAIL_ALREADY_USED);
}
}

private void restoreUser(User user, LoginType loginType) {
if (user.isDeleted()) {
userRepository.resaveByEmailAndLoginType(user.getEmail(), loginType);
}
}

private AuthTokenResponse createAuthTokenResponse(User user) {
String accessToken = jwtTokenProvider.createAccessToken(user);
String refreshToken = jwtTokenProvider.createRefreshToken(user);
return AuthTokenResponse.of(accessToken, refreshToken);
}


@Transactional
public void withdraw(User user) {
userRepository.deleteById(user.getId());
}

@Transactional(readOnly = true)
public AuthTokenResponse localLogin(LocalLoginRequestV1 request) {
User user = userRepository.findByEmailAndLoginType(new Email(request.email()), LoginType.LOCAL)
.orElseThrow(() -> new BangggoodException(ExceptionCode.USER_NOT_FOUND));
checkPassword(request, user);

String accessToken = jwtTokenProvider.createAccessToken(user);
String refreshToken = jwtTokenProvider.createRefreshToken(user);
return AuthTokenResponse.of(accessToken, refreshToken);
return createAuthTokenResponse(user);
}


Expand All @@ -82,10 +101,10 @@ private void checkPassword(LocalLoginRequestV1 request, User user) {
}
}

private User signUp(OauthInfoApiResponse oauthInfoApiResponse) {
User user = userRepository.save(oauthInfoApiResponse.toUserEntity());
defaultChecklistService.createDefaultChecklistAndQuestions(user);
return user;
private User signUp(User user) {
User savedUser = userRepository.save(user);
defaultChecklistService.createDefaultChecklistAndQuestions(savedUser);
return savedUser;
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,11 @@ default User getUserById(Long id) {
@Query("UPDATE User u SET u.deleted = true WHERE u.id = :id")
void deleteById(@Param("id") Long id);

@Transactional
@Modifying(flushAutomatically = true, clearAutomatically = true)
@Query("UPDATE User u SET u.deleted = false WHERE u.email = :email AND u.loginType = :loginType")
void resaveByEmailAndLoginType(@Param("email") Email email, @Param("loginType") LoginType loginType);

@Query("SELECT u FROM User u WHERE u.email = :email and u.loginType = :loginType")
Optional<User> findByEmailAndLoginTypeWithDeleted(Email email, LoginType loginType);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bang_ggood.auth.service;

import com.bang_ggood.IntegrationTestSupport;
import com.bang_ggood.auth.dto.request.LocalLoginRequestV1;
import com.bang_ggood.auth.dto.request.OauthLoginRequest;
import com.bang_ggood.auth.dto.request.RegisterRequestV1;
import com.bang_ggood.auth.dto.response.AuthTokenResponse;
Expand Down Expand Up @@ -36,6 +37,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.ArgumentMatchers.any;

@ExtendWith(MockitoExtension.class)
Expand All @@ -61,8 +63,10 @@ void localLogin() {
AuthTokenResponse response = authService.localLogin(LOCAL_LOGIN_REQUEST);

// then
assertThat(response.accessToken()).isNotBlank();
assertThat(response.refreshToken()).isNotBlank();
assertAll(
() -> assertThat(response.accessToken()).isNotBlank(),
() -> assertThat(response.refreshToken()).isNotBlank()
);
}

@DisplayName("로컬 로그인 실패: 일치하는 유저가 없는 경우")
Expand All @@ -83,9 +87,9 @@ void localLogin_userInvalidPassword() {
.hasMessage(ExceptionCode.USER_INVALID_PASSWORD.getMessage());
}

@DisplayName("회원가입 성공")
@DisplayName("회원가입 성공 : 회원가입 이력 없는 회원인 경우")
@Test
void register() {
void register_newUser() {
//given
RegisterRequestV1 request = new RegisterRequestV1("방방이", "[email protected]", "password1234");

Expand All @@ -97,6 +101,62 @@ void register() {
assertThat(findUser.getId()).isEqualTo(userId);
}

@DisplayName("회원가입 성공 : 탈퇴한 회원인 경우")
@Test
void register_deletedUser() {
// given
RegisterRequestV1 request = new RegisterRequestV1("방방이", "[email protected]", "password1234");
User existingUser = userRepository.save(request.toUserEntity());
userRepository.deleteById(existingUser.getId());

// when
Long userId = authService.register(request);

// then
User findUser = userRepository.findById(userId).orElseThrow();
assertThat(findUser.getId()).isEqualTo(userId);
}

@DisplayName("회원 가입 성공 : 회원 가입 시 디폴트 체크리스트 질문을 추가")
@Test
void register_default_checklist_question() {
// given
RegisterRequestV1 request = new RegisterRequestV1("방방이", "[email protected]", "password1234");
authService.register(request);

// when
AuthTokenResponse token = authService.localLogin(new LocalLoginRequestV1("[email protected]", "password1234"));

// then
User user = authService.getAuthUser(token.accessToken());
CustomChecklistQuestionsResponse customChecklistQuestions = questionManageService.readCustomChecklistQuestions(
user);

int sum = 0;
for (CategoryQuestionsResponse response : customChecklistQuestions.categories()) {
sum += response.questions().size();
}

assertThat(sum).isEqualTo(Question.findDefaultQuestions().size());
}

@DisplayName("회원 가입 성공 : 회원 가입시 디폴트 체크리스트를 추가")
@Test
void register_default_checklist() {
// given
RegisterRequestV1 request = new RegisterRequestV1("방방이", "[email protected]", "password1234");
Long userId = authService.register(request);

// when
AuthTokenResponse token = authService.localLogin(new LocalLoginRequestV1("[email protected]", "password1234"));

// then
User user = authService.getAuthUser(token.accessToken());
ChecklistsPreviewResponse response = checklistManageService.readAllChecklistsPreview(user);
assertThat(response.checklists()).hasSize(1);
}


@DisplayName("회원가입 성공 : 비밀번호 암호화")
@Test
void register_encodePassword() {
Expand Down Expand Up @@ -147,7 +207,7 @@ void withdraw() {
assertThat(findUser).isEmpty();
}

@DisplayName("카카오 로그인 성공 : 존재하지 않는 회원이면 데이터베이스에 새로운 유저를 추가하고 토큰 반환")
@DisplayName("카카오 로그인 성공 : 존재하지 않는 회원이면 회원 가입 후 로그인")
@Test
void oauthLogin_signup() {
// given
Expand All @@ -158,11 +218,13 @@ void oauthLogin_signup() {
AuthTokenResponse token = authService.oauthLogin(OAUTH_LOGIN_REQUEST);

// then
assertThat(token.accessToken()).isNotBlank();
assertThat(token.refreshToken()).isNotBlank();
assertAll(
() -> assertThat(token.accessToken()).isNotBlank(),
() -> assertThat(token.refreshToken()).isNotBlank()
);
}

@DisplayName("카카오 로그인 성공 : 존재하는 회원이면 데이터베이스에 새로운 유저를 추가하지 않고 토큰을 바로 반환")
@DisplayName("카카오 로그인 성공 : 존재하는 회원이면 로그인")
@Test
void oauthLogin() {
// given
Expand All @@ -174,8 +236,29 @@ void oauthLogin() {
AuthTokenResponse token = authService.oauthLogin(OAUTH_LOGIN_REQUEST);

// then
assertThat(token.accessToken()).isNotBlank();
assertThat(token.refreshToken()).isNotBlank();
assertAll(
() -> assertThat(token.accessToken()).isNotBlank(),
() -> assertThat(token.refreshToken()).isNotBlank()
);
}

@DisplayName("카카오 로그인 성공 : 탈퇴한 회원이면 재가입")
@Test
void oauthLogin_withdrawUser() {
// given
User user = userRepository.save(UserFixture.USER1());
userRepository.deleteById(user.getId());
Mockito.when(oauthClient.requestOauthInfo(any(OauthLoginRequest.class)))
.thenReturn(UserFixture.OAUTH_INFO_RESPONSE_USER1());

// when
AuthTokenResponse token = authService.oauthLogin(OAUTH_LOGIN_REQUEST);

// then
assertAll(
() -> assertThat(token.accessToken()).isNotBlank(),
() -> assertThat(token.refreshToken()).isNotBlank()
);
}

@DisplayName("카카오 로그인 성공 : 회원 가입시 디폴트 체크리스트 질문을 추가")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

class UserRepositoryTest extends IntegrationTestSupport {

@Autowired
Expand All @@ -27,7 +31,7 @@ void findByEmail() {
Optional<User> findUser = userRepository.findByEmailAndLoginType(user.getEmail(), user.getLoginType());

// then
Assertions.assertThat(findUser).isEmpty();
assertThat(findUser).isEmpty();
}

@DisplayName("유저 타입으로 조회 성공")
Expand All @@ -40,7 +44,7 @@ void findByType() {
List<User> users = userRepository.findUserByUserType(UserType.GUEST);

// then
Assertions.assertThat(users).containsExactly(expectedUser);
assertThat(users).containsExactly(expectedUser);
}

@DisplayName("논리적 삭제 성공")
Expand All @@ -54,6 +58,41 @@ void deleteById() {

// then
Optional<User> findUser = userRepository.findById(user.getId());
Assertions.assertThat(findUser).isEmpty();
assertThat(findUser).isEmpty();
}

@DisplayName("이메일과 로그인 타입으로 재저장 성공")
@Test
void resaveByEmailAndLoginType() {
// given
User user = userRepository.save(UserFixture.USER1());
userRepository.deleteById(user.getId());

// when
userRepository.resaveByEmailAndLoginType(user.getEmail(), user.getLoginType());

// then
Optional<User> deletedUser = userRepository.findByEmailAndLoginType(user.getEmail(), user.getLoginType());
assertAll(
() -> assertThat(deletedUser).isPresent(),
() -> assertThat(deletedUser.get().isDeleted()).isFalse()
);
}

@DisplayName("논리적 삭제된 유저를 포함해 이메일과 로그인 타입으로 조회 성공")
@Test
void findByEmailAndLoginTypeWithDeleted() {
// given
User user = userRepository.save(UserFixture.USER1());
userRepository.deleteById(user.getId());

// when
Optional<User> deletedUser = userRepository.findByEmailAndLoginTypeWithDeleted(user.getEmail(), user.getLoginType());

// then
assertAll(
() -> assertThat(deletedUser).isPresent(),
() -> assertThat(deletedUser.get().isDeleted()).isTrue()
);
}
}

0 comments on commit 585b16b

Please sign in to comment.