Skip to content

Commit

Permalink
Merge pull request #27 from Leets-Official/feat/#26/최초-회원가입-구현
Browse files Browse the repository at this point in the history
Feat #27 최초 회원가입 구현
  • Loading branch information
koreaioi authored Jan 14, 2025
2 parents 6392c06 + d51d25d commit 540e161
Show file tree
Hide file tree
Showing 23 changed files with 197 additions and 185 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## 📌 관련 이슈
관련 이슈 번호 #
관련 이슈 번호 #
Close #


Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/gachtaxi/GachtaxiApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@SpringBootApplication
@EnableJpaAuditing
@EnableMongoAuditing
public class GachtaxiApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
package com.gachtaxi.domain.members.controller;

import com.gachtaxi.domain.members.dto.request.InactiveMemberAuthCodeRequestDto;
import com.gachtaxi.domain.members.dto.request.MemberAgreementRequestDto;
import com.gachtaxi.domain.members.dto.request.MemberSupplmentRequestDto;
import com.gachtaxi.domain.members.dto.response.InactiveMemberResponseDto;
import com.gachtaxi.domain.members.service.AuthService;
import com.gachtaxi.domain.members.service.MemberService;
import com.gachtaxi.global.auth.enums.OauthLoginStatus;
import com.gachtaxi.global.auth.jwt.annotation.CurrentMemberId;
import com.gachtaxi.global.auth.jwt.dto.JwtTokenDto;
import com.gachtaxi.global.auth.jwt.service.JwtService;
import com.gachtaxi.global.auth.jwt.util.CookieUtil;
import com.gachtaxi.global.common.mail.dto.request.EmailAddressDto;
import com.gachtaxi.global.common.mail.service.EmailService;
import com.gachtaxi.global.common.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import static com.gachtaxi.domain.members.controller.ResponseMessage.*;
import static com.gachtaxi.global.auth.jwt.util.JwtProvider.ACCESS_TOKEN_SUBJECT;
import static com.gachtaxi.global.auth.jwt.util.JwtProvider.REFRESH_TOKEN_SUBJECT;
import static com.gachtaxi.global.auth.kakao.dto.KaKaoDTO.KakaoAuthCode;
import static com.gachtaxi.global.auth.kakao.dto.KaKaoDTO.OauthKakaoResponse;
import static com.gachtaxi.global.common.mail.message.ResponseMessage.EMAIL_AUTHENTICATION_SUCESS;
import static com.gachtaxi.global.common.mail.message.ResponseMessage.EMAIL_SEND_SUCCESS;
import static com.gachtaxi.global.common.mail.message.ResponseMessage.*;
import static org.springframework.http.HttpStatus.OK;

