Skip to content
Merged
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 @@ -37,11 +37,17 @@ public LoginResponseDto socialLogin(String providerId, String email) {
.providerId(providerId)
.nickname("유저" + providerId)
.email(email)
.isActive(true)
.build()
));

boolean isNewUser = user.getCreatedAt() != null &&
// 탈퇴한 회원이 다시 로그인하는 경우 계정 복구
boolean isReturningUser = false;
if (user.isWithdrawn()) {
user.reactivate();
isReturningUser = true;
}

boolean isNewUser = !isReturningUser && user.getCreatedAt() != null &&
user.getUpdatedAt() != null &&
user.getCreatedAt().equals(user.getUpdatedAt());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.comma.soomteum.domain.token.repository;

import com.comma.soomteum.domain.token.entity.Token;
import com.comma.soomteum.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;


public interface TokenRepository extends JpaRepository<Token, Long> {
Optional<Token> findByRefreshToken(String refreshToken);
void deleteByUser(User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.comma.soomteum.domain.user.entity.User;
import com.comma.soomteum.domain.user.dto.UserNicknameRequestDto;
import com.comma.soomteum.domain.user.dto.UserProfileResponseDto;
import com.comma.soomteum.domain.user.dto.UserWithdrawResponseDto;
import com.comma.soomteum.domain.user.service.UserService;
import com.comma.soomteum.global.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -35,4 +36,10 @@ public ApiResponse<UserProfileResponseDto> getUserProfile(@Parameter(hidden = tr
public ApiResponse<UserProfileResponseDto> updateNickname(@Parameter(hidden = true) @LoginUser User user, @Valid @RequestBody UserNicknameRequestDto userNicknameRequestDto) {
return ApiResponse.ok(userService.updateNickname(user.getUserId(), userNicknameRequestDto));
}

@Operation(summary = "회원 탈퇴", description = "사용자의 계정을 탈퇴 처리합니다.")
@PatchMapping("/withdraw")
public ApiResponse<UserWithdrawResponseDto> withdrawUser(@Parameter(hidden = true) @LoginUser User user) {
return ApiResponse.ok(userService.withdrawUser(user.getUserId()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.comma.soomteum.domain.user.dto;

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

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserWithdrawResponseDto {

private String message;

public static UserWithdrawResponseDto of() {
return UserWithdrawResponseDto.builder()
.message("회원 탈퇴가 완료되었습니다.")
.build();
}
}
21 changes: 20 additions & 1 deletion src/main/java/com/comma/soomteum/domain/user/entity/User.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.comma.soomteum.domain.user.entity;

import com.comma.soomteum.domain.BaseEntity;
import com.comma.soomteum.domain.user.enums.UserStatus;
import jakarta.persistence.*;
import lombok.*;

Expand All @@ -24,9 +25,27 @@ public class User extends BaseEntity {

private String email;

private Boolean isActive;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserStatus status = UserStatus.ACTIVE;

public void updateNickname(String nickname) {
this.nickname = nickname;
}

public void withdraw() {
this.status = UserStatus.WITHDRAWN;
}

public void reactivate() {
this.status = UserStatus.ACTIVE;
}

public boolean isWithdrawn() {
return this.status == UserStatus.WITHDRAWN;
}

public boolean isActive() {
return this.status == UserStatus.ACTIVE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.comma.soomteum.domain.user.enums;

public enum UserStatus {
ACTIVE, // 활성 회원
WITHDRAWN // 탈퇴 회원
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.comma.soomteum.domain.user.service;

import com.comma.soomteum.domain.token.repository.TokenRepository;
import com.comma.soomteum.domain.user.dto.UserNicknameRequestDto;
import com.comma.soomteum.domain.user.dto.UserProfileResponseDto;
import com.comma.soomteum.domain.user.dto.UserWithdrawResponseDto;
import com.comma.soomteum.domain.user.entity.User;
import com.comma.soomteum.domain.user.repository.UserRepository;
import com.comma.soomteum.global.response.CustomException;
Expand All @@ -16,6 +18,7 @@
public class UserService {

private final UserRepository userRepository;
private final TokenRepository tokenRepository;

/**
* 마이페이지 - 이메일, 닉네임 조회
Expand All @@ -36,4 +39,26 @@ public UserProfileResponseDto updateNickname(Long userId, UserNicknameRequestDto
user.updateNickname(userNicknameRequestDto.getNickname());
return UserProfileResponseDto.fromEntity(user);
}

/**
* 회원 탈퇴
**/
@Transactional
public UserWithdrawResponseDto withdrawUser(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));

// 이미 탈퇴한 회원인지 확인
if (user.isWithdrawn()) {
throw new CustomException(ErrorCode.ALREADY_WITHDRAWN_USER);
}

// 해당 사용자의 모든 토큰 삭제
tokenRepository.deleteByUser(user);

// 회원 상태를 탈퇴로 변경 (isActive = null)
user.withdraw();

return UserWithdrawResponseDto.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public enum ErrorCode {
DUPLICATE_EMAIL(409_001, HttpStatus.CONFLICT, "이미 사용 중인 이메일입니다."),
ALREADY_LIKED_PLACE(409_002, HttpStatus.CONFLICT, "이미 좋아요를 누른 장소입니다."),
NOT_LIKED_PLACE(409_003, HttpStatus.CONFLICT, "좋아요를 누르지 않은 장소입니다."),
ALREADY_WITHDRAWN_USER(409_004, HttpStatus.CONFLICT, "이미 탈퇴한 회원입니다."),


// ========================
Expand Down