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

Pet 71 feat: 이벤트 기반 user 생성 #23

Merged
merged 16 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
d1f203a
PET-71 feat : user-domain 모듈 생성 및 entity 생성
isprogrammingfun Aug 21, 2023
2e307a4
PET-71 feat : user-application 모듈 생성, 의존성 추가, 유저 생성을 위한 event handle…
isprogrammingfun Aug 21, 2023
2b95f20
PET-71 feat : 첫 회원가입 및 중복 계정 유무 검증 service 추가, 관련 예외 처리 추가, 의존성 추가
isprogrammingfun Aug 21, 2023
b2d5295
PET-71 feat : user-domain 모듈 repository, service 코드 추가, 관련 예외처리 추가
isprogrammingfun Aug 21, 2023
794b69f
PET-71 fix : 패키지 이름 domain -> entity로 수정
isprogrammingfun Aug 21, 2023
e416214
PET-71 feat : Mapper 클래스 추가, 어노테이션 추가
isprogrammingfun Aug 21, 2023
5106bd9
PET-71 fix : userRepository import
isprogrammingfun Aug 21, 2023
707e912
PET-71 refactor : 이벤트 처리 Subject에서 처리하는 방식으로 수정, InternalOAuthService…
isprogrammingfun Aug 21, 2023
d6f5424
PET-71 refactor : 의존성 제거
isprogrammingfun Aug 21, 2023
6828fd6
PET-71 user-application 의존성 추가
isprogrammingfun Aug 21, 2023
094f177
PET-71 chore : 불필요한 import 문 제거
isprogrammingfun Aug 21, 2023
69e4ef3
PET-71 refactor : 구글, 카카오, 네이버 OAuthUserInfo provider 추가
isprogrammingfun Aug 21, 2023
bb40393
PET-71 refactor : OAuthUserInfo provider 제거
isprogrammingfun Aug 21, 2023
d5ecd6d
PET-71 refactor : 예외처리 수정
isprogrammingfun Aug 21, 2023
92e6088
PET-71 refactor : 예외처리 수정
isprogrammingfun Aug 21, 2023
28ea4d7
PET-71 refactor : UserQueryService에서 중복 계정 예외 처리하도록 수정
isprogrammingfun Aug 21, 2023
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
1 change: 1 addition & 0 deletions Auth-Module/auth-application/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dependencies {
implementation project(":Auth-Module:JWT")
implementation project(":User-Module:user-application")
// Feign
implementation 'io.github.openfeign:feign-httpclient:12.1'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.4'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pawith.authmodule.application.common.exception;

import com.pawith.commonmodule.exception.BusinessException;
import com.pawith.commonmodule.exception.Error;

public class AccountAlreadyExistException extends BusinessException {
tlarbals824 marked this conversation as resolved.
Show resolved Hide resolved
public AccountAlreadyExistException(Error error) {
super(error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
public class OAuthUserInfo {
private final String username;
private final String email;
private final String provider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected OAuthUserInfo attemptLogin(String accessToken) {
Jws<Claims> oidcTokenJws = sigVerificationAndGetJws(accessToken);
// 토큰 바디 파싱해서 사용자 정보 획득
String email = (String) oidcTokenJws.getBody().get("email");
return new OAuthUserInfo("포잇",email);
return new OAuthUserInfo("포잇", email, PROVIDER.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class GoogleOAuthObserver extends AbstractOAuthObserver {
@Override
protected OAuthUserInfo attemptLogin(String accessToken) {
log.info("GoogleOAuthObserver attemptLogin");
return new OAuthUserInfo("Google username","Google email");
return new OAuthUserInfo("Google username","Google email", PROVIDER.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class KakaoOAuthObserver extends AbstractOAuthObserver {
@Override
protected OAuthUserInfo attemptLogin(String accessToken) {
log.info("KakaoOAuthObserver attemptLogin");
return new OAuthUserInfo("Kakao username","Kakao email");
return new OAuthUserInfo("Kakao username","Kakao email", PROVIDER.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class NaverOAuthObserver extends AbstractOAuthObserver {
private final RestTemplate restTemplate;
protected OAuthUserInfo attemptLogin(String accessToken) {
log.info("NaverOAuthObserver attemptLogin");
return new OAuthUserInfo("Naver username","Naver email");
return new OAuthUserInfo("Naver username","Naver email", PROVIDER.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package com.pawith.authmodule.application.port.out.observer.subject;

import com.pawith.authmodule.application.common.consts.AuthConsts;
import com.pawith.authmodule.application.common.exception.AccountAlreadyExistException;
import com.pawith.authmodule.application.dto.OAuthRequest;
import com.pawith.authmodule.application.dto.OAuthResponse;
import com.pawith.authmodule.application.dto.OAuthUserInfo;
import com.pawith.authmodule.application.port.out.observer.observer.AbstractOAuthObserver;
import com.pawith.commonmodule.exception.Error;
import com.pawith.commonmodule.observer.observer.Observer;
import com.pawith.commonmodule.observer.subject.Status;
import com.pawith.commonmodule.observer.subject.Subject;
import com.pawith.jwt.JWTProvider;
import com.pawith.usermodule.application.handler.event.UserSignUpEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -25,6 +29,8 @@ public final class OAuthSubject implements Subject<OAuthRequest, OAuthResponse>

private JWTProvider jwtProvider;

private ApplicationEventPublisher publisher;

@Override
public void registerObserver(Observer<? extends Status,?> o) {
observerList.add((AbstractOAuthObserver) o);
Expand All @@ -38,6 +44,11 @@ public void removeObserver(Observer<? extends Status, ?> o) {
@Override
public OAuthResponse notifyObservers(OAuthRequest object) {
final OAuthUserInfo oAuthUserInfo = attemptLogin(new OAuth(object.getProvider(), object.getAccessToken()));
try {
publisher.publishEvent(new UserSignUpEvent(oAuthUserInfo.getUsername(), oAuthUserInfo.getEmail(), oAuthUserInfo.getProvider()));
tlarbals824 marked this conversation as resolved.
Show resolved Hide resolved
}catch (AccountAlreadyExistException ex) {
tlarbals824 marked this conversation as resolved.
Show resolved Hide resolved
throw new AccountAlreadyExistException(Error.ACCOUNT_ALREADY_EXIST);
}
return generateServerAuthenticationTokens(oAuthUserInfo);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pawith.commonmodule.annotation;

import org.springframework.stereotype.Service;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
public @interface DomainService {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.pawith.commonmodule.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Mapper {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pawith.commonmodule.domain;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

@CreatedDate
protected LocalDateTime createdAt;

@LastModifiedDate
protected LocalDateTime updatedAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public enum Error {
NOT_EXIST_TOKEN("토큰이 존재하지 않습니다.", 1003),
INVALID_AUTHORIZATION_TYPE("유효하지 않은 Authorization Type 입니다.", 1004),
EMPTY_AUTHORIZATION_HEADER("Authorization Header가 비어있습니다.", 1005),
ACCOUNT_ALREADY_EXIST("이미 가입한 계정이 있습니다", 1006),

// User
USER_NOT_FOUND("사용자를 찾을 수 없습니다.", 2000),
;

private final String message;
Expand Down
5 changes: 5 additions & 0 deletions User-Module/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
subprojects {
dependencies {
implementation project(":Common-Module")
}
}
3 changes: 3 additions & 0 deletions User-Module/user-application/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
implementation project(":User-Module:user-domain")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.pawith.usermodule.application.handler;

import com.pawith.usermodule.application.handler.event.UserSignUpEvent;
import com.pawith.usermodule.application.mapper.UserMapper;
import com.pawith.usermodule.domain.entity.User;
import com.pawith.usermodule.domain.repository.UserRepository;
import com.pawith.usermodule.domain.service.UserSaveService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@RequiredArgsConstructor
public class UserSignUpHandler {

private final UserSaveService userSaveService;
private final UserRepository userRepository;

@Transactional
@EventListener
public void signUp(UserSignUpEvent userSignUpEvent){
tlarbals824 marked this conversation as resolved.
Show resolved Hide resolved
if(!userRepository.existsByEmail(userSignUpEvent.getEmail())) {
final User user = UserMapper.toEntity(userSignUpEvent);
userSaveService.saveUser(user);
}
else
throw new IllegalArgumentException("사용자 존재");
tlarbals824 marked this conversation as resolved.
Show resolved Hide resolved
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.pawith.usermodule.application.handler.event;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
@AllArgsConstructor
@Builder
public class UserSignUpEvent {
private final String nickname;
private final String email;
private final String Provider;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.pawith.usermodule.application.mapper;

import com.pawith.commonmodule.annotation.Mapper;
import com.pawith.usermodule.application.handler.event.UserSignUpEvent;
import com.pawith.usermodule.domain.entity.User;

@Mapper
public class UserMapper {

public static User toEntity(UserSignUpEvent userSignUpEvent){
return User.builder()
.nickname(userSignUpEvent.getNickname())
.email(userSignUpEvent.getEmail())
.provider(userSignUpEvent.getProvider())
.build();
}

}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.pawith.usermodule.domain.entity;

import com.pawith.commonmodule.domain.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;

private String nickname;
private String email;
private String profileImageUrl;
private String provider;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pawith.usermodule.domain.exception;

import com.pawith.commonmodule.exception.BusinessException;
import com.pawith.commonmodule.exception.Error;

public class UserException extends BusinessException {
public UserException(Error error) {
super(error);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.pawith.usermodule.domain.exception;

import com.pawith.commonmodule.exception.Error;

public class UserNotFoundException extends UserException{
public UserNotFoundException(Error error) { super(error); }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.pawith.usermodule.domain.repository;

import com.pawith.usermodule.domain.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.pawith.usermodule.domain.service;

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.commonmodule.exception.Error;
import com.pawith.usermodule.domain.entity.User;
import com.pawith.usermodule.domain.exception.UserNotFoundException;
import com.pawith.usermodule.domain.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@DomainService
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class UserQueryService {
private final UserRepository userRepository;


public User findByEmail(String email) {
return userRepository.findByEmail(email)
.orElseThrow(() -> new UserNotFoundException(Error.USER_NOT_FOUND));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.pawith.usermodule.domain.service;

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.usermodule.domain.entity.User;
import com.pawith.usermodule.domain.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@DomainService
@RequiredArgsConstructor
public class UserSaveService {

private final UserRepository userRepository;

@Transactional
public void saveUser(User user) {
userRepository.save(user);
}

}
5 changes: 5 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ include 'Auth-Module:auth-application'
findProject(':Auth-Module:auth-application')?.name = 'auth-application'

include 'Auth-Module:JWT'
include 'User-Module'
include 'User-Module:user-domain'
findProject(':User-Module:user-domain')?.name = 'user-domain'
include 'User-Module:user-application'
findProject(':User-Module:user-application')?.name = 'user-application'