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 @@ -30,6 +30,7 @@ public enum ErrorStatus implements BaseErrorCode {

USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "USER4001", "사용자를 찾을 수 없습니다."),
NICKNAME_NOT_EXIST(HttpStatus.BAD_REQUEST, "USER4002", "닉네임은 필수 입니다."),
WITHDRAWAL_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "USER5001", "계정 탈퇴 처리 중 오류가 발생했습니다."),

// 비밀번호 관련 에러 추가
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "PASSWORD4001", "유효하지 않은 비밀번호입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import learningFlow.learningFlow_BE.domain.Memo;
import learningFlow.learningFlow_BE.domain.MemoId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

Expand All @@ -11,4 +12,8 @@
public interface MemoRepository extends JpaRepository<Memo, MemoId> {
@Query("SELECT m FROM Memo m WHERE m.id.collectionEpisodeId = :episodeId")
Optional<Memo> findByEpisodeId(@Param("episodeId") Long episodeId);
}

@Modifying
@Query("DELETE FROM Memo m WHERE m.id.userId = :loginId")
void deleteAllByUserId(@Param("loginId") String loginId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
import learningFlow.learningFlow_BE.domain.Collection;
import learningFlow.learningFlow_BE.domain.User;
import learningFlow.learningFlow_BE.domain.UserCollection;
import org.springframework.data.jpa.repository.JpaRepository;
import learningFlow.learningFlow_BE.domain.enums.UserCollectionStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface UserCollectionRepository extends JpaRepository<UserCollection, Long> {
Optional<UserCollection> findByUserAndCollection(User user, Collection collection);
List<UserCollection> findByUserAndStatusOrderByCompletedTimeDesc(User user, UserCollectionStatus status);
Optional<UserCollection> findFirstByUserAndStatusOrderByUpdatedAtDesc(User user, UserCollectionStatus status);

@Modifying
@Query("DELETE FROM UserCollection uc WHERE uc.user.loginId = :loginId")
void deleteAllByUserId(@Param("loginId") String loginId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
import learningFlow.learningFlow_BE.domain.UserEpisodeProgress;
import learningFlow.learningFlow_BE.domain.UserEpisodeProgressId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface UserEpisodeProgressRepository extends JpaRepository<UserEpisodeProgress, UserEpisodeProgressId> {
}
@Modifying
@Query("DELETE FROM UserEpisodeProgress uep WHERE uep.id.userId = :loginId")
void deleteAllByUserId(@Param("loginId") String loginId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import learningFlow.learningFlow_BE.domain.Collection;
import learningFlow.learningFlow_BE.domain.enums.UserCollectionStatus;
import learningFlow.learningFlow_BE.domain.uuid.UuidRepository;
import learningFlow.learningFlow_BE.repository.MemoRepository;
import learningFlow.learningFlow_BE.repository.UserCollectionRepository;
import learningFlow.learningFlow_BE.repository.UserEpisodeProgressRepository;
import learningFlow.learningFlow_BE.repository.UserRepository;
Expand Down Expand Up @@ -43,6 +44,7 @@ public class UserService {
private final UuidRepository uuidRepository;
private final CollectionService collectionService;
private final UserEpisodeProgressRepository userEpisodeProgressRepository;
private final MemoRepository memoRepository;

private static final int BOOKMARK_PAGE_SIZE = 8;

Expand Down Expand Up @@ -238,4 +240,28 @@ public UserResponseDTO.UserMyPageResponseDTO getUserMyPageResponseDTO(String log

return UserConverter.convertToUserMyPageResponseDTO(user, recentlyWatchedEpisodeDTOList, completedCollectionList);
}

@Transactional
public void withdrawUser(String loginId) {
User user = userRepository.findById(loginId)
.orElseThrow(() -> new UserHandler(ErrorStatus.USER_NOT_FOUND));

try {
// 유저의 메모 삭제
memoRepository.deleteAllByUserId(loginId);

// 유저의 학습 진도 삭제
userEpisodeProgressRepository.deleteAllByUserId(loginId);

// 유저의 컬렉션 관계 삭제
userCollectionRepository.deleteAllByUserId(loginId);

// 유저 완전 삭제
userRepository.delete(user);

} catch (Exception e) {
throw new UserHandler(ErrorStatus.WITHDRAWAL_FAILED);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,44 @@ public ApiResponse<String> goChangeEmail(
EmailVerificationToken verificationToken = localUserAuthService.validateRegistrationToken(emailResetCode);
return ApiResponse.onSuccess(localUserAuthService.changeEmail(verificationToken));
}

@DeleteMapping("/withdraw")
@Operation(summary = "회원 탈퇴 API", description = """
회원 탈퇴를 처리합니다.

[처리 내용]
- 계정 영구 삭제
- 모든 개인 데이터 삭제
* 학습 데이터
* 메모
* 북마크
* 프로필 정보

[주의사항]
- 탈퇴 후 데이터 복구 불가능
- 탈퇴 후 동일 이메일로 새로운 계정 생성 가능
""")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "탈퇴 성공"
),
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "401",
description = "로그인이 필요한 서비스입니다.",
content = @Content(schema = @Schema(implementation = ApiResponse.class))
),
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "500",
description = "계정 탈퇴 처리 중 오류가 발생했습니다.",
content = @Content(schema = @Schema(implementation = ApiResponse.class))
)
})
public ApiResponse<String> withdrawUser(
@AuthenticationPrincipal PrincipalDetails principalDetails
) {
userService.withdrawUser(principalDetails.getUser().getLoginId());
return ApiResponse.onSuccess("회원 탈퇴가 완료되었습니다.");
}

}