Skip to content

Commit

Permalink
Merge pull request #176 from UMC5th-bias/refactor/#174
Browse files Browse the repository at this point in the history
[REFACTOR/#174] MemberService 로직 리팩 및 회원가입 테스트 코드 작성
  • Loading branch information
JungYoonShin authored Feb 11, 2025
2 parents ca9431e + 7ff706d commit c4f7357
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.favoriteplace.app.member.controller.dto.MemberDto.EmailCheckReqDto;
import com.favoriteplace.app.member.controller.dto.MemberDto.EmailDuplicateResDto;
import com.favoriteplace.app.member.controller.dto.MemberDto.EmailSendResDto;
import com.favoriteplace.app.member.controller.dto.MemberDto.MemberSignUpReqDto;
import com.favoriteplace.app.member.controller.dto.MemberSignUpReqDto;
import com.favoriteplace.app.member.service.MailSendService;
import com.favoriteplace.app.member.service.MemberService;
import com.favoriteplace.global.util.SecurityUtil;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,4 @@ public record KaKaoSignUpRequestDto(
Boolean snsAllow,
String introduction
) {
public Member toEntity(String profileImg, Item titleItem, String email) {
return Member.builder()
.nickname(nickname)
.email(email)
.alarmAllowance(snsAllow)
.description(introduction)
.profileImageUrl(profileImg)
.point(0L)
.loginType(LoginType.KAKAO)
.profileTitle(titleItem)
.status(MemberStatus.Y)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,6 @@
import lombok.NoArgsConstructor;

public class MemberDto {
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class MemberSignUpReqDto {
@NotBlank(message = "닉네임은 필수값입니다.")
public String nickname;

public String email;
public String password;
public Boolean snsAllow;
public String introduction;

public Member toEntity(String encodedPassword, String profileImg, Item titleItem) {
return Member.builder()
.nickname(nickname)
.email(email)
.password(encodedPassword)
.alarmAllowance(snsAllow)
.description(introduction)
.profileImageUrl(profileImg)
.point(0L)
.loginType(LoginType.SELF)
.profileTitle(titleItem)
.status(MemberStatus.Y)
.build();
}
}

@Builder
@Getter
@AllArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.favoriteplace.app.member.controller.dto;

import jakarta.validation.constraints.NotBlank;

public record MemberSignUpReqDto(
@NotBlank(message = "닉네임은 필수값입니다.")
String nickname,
String email,
String password,
Boolean snsAllow,
String introduction
) {
}
20 changes: 19 additions & 1 deletion src/main/java/com/favoriteplace/app/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class Member extends BaseTimeEntity {
@JoinColumn(name = "profile_icon_id")
private Item profileIcon;

@Column(nullable = false)
@Column(nullable = false, unique = true)
private String email;

private String password;
Expand Down Expand Up @@ -76,6 +76,24 @@ public class Member extends BaseTimeEntity {

private String fcmToken;

public static Member create(
String nickname, String email,
boolean snsAllow, String introduction,
String profileImage, Item titleItem)
{
return Member.builder()
.nickname(nickname)
.email(email)
.alarmAllowance(snsAllow)
.description(introduction)
.profileImageUrl(profileImage)
.point(0L)
.loginType(LoginType.KAKAO)
.profileTitle(titleItem)
.status(MemberStatus.Y)
.build();
}

public void updatePassword(String password) { this.password = password; }

public void updateRefreshToken(String refreshToken) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.favoriteplace.app.member.repository;

import com.favoriteplace.app.member.domain.Member;

import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findByEmail(String email);
boolean existsById(Long id);

List<Member> findAllByEmail(String email);
}


122 changes: 69 additions & 53 deletions src/main/java/com/favoriteplace/app/member/service/MemberService.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package com.favoriteplace.app.member.service;

import static com.favoriteplace.global.exception.ErrorCode.NOT_SIGNUP_WITH_KAKAO;
import static com.favoriteplace.global.exception.ErrorCode.TOKEN_NOT_VALID;
import static com.favoriteplace.global.exception.ErrorCode.USER_ALREADY_EXISTS;
import static com.favoriteplace.global.exception.ErrorCode.USER_NOT_FOUND;

import com.favoriteplace.app.member.controller.dto.MemberSignUpReqDto;
import com.favoriteplace.app.member.controller.dto.TokenInfoDto;
import com.favoriteplace.app.member.domain.Member;
import com.favoriteplace.app.item.domain.Item;
import com.favoriteplace.app.item.repository.ItemRepository;
import com.favoriteplace.app.member.controller.dto.AuthKakaoLoginDto;
import com.favoriteplace.app.member.controller.dto.UserInfoResponseDto;
import com.favoriteplace.app.member.controller.dto.KaKaoSignUpRequestDto;
import com.favoriteplace.app.member.controller.dto.MemberDto;
import com.favoriteplace.app.member.controller.dto.TokenInfoDto;
import com.favoriteplace.app.member.controller.dto.UserInfoResponseDto;
import com.favoriteplace.app.member.domain.Member;
import com.favoriteplace.app.member.controller.dto.MemberDto.EmailDuplicateResDto;
import com.favoriteplace.app.member.controller.dto.MemberDto.EmailSendReqDto;
import com.favoriteplace.app.item.repository.ItemRepository;
import com.favoriteplace.app.member.repository.MemberRepository;
import com.favoriteplace.global.exception.RestApiException;
import com.favoriteplace.global.s3Image.AmazonS3ImageManager;
import com.favoriteplace.global.auth.kakao.KakaoClient;
import com.favoriteplace.global.auth.provider.JwtTokenProvider;
import com.favoriteplace.global.util.SecurityUtil;
import com.favoriteplace.global.exception.RestApiException;
import com.favoriteplace.global.s3Image.AmazonS3ImageManager;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
Expand All @@ -36,26 +36,23 @@
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
@Slf4j
public class MemberService {

private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;
private final JwtTokenProvider jwtTokenProvider;
private final SecurityUtil securityUtil;
private final AmazonS3ImageManager amazonS3ImageManager;
private final ItemRepository itemRepository;
private final RedisTemplate redisTemplate;
private final KakaoClient kakaoClient;

public TokenInfoDto kakaoLogin(final String token) {
AuthKakaoLoginDto userInfo = kakaoClient.getUserInfo(token);
String userEmail = getUserEmailFromKakao(token);

// 최초 로그인이라면 회원가입 API로 통신하도록
Member member = memberRepository.findByEmail(userInfo.kakaoAccount().email())
.orElseThrow(() -> new RestApiException(NOT_SIGNUP_WITH_KAKAO));
Member member = findMember(userEmail);

return jwtTokenProvider.generateToken(userInfo.kakaoAccount().email());
return issueToken(userEmail);
}

@Transactional
Expand All @@ -65,24 +62,22 @@ public MemberDto.MemberSignUpResDto kakaoSignUp(
final List<MultipartFile> images
) throws IOException {

String userEmail = kakaoClient.getUserInfo(token).kakaoAccount().email();
String userEmail = getUserEmailFromKakao(token);

memberRepository.findByEmail(userEmail)
.ifPresent(a -> {
throw new RestApiException(USER_ALREADY_EXISTS);
});

String profileImageUrl = null;
if (images != null && !images.get(0).isEmpty()) {
profileImageUrl = uploadProfileImage(images.get(0));
}
String profileImage = getProfileImageFromRequest(images);

Item titleItem = itemRepository.findByName("새싹회원").get();
Item titleItem = getDefaultProfileItem();

Member member = memberSignUpReqDto.toEntity(profileImageUrl, titleItem, userEmail);
memberRepository.save(member);
Member member = saveUser(memberSignUpReqDto.nickname(), userEmail,
memberSignUpReqDto.snsAllow(), memberSignUpReqDto.introduction(),
profileImage, titleItem);

TokenInfoDto tokenInfo = jwtTokenProvider.generateToken(userEmail);
TokenInfoDto tokenInfo = issueToken(userEmail);
member.updateRefreshToken(tokenInfo.refreshToken());

return MemberDto.MemberSignUpResDto.from(member, tokenInfo);
Expand All @@ -91,30 +86,21 @@ public MemberDto.MemberSignUpResDto kakaoSignUp(

@Transactional
public MemberDto.MemberSignUpResDto signup(
final MemberDto.MemberSignUpReqDto memberSignUpReqDto,
final MemberSignUpReqDto memberSignUpReqDto,
final List<MultipartFile> images
) throws IOException {

memberRepository.findByEmail(memberSignUpReqDto.getEmail())
.ifPresent(
existingMember -> {
throw new RestApiException(USER_ALREADY_EXISTS);
}
);

String profileImageUrl = null;
if (images != null && !images.get(0).isEmpty()) {
profileImageUrl = uploadProfileImage(images.get(0));
}
String password = passwordEncoder.encode(memberSignUpReqDto.password());

String password = passwordEncoder.encode(memberSignUpReqDto.getPassword());
Item titleItem = getDefaultProfileItem();

Item titleItem = itemRepository.findByName("새싹회원").get();
String profileImage = getProfileImageFromRequest(images);

Member member = memberSignUpReqDto.toEntity(password, profileImageUrl, titleItem);
memberRepository.save(member);
Member member = saveUser(memberSignUpReqDto.nickname(), memberSignUpReqDto.email(),
memberSignUpReqDto.snsAllow(), memberSignUpReqDto.introduction(),
profileImage, titleItem);

TokenInfoDto tokenInfo = jwtTokenProvider.generateToken(member.getEmail());
TokenInfoDto tokenInfo= issueToken(member.getEmail());
member.updateRefreshToken(tokenInfo.refreshToken());

return MemberDto.MemberSignUpResDto.from(member, tokenInfo);
Expand All @@ -124,12 +110,11 @@ public String uploadProfileImage(MultipartFile profileImage) throws IOException
return amazonS3ImageManager.upload(profileImage).join();
}

@Transactional
public MemberDto.EmailDuplicateResDto emailDuplicateCheck(MemberDto.EmailSendReqDto emailSendReqDto) {
public MemberDto.EmailDuplicateResDto emailDuplicateCheck(EmailSendReqDto emailSendReqDto) {
String email = emailSendReqDto.getEmail();
Boolean isExists = memberRepository.findByEmail(email).isPresent();

return new MemberDto.EmailDuplicateResDto(isExists);
return new EmailDuplicateResDto(isExists);
}

@Transactional
Expand All @@ -140,7 +125,6 @@ public void setNewPassword(String email, String password) {
member.updatePassword(newPassword);
}

@Transactional
public UserInfoResponseDto getUserInfo(Member member) {
if (member != null) {
return UserInfoResponseDto.of(member);
Expand All @@ -149,25 +133,57 @@ public UserInfoResponseDto getUserInfo(Member member) {
}

@Transactional
public void logout(String token){
Authentication authentication = jwtTokenProvider.getAuthentication(token);
public void logout(String accessToken) {
/*1. Access Token 검증 */
if (!jwtTokenProvider.validateToken(accessToken)) {
new RestApiException(TOKEN_NOT_VALID);
}

Authentication authentication = jwtTokenProvider.getAuthentication(accessToken);
Member member = findMember(authentication.getName());

if (member.getRefreshToken() != null && !member.getRefreshToken().isEmpty()) {
member.deleteRefreshToken(member.getRefreshToken());
}

/* 해당 asscess token 유효시간을 계산해서 blacklist로 저장 */
Long expriation = jwtTokenProvider.getExpiration(token);
log.info(String.valueOf(expriation));
Long expriation = jwtTokenProvider.getExpiration(accessToken);
redisTemplate.opsForValue()
.set(token, "logout", expriation, TimeUnit.MILLISECONDS);

.set(accessToken, "logout", expriation, TimeUnit.MICROSECONDS);
}

public Member findMember(final String email) {
private Member findMember(final String email) {
return memberRepository.findByEmail(email)
.orElseThrow(() -> new RestApiException(USER_NOT_FOUND));
}

private String getUserEmailFromKakao(String token) {
return kakaoClient.getUserInfo(token).kakaoAccount().email();
}

private Item getDefaultProfileItem() {
return itemRepository.findByName("새싹회원").get();
}

private TokenInfoDto issueToken(String email) {
return jwtTokenProvider.generateToken(email);
}

private Member saveUser(
String nickname, String email,
boolean snsAllow, String introduction,
String profileImage, Item titleItem)
{
Member member = Member.create(nickname, email, snsAllow, introduction, profileImage, titleItem);
return memberRepository.save(member);
}

private String getProfileImageFromRequest(List<MultipartFile> images) throws IOException {
String profileImageUrl = null;
if (images != null && !images.get(0).isEmpty()) {
profileImageUrl = uploadProfileImage(images.get(0));
}
return profileImageUrl;
}

}
Loading

0 comments on commit c4f7357

Please sign in to comment.