Skip to content

Commit

Permalink
[MERGE] feat/#23 -> dev
Browse files Browse the repository at this point in the history
[FEAT/#23] 소셜 계정 변경하기 API 구현
  • Loading branch information
yummygyudon authored Dec 7, 2024
2 parents 7b9a101 + a8cf5a2 commit 364508a
Show file tree
Hide file tree
Showing 20 changed files with 232 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package sopt.makers.authentication.application.auth.api;

import static sopt.makers.authentication.support.code.domain.success.AuthSuccess.AUTHENTICATE_SOCIAL_ACCOUNT;

import sopt.makers.authentication.application.auth.dto.request.AuthRequest;
import sopt.makers.authentication.application.auth.dto.response.AuthResponse;
import sopt.makers.authentication.support.code.domain.success.AuthSuccess;
import sopt.makers.authentication.support.common.api.BaseResponse;
import sopt.makers.authentication.support.util.CookieUtil;
import sopt.makers.authentication.support.util.ResponseUtil;
import sopt.makers.authentication.usecase.auth.port.in.AuthenticateSocialAccountUsecase;
import sopt.makers.authentication.usecase.auth.port.in.AuthenticateSocialAccountUsecase.AuthenticateTokenInfo;
import sopt.makers.authentication.usecase.auth.port.in.CreatePhoneVerificationUsecase;
Expand Down Expand Up @@ -36,8 +35,7 @@ public class AuthApiController implements AuthApi {
public ResponseEntity<BaseResponse<?>> createPhoneVerification(
@RequestBody AuthRequest.CreatePhoneVerification createPhoneVerificationRequest) {
createVerificationUsecase.create(createPhoneVerificationRequest.toCommand());
return ResponseEntity.status(AuthSuccess.CREATE_PHONE_VERIFICATION.getStatus().value())
.body(BaseResponse.ofSuccess(AuthSuccess.CREATE_PHONE_VERIFICATION));
return ResponseUtil.success(AuthSuccess.CREATE_PHONE_VERIFICATION);
}

@Override
Expand All @@ -60,12 +58,10 @@ public ResponseEntity<BaseResponse<?>> authenticateSocialAuthInfoFromWeb(
authenticateSocialAccountUsecase.authenticate(socialAuthInfo.toCommand());
HttpHeaders headers = cookieUtil.setRefreshToken(tokenInfo.refreshToken());

return ResponseEntity.ok()
.headers(headers)
.body(
BaseResponse.ofSuccess(
AUTHENTICATE_SOCIAL_ACCOUNT,
AuthResponse.AuthenticateSocialAuthInfoForWeb.of(tokenInfo.accessToken())));
return ResponseUtil.success(
AuthSuccess.AUTHENTICATE_SOCIAL_ACCOUNT,
headers,
AuthResponse.AuthenticateSocialAuthInfoForWeb.of(tokenInfo.accessToken()));
}

@Override
Expand All @@ -75,10 +71,9 @@ public ResponseEntity<BaseResponse<?>> authenticateSocialAuthInfoFromApp(
AuthenticateTokenInfo tokenInfo =
authenticateSocialAccountUsecase.authenticate(socialAuthInfo.toCommand());

return ResponseEntity.ok(
BaseResponse.ofSuccess(
AUTHENTICATE_SOCIAL_ACCOUNT,
AuthResponse.AuthenticateSocialAuthInfoForApp.of(
tokenInfo.accessToken(), tokenInfo.refreshToken())));
return ResponseUtil.success(
AuthSuccess.AUTHENTICATE_SOCIAL_ACCOUNT,
AuthResponse.AuthenticateSocialAuthInfoForApp.of(
tokenInfo.accessToken(), tokenInfo.refreshToken()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sopt.makers.authentication.application.auth.api;

import sopt.makers.authentication.application.auth.dto.request.SocialAccountRequest;
import sopt.makers.authentication.support.common.api.BaseResponse;

import org.springframework.http.ResponseEntity;

public interface SocialAccountApi {
ResponseEntity<BaseResponse<?>> updateSocialAccount(
SocialAccountRequest.UpdateSocialAccount socialAccountInfo);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package sopt.makers.authentication.application.auth.api;

import sopt.makers.authentication.application.auth.dto.request.SocialAccountRequest;
import sopt.makers.authentication.support.code.domain.success.SocialAccountSuccess;
import sopt.makers.authentication.support.common.api.BaseResponse;
import sopt.makers.authentication.support.util.ResponseUtil;
import sopt.makers.authentication.usecase.auth.port.in.UpdateSocialAccountUsecase;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/v1/social/accounts")
@RequiredArgsConstructor
public class SocialAccountApiController implements SocialAccountApi {
private final UpdateSocialAccountUsecase updateSocialAccountUsecase;

@Override
@PatchMapping
public ResponseEntity<BaseResponse<?>> updateSocialAccount(
SocialAccountRequest.UpdateSocialAccount socialAccountInfo) {
updateSocialAccountUsecase.update(socialAccountInfo.toCommand());
return ResponseUtil.success(SocialAccountSuccess.UPDATE_SOCIAL_ACCOUNT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static lombok.AccessLevel.PRIVATE;

import sopt.makers.authentication.domain.auth.AuthPlatform;
import sopt.makers.authentication.domain.auth.PhoneVerificationType;
import sopt.makers.authentication.usecase.auth.port.in.AuthenticateSocialAccountUsecase.AuthenticateSocialAccountCommand;
import sopt.makers.authentication.usecase.auth.port.in.CreatePhoneVerificationUsecase.CreateVerificationCommand;
Expand Down Expand Up @@ -41,7 +40,7 @@ public VerifyVerificationCommand toCommand() {

public record AuthenticateSocialAuthInfo(String code, String authPlatform) {
public AuthenticateSocialAccountCommand toCommand() {
return new AuthenticateSocialAccountCommand(AuthPlatform.find(authPlatform), code);
return AuthenticateSocialAccountCommand.of(authPlatform, code);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package sopt.makers.authentication.application.auth.dto.request;

import static lombok.AccessLevel.PRIVATE;

import sopt.makers.authentication.usecase.auth.port.in.UpdateSocialAccountUsecase.UpdateSocialAccountCommand;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = PRIVATE)
public final class SocialAccountRequest {
public record UpdateSocialAccount(String phone, String code, String authPlatform) {
public UpdateSocialAccountCommand toCommand() {
return UpdateSocialAccountCommand.of(phone, authPlatform, code);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package sopt.makers.authentication.database;

import sopt.makers.authentication.database.rdb.entity.*;
import sopt.makers.authentication.database.rdb.repository.UserRegister;
import sopt.makers.authentication.database.rdb.repository.UserRetriever;
import sopt.makers.authentication.domain.auth.SocialAccount;
import sopt.makers.authentication.domain.user.User;
Expand All @@ -13,19 +15,29 @@
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {
private final UserRetriever userRetriever;
private final UserRegister userRegister;

@Override
public User findBySocialAccount(SocialAccount socialAccount) {
return userRetriever.findBySocialAccount(socialAccount);
}

@Override
public Long findIdByUser(User user) {
return userRetriever.findIdByUser(user);
}

@Override
public User findByPhone(String phone) {
return null;
return userRetriever.findByPhone(phone);
}

@Override
public Long findIdByUser(User user) {
return userRetriever.findIdByUser(user);
public User update(Long id, User user, SocialAccount socialAccount) {
user.updateSocialAccount(socialAccount);
UserEntity userEntity = UserEntity.fromDomain(user);
userEntity.setId(id);
UserEntity updatedUserEntity = userRegister.save(userEntity);
return updatedUserEntity.toDomain();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ private UserEntity(
this.authPlatformType = authPlatformType;
}

public static UserEntity fromDomain(final Long id, User user) {
Profile profile = user.getProfile();
SocialAccount socialAccount = user.getSocialAccount();
UserEntity userEntity =
new UserEntity(
profile.name(),
profile.phone(),
profile.email().orElse(null),
profile.birthday(),
socialAccount.authPlatformId(),
socialAccount.authPlatformType());
userEntity.setId(id);
return userEntity;
}

public static UserEntity fromDomain(final User user) {
Profile profile = user.getProfile();
SocialAccount socialAccount = user.getSocialAccount();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package sopt.makers.authentication.database.rdb.repository;

import sopt.makers.authentication.database.rdb.entity.UserEntity;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;

@Component
@Transactional
@RequiredArgsConstructor
public class UserRegister {
private final UserJpaRepository userJpaRepository;

public UserEntity save(UserEntity userEntity) {
return userJpaRepository.save(userEntity);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package sopt.makers.authentication.database.rdb.repository;

import static sopt.makers.authentication.support.code.domain.failure.AuthFailure.NOT_FOUND_USER_WITH_SOCIAL_ACCOUNT;
import static sopt.makers.authentication.support.code.domain.failure.UserFailure.NOT_FOUND_PHONE;

import sopt.makers.authentication.database.rdb.entity.UserEntity;
import sopt.makers.authentication.domain.auth.*;
import sopt.makers.authentication.domain.auth.AuthPlatform;
import sopt.makers.authentication.domain.auth.SocialAccount;
import sopt.makers.authentication.domain.user.User;
import sopt.makers.authentication.support.code.domain.failure.UserFailure;
import sopt.makers.authentication.support.exception.domain.AuthException;
import sopt.makers.authentication.support.exception.domain.UserException;

Expand Down Expand Up @@ -39,9 +40,7 @@ public Long findIdByUser(User user) {

public User findByPhone(String phone) {
UserEntity userEntity =
userJpaRepository
.findByPhone(phone)
.orElseThrow(() -> new UserException(UserFailure.NOT_FOUND_USER));
userJpaRepository.findByPhone(phone).orElseThrow(() -> new UserException(NOT_FOUND_PHONE));
return userEntity.toDomain();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ public class OAuthAuthenticatorImpl implements OAuthAuthenticator {
private final AppleAuthService appleAuthService;
private final GoogleAuthService googleAuthService;

public String getAuthPlatformId(AuthPlatform authPlatform, String code) {
public String getAuthPlatformId(String authPlatform, String code) {
IdTokenResponse idTokenResponse = getIdTokenByCode(authPlatform, code);
return parseAuthPlatformId(idTokenResponse);
}

public IdTokenResponse getIdTokenByCode(AuthPlatform type, String code) {
public IdTokenResponse getIdTokenByCode(String authPlatform, String code) {
AuthPlatform type = AuthPlatform.find(authPlatform);

return switch (type) {
case APPLE -> appleAuthService.getIdTokenByCode(code);
case GOOGLE -> googleAuthService.getIdTokenByCode(code);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ public enum UserFailure implements FailureCode {
// 400
DUPLICATE_ACTIVITY(HttpStatus.BAD_REQUEST, "이미 존재하는 활동 정보입니다"),
ROLE_REQUIRES_PART(HttpStatus.BAD_REQUEST, "해당 Role은 Part가 필수입니다"),

// 404
NOT_FOUND_REGISTER_INFO(HttpStatus.NOT_FOUND, "존재하지 않는 가입 대상 정보입니다."),
NOT_FOUND_USER(HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다."),
NOT_FOUND_ROLE(HttpStatus.NOT_FOUND, "존재하지 않는 역할입니다"),
NOT_FOUND_PART(HttpStatus.NOT_FOUND, "존재하지 않는 파트입니다"),
;
NOT_FOUND_PHONE(HttpStatus.NOT_FOUND, "존재하지 않는 핸드폰 번호입니다"),
NOT_FOUND_USER(HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다."),
NOT_FOUND_REGISTER_INFO(HttpStatus.NOT_FOUND, "존재하지 않는 가입 대상 정보입니다.");
private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package sopt.makers.authentication.support.code.domain.success;

import static lombok.AccessLevel.PRIVATE;

import sopt.makers.authentication.support.code.base.*;

import org.springframework.http.*;

import lombok.*;

@Getter
@RequiredArgsConstructor(access = PRIVATE)
public enum SocialAccountSuccess implements SuccessCode {
UPDATE_SOCIAL_ACCOUNT(HttpStatus.OK, "소셜 계정 변경에 성공했습니다.");

private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package sopt.makers.authentication.support.util;

import java.io.*;
import java.nio.charset.*;
import java.security.*;
import java.util.*;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Optional;

import org.bouncycastle.asn1.pkcs.*;
import org.bouncycastle.openssl.*;
import org.bouncycastle.openssl.jcajce.*;
import org.springframework.core.io.*;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.springframework.core.io.ClassPathResource;

import lombok.extern.slf4j.*;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public final class KeyFileUtil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import static sopt.makers.authentication.support.constant.SystemConstant.UTF_8;

import sopt.makers.authentication.support.code.base.FailureCode;
import sopt.makers.authentication.support.code.base.SuccessCode;
import sopt.makers.authentication.support.common.api.BaseResponse;
import sopt.makers.authentication.support.exception.base.BaseException;

import java.io.IOException;

import jakarta.servlet.http.HttpServletResponse;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import com.fasterxml.jackson.databind.ObjectMapper;

Expand All @@ -27,4 +31,27 @@ public static void generateErrorResponse(
response.setCharacterEncoding(UTF_8);
response.getWriter().write(bodyValue);
}

public static <T> ResponseEntity<BaseResponse<?>> success(SuccessCode code, T data) {
return ResponseEntity.status(code.getStatus()).body(BaseResponse.ofSuccess(code, data));
}

public static ResponseEntity<BaseResponse<?>> success(SuccessCode code) {
return ResponseEntity.status(code.getStatus()).body(BaseResponse.ofSuccess(code));
}

public static <T> ResponseEntity<BaseResponse<?>> success(
SuccessCode code, HttpHeaders headers, T data) {
return ResponseEntity.status(code.getStatus())
.headers(headers)
.body(BaseResponse.ofSuccess(code, data));
}

public static <T> ResponseEntity<BaseResponse<?>> failure(FailureCode code, T data) {
return ResponseEntity.status(code.getStatus()).body(BaseResponse.ofFailure(code, data));
}

public static ResponseEntity<BaseResponse<?>> failure(FailureCode code) {
return ResponseEntity.status(code.getStatus()).body(BaseResponse.ofFailure(code));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package sopt.makers.authentication.usecase.auth.port.in;

import sopt.makers.authentication.domain.auth.AuthPlatform;

public interface AuthenticateSocialAccountUsecase {
AuthenticateTokenInfo authenticate(AuthenticateSocialAccountCommand command);

Expand All @@ -11,5 +9,9 @@ public static AuthenticateTokenInfo of(String accessToken, String refreshToken)
}
}

record AuthenticateSocialAccountCommand(AuthPlatform authPlatform, String code) {}
record AuthenticateSocialAccountCommand(String authPlatform, String code) {
public static AuthenticateSocialAccountCommand of(String authPlatform, String code) {
return new AuthenticateSocialAccountCommand(authPlatform, code);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sopt.makers.authentication.usecase.auth.port.in;

public interface UpdateSocialAccountUsecase {
boolean update(UpdateSocialAccountCommand command);

record UpdateSocialAccountCommand(String phone, String authPlatform, String code) {
public static UpdateSocialAccountCommand of(String phone, String authPlatform, String code) {
return new UpdateSocialAccountCommand(phone, authPlatform, code);
}
}
}
Loading

0 comments on commit 364508a

Please sign in to comment.