Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,23 @@ public MyPageDto getMemberInfo(Long memberId){
MemberEntity member = memberRepository.findById(memberId)
.orElseThrow(() -> new EntityNotFoundException("Member Not Found"));

// 탈퇴한 회원인지 확인
if (member.isDeleted()) {
throw new IllegalStateException("탈퇴한 회원입니다.");
}

return new MyPageDto(member.getId(), member.getNickname(), member.getEmail());
}

public MyPageDto updateMemberInfo(Long memberId, String nickName, String email){
MemberEntity member = memberRepository.findById(memberId)
.orElseThrow(() -> new EntityNotFoundException("Member Not Found"));

// 탈퇴한 회원인지 확인
if (member.isDeleted()) {
throw new IllegalStateException("탈퇴한 회원입니다.");
}

member.updateByMyPage(nickName, email);
memberRepository.save(member);

Expand All @@ -36,6 +46,8 @@ public void deleteMemberInfo(Long memberId){
MemberEntity member = memberRepository.findById(memberId)
.orElseThrow(() -> new EntityNotFoundException("Member Not Found"));

memberRepository.delete(member);
// Soft Delete: 회원 탈퇴 처리
member.withdraw();
memberRepository.save(member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.LifeMaster_BE.Exception.CustomException.MemberSuspendedException;
import com.example.LifeMaster_BE.UserManager.Member.MemberEntity;
import com.example.LifeMaster_BE.UserManager.Member.MemberRepository;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -24,7 +25,8 @@ public class CustomUserDetailService implements UserDetailsService {
@Override
public CustomUserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

MemberEntity member = memberRepository.findByEmail(email)
// 탈퇴하지 않은 회원만 조회
MemberEntity member = memberRepository.findByEmailAndMemberStatusNot(email, MemberStatus.DELETED)
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + email));

// 정지 상태 체크
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.LifeMaster_BE.UserManager.Member.MemberEntity;
import com.example.LifeMaster_BE.UserManager.Member.MemberRepository;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -25,8 +26,10 @@ public Boolean login(String email, String password) {
}

private boolean checkPassword(String email, String password) {
MemberEntity memberEntity = memberRepository.findByEmail(email)
// 탈퇴하지 않은 회원만 조회
MemberEntity memberEntity = memberRepository.findByEmailAndMemberStatusNot(email, MemberStatus.DELETED)
.orElseThrow(() -> new EntityNotFoundException("사용자를 찾을 수 없습니다."));

BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

return bCryptPasswordEncoder.matches(password, memberEntity.getPassword());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.LifeMaster_BE.UserManager.Member.MemberEntity;
import com.example.LifeMaster_BE.UserManager.Member.MemberRepository;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;
import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
Expand All @@ -20,7 +21,8 @@ public class PasswordService {
private final TokenService tokenService;

public void sendPasswordResetEmail(String email) {
MemberEntity memberEntity = memberRepository.findByEmail(email)
// 탈퇴하지 않은 회원만 조회
MemberEntity memberEntity = memberRepository.findByEmailAndMemberStatusNot(email, MemberStatus.DELETED)
.orElseThrow(() -> new EntityNotFoundException("존재하지 않는 이메일 정보입니다."));

String code = tokenService.createVerificationCode(email, memberEntity.getId());
Expand Down Expand Up @@ -56,6 +58,11 @@ public void resetPassword(String token, String newPassword, String checkPassword
MemberEntity memberEntity = memberRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException("Invalid member"));

// 탈퇴한 회원인지 확인
if (memberEntity.isDeleted()) {
throw new IllegalStateException("탈퇴한 회원입니다.");
}

BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String hashedPassword = bCryptPasswordEncoder.encode(newPassword);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.example.LifeMaster_BE.UserManager.Member.LoginType;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;

import java.io.IOException;
import java.time.Duration;
Expand Down Expand Up @@ -80,7 +81,8 @@ public Long registerMemberWithNickname(String regId, String nickname, MultipartF
}

public boolean checkNicknameAvailable(String nickname){
return memberRepository.existsByNickname(nickname);
// 탈퇴하지 않은 회원 중에서 닉네임 중복 체크
return memberRepository.existsByNicknameAndMemberStatusNot(nickname, MemberStatus.DELETED);
}

private void checkBeforeRegister(String email, String password, String confirmPassword){
Expand All @@ -94,7 +96,8 @@ private void checkBeforeRegister(String email, String password, String confirmPa
}

private boolean checkEmailDuplicate(String email){
return memberRepository.existsByEmail(email);
// 탈퇴하지 않은 회원 중에서 이메일 중복 체크
return memberRepository.existsByEmailAndMemberStatusNot(email, MemberStatus.DELETED);
}

private boolean confirmPassword(String password, String confirmPassword){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ public class MemberEntity {
@CreatedDate
private LocalDateTime createdAt;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;

// Many-to-Many 관계 추가
@ManyToMany
@JsonIgnore
Expand Down Expand Up @@ -245,4 +248,15 @@ public boolean isSuspended() {
}
return false;
}

// 회원 탈퇴 관련 메서드
public void withdraw() {
this.memberStatus = MemberStatus.DELETED;
this.loginStatus = false;
this.deletedAt = LocalDateTime.now();
}

public boolean isDeleted() {
return this.memberStatus == MemberStatus.DELETED;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public interface MemberRepository extends JpaRepository<MemberEntity, Long> {
boolean existsByNickname(String nickname);
boolean existsByEmail(String Email);

// 탈퇴하지 않은 회원 조회 메서드 (일반 사용자용)
boolean existsByNicknameAndMemberStatusNot(String nickname, MemberStatus status);
boolean existsByEmailAndMemberStatusNot(String email, MemberStatus status);
Optional<MemberEntity> findByEmailAndMemberStatusNot(String email, MemberStatus status);

// 기존 메서드 (관리자용 - 탈퇴 회원 포함)
Optional<MemberEntity> findByEmail(String email);
@Query("SELECT m.email FROM MemberEntity m WHERE m.id = :id")
Optional<String> findEmailById(@Param("id") Long id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import com.example.LifeMaster_BE.UserManager.Member.LoginType;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;

import java.time.Instant;
import java.util.*;
Expand Down Expand Up @@ -173,7 +174,8 @@ public GoogleOAuth2AuthenticationResponse handleOAuth2AuthenticationGoogle(Strin
MemberEntity member = new MemberEntity(user.getEmail(), user.getIdentifier());
member.setLoginType(LoginType.GOOGLE);

Optional<MemberEntity> existing = memberRepository.findByEmail(user.getEmail());
// 탈퇴하지 않은 회원만 조회
Optional<MemberEntity> existing = memberRepository.findByEmailAndMemberStatusNot(user.getEmail(), MemberStatus.DELETED);

if (existing.isEmpty()) {
String baseNickname = resolveNickname(
Expand Down Expand Up @@ -237,7 +239,8 @@ public GoogleOAuth2AuthenticationResponse handleOAuth2AuthenticationNaver(String
MemberEntity member = new MemberEntity(user.getEmail(),user.getIdentifier());
member.setLoginType(LoginType.NAVER);

Optional<MemberEntity> existing = memberRepository.findByEmail(user.getEmail());
// 탈퇴하지 않은 회원만 조회
Optional<MemberEntity> existing = memberRepository.findByEmailAndMemberStatusNot(user.getEmail(), MemberStatus.DELETED);

if (existing.isEmpty()) {
String baseNickname = resolveNickname(
Expand Down Expand Up @@ -454,7 +457,8 @@ private OAuthUsersEntity saveOrUpdate(OAuthUsersEntity usersEntity) {
}

private MemberEntity saveOrUpdateMember(MemberEntity usersEntity) {
MemberEntity user = memberRepository.findByEmail(usersEntity.getEmail())
// 탈퇴하지 않은 회원만 조회
MemberEntity user = memberRepository.findByEmailAndMemberStatusNot(usersEntity.getEmail(), MemberStatus.DELETED)
.map(entity -> entity.updateOAuthInfo(
usersEntity.getPicture(),
usersEntity.getNickname(),
Expand All @@ -474,7 +478,8 @@ private String generateUniqueNickname(String baseNickname) {
String nickname = baseNickname;
int suffix = 1;

while (memberRepository.existsByNickname(nickname)) {
// 탈퇴하지 않은 회원 중에서 닉네임 중복 체크
while (memberRepository.existsByNicknameAndMemberStatusNot(nickname, MemberStatus.DELETED)) {
nickname = baseNickname + "_" + suffix++;
}
return nickname;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.LifeMaster_BE.UserManager.Member.LoginType;
import com.example.LifeMaster_BE.UserManager.Member.MemberEntity;
import com.example.LifeMaster_BE.UserManager.Member.MemberRepository;
import com.example.LifeMaster_BE.UserManager.Member.MemberStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -47,8 +48,8 @@ public ResponseEntity<?> kakaoCallback(@RequestParam String code) {
return ResponseEntity.status(400).body(Map.of("message", "사용자 이메일이 없습니다."));
}

// 3. DB 조회 혹은 신규 생성
MemberEntity user = memberRepository.findByEmail(email).orElseGet(() -> {
// 3. DB 조회 혹은 신규 생성 (탈퇴하지 않은 회원만)
MemberEntity user = memberRepository.findByEmailAndMemberStatusNot(email, MemberStatus.DELETED).orElseGet(() -> {
MemberEntity newUser = MemberEntity.builder()
.email(email)
.nickname(nickname)
Expand Down Expand Up @@ -85,7 +86,8 @@ public ResponseEntity<?> refreshAccessToken(@RequestParam String refreshToken) {
// JwtUtil로 email 추출
String email = jwtUtil.extractEmail(refreshToken);

MemberEntity user = memberRepository.findByEmail(email)
// 탈퇴하지 않은 회원만 조회
MemberEntity user = memberRepository.findByEmailAndMemberStatusNot(email, MemberStatus.DELETED)
.orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다: " + email));

String newAccessToken = jwtUtil.generateToken(user.getEmail());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ void deleteMemberInfo_success(){

myPageService.deleteMemberInfo(memberId);

verify(memberRepository).delete(member);
// Soft delete이므로 save() 호출됨
verify(memberRepository).save(member);
}

@Test
Expand Down
Loading