Skip to content

Commit a17010e

Browse files
Merge pull request #164 from TeamLearningFlow/develop
user 삭제 기능 구현
2 parents 3a7cda8 + c1a6b2a commit a17010e

6 files changed

Lines changed: 89 additions & 3 deletions

File tree

src/main/java/learningFlow/learningFlow_BE/apiPayload/code/status/ErrorStatus.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public enum ErrorStatus implements BaseErrorCode {
3030

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

3435
// 비밀번호 관련 에러 추가
3536
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "PASSWORD4001", "유효하지 않은 비밀번호입니다."),

src/main/java/learningFlow/learningFlow_BE/repository/MemoRepository.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import learningFlow.learningFlow_BE.domain.Memo;
44
import learningFlow.learningFlow_BE.domain.MemoId;
55
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Modifying;
67
import org.springframework.data.jpa.repository.Query;
78
import org.springframework.data.repository.query.Param;
89

@@ -11,4 +12,8 @@
1112
public interface MemoRepository extends JpaRepository<Memo, MemoId> {
1213
@Query("SELECT m FROM Memo m WHERE m.id.collectionEpisodeId = :episodeId")
1314
Optional<Memo> findByEpisodeId(@Param("episodeId") Long episodeId);
14-
}
15+
16+
@Modifying
17+
@Query("DELETE FROM Memo m WHERE m.id.userId = :loginId")
18+
void deleteAllByUserId(@Param("loginId") String loginId);
19+
}

src/main/java/learningFlow/learningFlow_BE/repository/UserCollectionRepository.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@
33
import learningFlow.learningFlow_BE.domain.Collection;
44
import learningFlow.learningFlow_BE.domain.User;
55
import learningFlow.learningFlow_BE.domain.UserCollection;
6-
import org.springframework.data.jpa.repository.JpaRepository;
76
import learningFlow.learningFlow_BE.domain.enums.UserCollectionStatus;
7+
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.Modifying;
9+
import org.springframework.data.jpa.repository.Query;
10+
import org.springframework.data.repository.query.Param;
11+
812
import java.util.List;
913
import java.util.Optional;
1014

1115
public interface UserCollectionRepository extends JpaRepository<UserCollection, Long> {
1216
Optional<UserCollection> findByUserAndCollection(User user, Collection collection);
1317
List<UserCollection> findByUserAndStatusOrderByCompletedTimeDesc(User user, UserCollectionStatus status);
1418
Optional<UserCollection> findFirstByUserAndStatusOrderByUpdatedAtDesc(User user, UserCollectionStatus status);
19+
20+
@Modifying
21+
@Query("DELETE FROM UserCollection uc WHERE uc.user.loginId = :loginId")
22+
void deleteAllByUserId(@Param("loginId") String loginId);
1523
}

src/main/java/learningFlow/learningFlow_BE/repository/UserEpisodeProgressRepository.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
import learningFlow.learningFlow_BE.domain.UserEpisodeProgress;
44
import learningFlow.learningFlow_BE.domain.UserEpisodeProgressId;
55
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Modifying;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
69

710
public interface UserEpisodeProgressRepository extends JpaRepository<UserEpisodeProgress, UserEpisodeProgressId> {
8-
}
11+
@Modifying
12+
@Query("DELETE FROM UserEpisodeProgress uep WHERE uep.id.userId = :loginId")
13+
void deleteAllByUserId(@Param("loginId") String loginId);
14+
}

src/main/java/learningFlow/learningFlow_BE/service/user/UserService.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import learningFlow.learningFlow_BE.domain.Collection;
1111
import learningFlow.learningFlow_BE.domain.enums.UserCollectionStatus;
1212
import learningFlow.learningFlow_BE.domain.uuid.UuidRepository;
13+
import learningFlow.learningFlow_BE.repository.MemoRepository;
1314
import learningFlow.learningFlow_BE.repository.UserCollectionRepository;
1415
import learningFlow.learningFlow_BE.repository.UserEpisodeProgressRepository;
1516
import learningFlow.learningFlow_BE.repository.UserRepository;
@@ -43,6 +44,7 @@ public class UserService {
4344
private final UuidRepository uuidRepository;
4445
private final CollectionService collectionService;
4546
private final UserEpisodeProgressRepository userEpisodeProgressRepository;
47+
private final MemoRepository memoRepository;
4648

4749
private static final int BOOKMARK_PAGE_SIZE = 8;
4850

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

239241
return UserConverter.convertToUserMyPageResponseDTO(user, recentlyWatchedEpisodeDTOList, completedCollectionList);
240242
}
243+
244+
@Transactional
245+
public void withdrawUser(String loginId) {
246+
User user = userRepository.findById(loginId)
247+
.orElseThrow(() -> new UserHandler(ErrorStatus.USER_NOT_FOUND));
248+
249+
try {
250+
// 유저의 메모 삭제
251+
memoRepository.deleteAllByUserId(loginId);
252+
253+
// 유저의 학습 진도 삭제
254+
userEpisodeProgressRepository.deleteAllByUserId(loginId);
255+
256+
// 유저의 컬렉션 관계 삭제
257+
userCollectionRepository.deleteAllByUserId(loginId);
258+
259+
// 유저 완전 삭제
260+
userRepository.delete(user);
261+
262+
} catch (Exception e) {
263+
throw new UserHandler(ErrorStatus.WITHDRAWAL_FAILED);
264+
}
265+
}
266+
241267
}

src/main/java/learningFlow/learningFlow_BE/web/controller/UserRestController.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,44 @@ public ApiResponse<String> goChangeEmail(
279279
EmailVerificationToken verificationToken = localUserAuthService.validateRegistrationToken(emailResetCode);
280280
return ApiResponse.onSuccess(localUserAuthService.changeEmail(verificationToken));
281281
}
282+
283+
@DeleteMapping("/withdraw")
284+
@Operation(summary = "회원 탈퇴 API", description = """
285+
회원 탈퇴를 처리합니다.
286+
287+
[처리 내용]
288+
- 계정 영구 삭제
289+
- 모든 개인 데이터 삭제
290+
* 학습 데이터
291+
* 메모
292+
* 북마크
293+
* 프로필 정보
294+
295+
[주의사항]
296+
- 탈퇴 후 데이터 복구 불가능
297+
- 탈퇴 후 동일 이메일로 새로운 계정 생성 가능
298+
""")
299+
@ApiResponses({
300+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
301+
responseCode = "200",
302+
description = "탈퇴 성공"
303+
),
304+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
305+
responseCode = "401",
306+
description = "로그인이 필요한 서비스입니다.",
307+
content = @Content(schema = @Schema(implementation = ApiResponse.class))
308+
),
309+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
310+
responseCode = "500",
311+
description = "계정 탈퇴 처리 중 오류가 발생했습니다.",
312+
content = @Content(schema = @Schema(implementation = ApiResponse.class))
313+
)
314+
})
315+
public ApiResponse<String> withdrawUser(
316+
@AuthenticationPrincipal PrincipalDetails principalDetails
317+
) {
318+
userService.withdrawUser(principalDetails.getUser().getLoginId());
319+
return ApiResponse.onSuccess("회원 탈퇴가 완료되었습니다.");
320+
}
321+
282322
}

0 commit comments

Comments
 (0)