@RequestMapping("/auth")
Expand All @@ -32,27 +33,35 @@
public class AuthController {

private final EmailService emailService;
private final CookieUtil cookieUtil;
private final AuthService authService;
private final JwtService jwtService;
private final MemberService memberService;

@PostMapping("/login/kakao")
@Operation(summary = "인가 코드를 전달받아, 소셜 로그인을 진행합니다.")
public ApiResponse<OauthKakaoResponse> kakaoLogin(@RequestBody @Valid KakaoAuthCode kakaoAuthCode, HttpServletResponse response) {
OauthKakaoResponse res = authService.kakaoLogin(kakaoAuthCode.authCode(), response);
ResponseMessage OAUTH_STATUS = (res.status() == OauthLoginStatus.LOGIN)
? LOGIN_SUCCESS
: UN_REGISTER;
return ApiResponse.response(HttpStatus.OK, OAUTH_STATUS.getMessage(), res);
public ApiResponse<ResponseMessage> kakaoLogin(@RequestBody @Valid KakaoAuthCode kakaoAuthCode, HttpServletResponse response) {
JwtTokenDto jwtTokenDto = authService.kakaoLogin(kakaoAuthCode.authCode());
response.setHeader(ACCESS_TOKEN_SUBJECT, jwtTokenDto.accessToken());

if(jwtTokenDto.isTemporaryUser()){ // 임시 유저
return ApiResponse.response(HttpStatus.OK, UN_REGISTER.getMessage(), UN_REGISTER);
}

cookieUtil.setCookie(REFRESH_TOKEN_SUBJECT, jwtTokenDto.refreshToken(), response);
return ApiResponse.response(HttpStatus.OK, LOGIN_SUCCESS.getMessage(), LOGIN_SUCCESS);
}

@PostMapping("/refresh")
@Operation(summary = "RefreshToken으로 AccessToken과 RefreshToken을 재발급 하는 API 입니다.")
public ApiResponse<Void> reissueRefreshToken(HttpServletRequest request, HttpServletResponse response) {
JwtTokenDto jwtTokenDto = jwtService.reissueJwtToken(request);
public ApiResponse<Void> reissueRefreshToken(
@CookieValue(value = REFRESH_TOKEN_SUBJECT) String refreshToken,
HttpServletResponse response
) {
JwtTokenDto jwtTokenDto = jwtService.reissueJwtToken(refreshToken);
response.setHeader(ACCESS_TOKEN_SUBJECT, jwtTokenDto.accessToken());
cookieUtil.setCookie(REFRESH_TOKEN_SUBJECT, jwtTokenDto.refreshToken(), response);

jwtService.setCookie(jwtTokenDto.refreshToken(), response);
jwtService.setHeader(jwtTokenDto.accessToken(), response);
return ApiResponse.response(HttpStatus.OK, REFRESH_TOKEN_REISSUE.getMessage());
}

Expand All @@ -73,7 +82,31 @@ public ApiResponse checkAuthCodeAndUpdateEmail(
@CurrentMemberId Long userId
) {
emailService.checkEmailAuthCode(dto.email(), dto.authCode());
memberService.updateInactiveMemberOfEmail(dto.email(), userId);
memberService.updateMemberEmail(dto.email(), userId);
return ApiResponse.response(OK, EMAIL_AUTHENTICATION_SUCESS.getMessage(), InactiveMemberResponseDto.from(userId));
}

@PatchMapping("/agreement")
@Operation(summary = "약관 동의 정보를 업데이트하는 API 입니다.")
public ApiResponse<Void> updateUserAgreement(
@RequestBody MemberAgreementRequestDto dto,
@CurrentMemberId Long userId
){
memberService.updateMemberAgreement(dto, userId);
return ApiResponse.response(OK, AGREEEMENT_UPDATE_SUCCESS.getMessage());
}

@PatchMapping("/supplement")
@Operation(summary = "사용자 추가 정보 업데이트하는 API 입니다. (프로필, 닉네임, 실명, 학번, 성별,)")
public ApiResponse<Void> updateMemberSupplement(
@RequestBody MemberSupplmentRequestDto dto,
@CurrentMemberId Long userId
){
memberService.updateMemberSupplement(dto, userId);
return ApiResponse.response(OK, SUPPLEMENT_UPDATE_SUCCESS.getMessage());
}

/*
* refactoring
* */
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
package com.gachtaxi.domain.members.controller;

import com.gachtaxi.domain.members.dto.request.UserSignUpRequestDto;
import com.gachtaxi.domain.members.service.MemberService;
import com.gachtaxi.global.common.response.ApiResponse;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static com.gachtaxi.domain.members.controller.ResponseMessage.REGISTER_SUCCESS;
import static org.springframework.http.HttpStatus.OK;

@RequestMapping("/api/members")
@RestController
@RequiredArgsConstructor
public class MemberController {

private final MemberService memberService;

@PostMapping()
public ApiResponse<Void> signUp(@RequestBody @Valid UserSignUpRequestDto signUpDto, HttpServletResponse response) {
memberService.saveMember(signUpDto, response);
return ApiResponse.response(OK, REGISTER_SUCCESS.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.gachtaxi.domain.members.dto.request;

import jakarta.validation.constraints.NotNull;

public record MemberAgreementRequestDto(
@NotNull boolean termsAgreement,
@NotNull boolean privacyAgreement,
@NotNull boolean marketingAgreement
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.gachtaxi.domain.members.dto.request;

import com.gachtaxi.domain.members.entity.enums.Gender;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record MemberSupplmentRequestDto(
String profilePicture,
@NotBlank String nickname,
@NotBlank String realName,
@NotNull Long studentNumber,
@NotNull Gender gender
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.gachtaxi.domain.members.dto.response;

import com.gachtaxi.domain.members.controller.ResponseMessage;

public record OauthResponse(
String status
) {
public static OauthResponse from(ResponseMessage responseMessage) {
return new OauthResponse(responseMessage.name());
}
}
38 changes: 19 additions & 19 deletions src/main/java/com/gachtaxi/domain/members/entity/Members.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gachtaxi.domain.members.entity;

import com.gachtaxi.domain.members.dto.request.UserSignUpRequestDto;
import com.gachtaxi.domain.members.dto.request.MemberAgreementRequestDto;
import com.gachtaxi.domain.members.dto.request.MemberSupplmentRequestDto;
import com.gachtaxi.domain.members.entity.enums.Gender;
import com.gachtaxi.domain.members.entity.enums.Role;
import com.gachtaxi.domain.members.entity.enums.UserStatus;
Expand Down Expand Up @@ -83,31 +84,30 @@ public void updateEmail(String email) {
this.email = email;
}

public static Members of(UserSignUpRequestDto dto){
return Members.builder()
//.profilePicture(dto.profilePicture())
.email(dto.email())
.nickname(dto.nickName())
.realName(dto.realName())
.studentNumber(dto.studentNumber())
//.phoneNumber(dto.phoneNumber())
.kakaoId(dto.kakaoId())
.googleId(dto.googleId())
.role(Role.MEMBER)
.status(UserStatus.ACTIVE)
.gender(dto.gender())
.termsAgreement(dto.termsAgreement())
.privacyAgreement(dto.privacyAgreement())
.marketingAgreement(dto.marketingAgreement())
.twoFactorAuthentication(dto.twoFactorAuthentication())
.build();
public void updateAgreement(MemberAgreementRequestDto dto) {
this.termsAgreement = dto.termsAgreement();
this.privacyAgreement = dto.privacyAgreement();
this.marketingAgreement = dto.marketingAgreement();
}

public void updateSupplment(MemberSupplmentRequestDto dto) {
this.profilePicture = dto.profilePicture();
this.nickname = dto.nickname();
this.realName = dto.realName();
this.studentNumber = dto.studentNumber();
this.gender = dto.gender();
this.status = UserStatus.ACTIVE;
}

public static Members ofKakaoId(Long kakaoId){
return Members.builder()
.kakaoId(kakaoId)
.status(UserStatus.INACTIVE)
.role(Role.MEMBER)
.termsAgreement(false)
.privacyAgreement(false)
.marketingAgreement(false)
.twoFactorAuthentication(false)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.gachtaxi.domain.members.exception;

import com.gachtaxi.global.common.exception.BaseException;

import static com.gachtaxi.domain.members.exception.ErrorMessage.DUPLICATED_EMAIL;
import static org.springframework.http.HttpStatus.BAD_REQUEST;

public class DuplicatedEmailException extends BaseException {
public DuplicatedEmailException() {
super(BAD_REQUEST, DUPLICATED_EMAIL.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum ErrorMessage {

DUPLICATED_STUDENT_NUMBER("이미 가입된 학번입니다."),
MEMBER_NOT_FOUND("회원을 찾을 수 없습니다."),
DUPLICATED_EMAIL("중복된 이메일입니다."),
EMAIL_FROM_INVALID("가천대 이메일 형식이 아닙니다.");

private final String message;
Expand Down
28 changes: 7 additions & 21 deletions src/main/java/com/gachtaxi/domain/members/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import com.gachtaxi.domain.members.dto.request.InactiveMemberDto;
import com.gachtaxi.domain.members.entity.Members;
import com.gachtaxi.global.auth.jwt.dto.JwtTokenDto;
import com.gachtaxi.global.auth.jwt.service.JwtService;
import com.gachtaxi.global.auth.kakao.util.KakaoUtil;
import com.gachtaxi.global.auth.mapper.OauthMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

Expand All @@ -14,44 +13,31 @@
import static com.gachtaxi.domain.members.entity.enums.UserStatus.INACTIVE;
import static com.gachtaxi.global.auth.kakao.dto.KaKaoDTO.*;


/*
* AuthService는 인증 로직 책임을 가진다.
* */


@Service
@RequiredArgsConstructor
public class AuthService {

private final KakaoUtil kakaoUtil;
private final OauthMapper oauthMapper;
private final JwtService jwtService;
private final MemberService memberService;

public OauthKakaoResponse kakaoLogin(String authCode, HttpServletResponse response) {
public JwtTokenDto kakaoLogin(String authCode) {
KakaoAccessToken kakaoAccessToken = kakaoUtil.reqeustKakaoToken(authCode);
KakaoUserInfoResponse userInfo = kakaoUtil.requestKakaoProfile(kakaoAccessToken.access_token());

Long kakaoId = userInfo.id();
Optional<Members> optionalMember = memberService.findByKakaoId(kakaoId);

if(optionalMember.isEmpty()) {
InactiveMemberDto tmpDto = memberService.saveTmpMember(kakaoId);

jwtService.responseTmpAccessToken(tmpDto, response);
return oauthMapper.toKakaoUnRegisterResponse(tmpDto.userId());
return jwtService.generateTmpAccessToken(memberService.saveTmpMember(kakaoId));
}

// 회원 가입 진행 중 중단된 유저 또한 다시 임시 토큰을 재발급해준다.
if(optionalMember.get().getStatus() == INACTIVE){
InactiveMemberDto tmpDto = InactiveMemberDto.of(optionalMember.get());
jwtService.responseTmpAccessToken(tmpDto, response);
return oauthMapper.toKakaoUnRegisterResponse(tmpDto.userId());
Members member = optionalMember.get();
if(member.getStatus() == INACTIVE){
return jwtService.generateTmpAccessToken(InactiveMemberDto.of(optionalMember.get()));
}

Members member = optionalMember.get();
jwtService.responseJwtToken(member.getId(), member.getEmail(), member.getRole(), response);
return oauthMapper.toKakaoLoginResponse(member.getId());
return jwtService.generateJwtToken(member.getId(), member.getEmail(), member.getRole().name());
}
}
Loading

0 comments on commit 540e161

Please sign in to comment.