Repository navigation
fix: 외래키로 인해 물리적 탈퇴가 되지 않는 문제 수정 #848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| package com.example.solidconnection.scheduler; | ||
|
|
||
| import com.example.solidconnection.application.repository.ApplicationRepository; | ||
| import com.example.solidconnection.chat.repository.ChatMessageRepository; | ||
| import com.example.solidconnection.chat.repository.ChatParticipantRepository; | ||
| import com.example.solidconnection.chat.repository.ChatReadStatusRepository; | ||
| import com.example.solidconnection.chat.repository.ChatRoomRepository; | ||
| import com.example.solidconnection.community.comment.repository.CommentRepository; | ||
| import com.example.solidconnection.community.post.repository.PostLikeRepository; | ||
| import com.example.solidconnection.community.post.repository.PostRepository; | ||
|
|
@@ -19,6 +21,7 @@ | |
| import com.example.solidconnection.score.repository.LanguageTestScoreRepository; | ||
| import com.example.solidconnection.siteuser.domain.SiteUser; | ||
| import com.example.solidconnection.siteuser.repository.SiteUserRepository; | ||
| import com.example.solidconnection.siteuser.repository.UserBanRepository; | ||
| import com.example.solidconnection.siteuser.repository.UserBlockRepository; | ||
| import com.example.solidconnection.university.repository.LikedUnivApplyInfoRepository; | ||
| import java.time.LocalDate; | ||
|
|
@@ -49,10 +52,13 @@ public class UserRemovalScheduler { | |
| private final MentoringRepository mentoringRepository; | ||
| private final NewsRepository newsRepository; | ||
| private final LikedNewsRepository likedNewsRepository; | ||
| private final ChatRoomRepository chatRoomRepository; | ||
| private final ChatParticipantRepository chatParticipantRepository; | ||
| private final ChatMessageRepository chatMessageRepository; | ||
| private final ChatReadStatusRepository chatReadStatusRepository; | ||
| private final ReportRepository reportRepository; | ||
| private final UserBlockRepository userBlockRepository; | ||
| private final UserBanRepository userBanRepository; | ||
| private final MentorApplicationRepository mentorApplicationRepository; | ||
| private final S3Service s3Service; | ||
|
|
||
|
|
@@ -72,21 +78,19 @@ private void deleteUserAndRelatedData(SiteUser user) { | |
| long siteUserId = user.getId(); | ||
|
|
||
| likedNewsRepository.deleteAllBySiteUserId(siteUserId); | ||
| newsRepository.deleteAllBySiteUserId(siteUserId); | ||
| deleteNews(siteUserId); | ||
|
|
||
| postLikeRepository.deleteAllBySiteUserId(siteUserId); | ||
| commentRepository.deleteAllBySiteUserId(siteUserId); | ||
| postRepository.deleteAllBySiteUserId(siteUserId); | ||
| deletePosts(siteUserId); | ||
|
|
||
| mentoringRepository.deleteAllByMenteeId(siteUserId); | ||
| mentorRepository.deleteAllBySiteUserId(siteUserId); | ||
| deleteChatData(siteUserId); | ||
| deleteMentorings(siteUserId); | ||
| mentorApplicationRepository.deleteAllBySiteUserId(siteUserId); | ||
|
|
||
| List<Long> chatParticipantIds = chatParticipantRepository.findAllIdsBySiteUserId(siteUserId); | ||
| chatReadStatusRepository.deleteAllByChatParticipantIdIn(chatParticipantIds); | ||
| chatParticipantRepository.deleteAllBySiteUserId(siteUserId); | ||
| reportRepository.deleteAllByReporterId(siteUserId); | ||
| userBlockRepository.deleteAllByBlockerIdOrBlockedId(siteUserId, siteUserId); | ||
| deleteUserBans(siteUserId); | ||
|
|
||
| applicationRepository.deleteAllBySiteUserId(siteUserId); | ||
| gpaScoreRepository.deleteAllBySiteUserId(siteUserId); | ||
|
|
@@ -99,4 +103,83 @@ private void deleteUserAndRelatedData(SiteUser user) { | |
|
|
||
| siteUserRepository.delete(user); | ||
| } | ||
|
|
||
| /* | ||
| * 다른 사용자가 누른 좋아요가 남아 있으면 뉴스를 삭제할 수 없으므로 함께 삭제한다. | ||
| * */ | ||
| private void deleteNews(long siteUserId) { | ||
| List<Long> newsIds = newsRepository.findAllIdsBySiteUserId(siteUserId); | ||
| if (!newsIds.isEmpty()) { | ||
| likedNewsRepository.deleteAllByNewsIdIn(newsIds); | ||
| } | ||
| newsRepository.deleteAllBySiteUserId(siteUserId); | ||
| } | ||
|
|
||
| /* | ||
| * 신고로 가려진 게시글은 조회 필터에 걸려 삭제되지 않으므로, 플래그를 되돌린 뒤 삭제한다. | ||
| * */ | ||
| private void deletePosts(long siteUserId) { | ||
| postRepository.unmarkDeletedBySiteUserId(siteUserId); | ||
| postRepository.deleteAllBySiteUserId(siteUserId); | ||
| } | ||
|
|
||
| /* | ||
| * 신고로 가려진 메시지는 조회 필터에 걸리므로, 플래그를 되돌린 뒤 삭제한다. | ||
| * 채팅방이 멘토링을 참조하므로 멘토링보다 먼저 삭제한다. | ||
| * */ | ||
| private void deleteChatData(long siteUserId) { | ||
| deleteOneOnOneChatRooms(siteUserId); | ||
| deleteGroupChatParticipation(siteUserId); | ||
| } | ||
|
|
||
| /* | ||
| * 1:1 채팅방은 참여자 한 명이 사라지면 유지될 수 없으므로 방 전체를 삭제한다. | ||
| * */ | ||
| private void deleteOneOnOneChatRooms(long siteUserId) { | ||
| List<Long> chatRoomIds = chatParticipantRepository.findAllChatRoomIdsBySiteUserIdAndIsGroup(siteUserId, false); | ||
| if (chatRoomIds.isEmpty()) { | ||
| return; | ||
| } | ||
| chatMessageRepository.unmarkDeletedByChatRoomIdIn(chatRoomIds); | ||
| chatMessageRepository.deleteAllByChatRoomIdIn(chatRoomIds); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a deleted room contains files uploaded through the chat upload endpoint, this call cascades removal of the Useful? React with 👍 / 👎. |
||
| chatReadStatusRepository.deleteAllByChatRoomIdIn(chatRoomIds); | ||
| chatParticipantRepository.deleteAllByChatRoomIdIn(chatRoomIds); | ||
| chatRoomRepository.deleteAllById(chatRoomIds); | ||
|
whqtker marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /* | ||
| * 그룹 채팅방은 남은 참여자들의 대화가 유지되어야 하므로 탈퇴자의 참여 기록만 삭제한다. | ||
| * */ | ||
| private void deleteGroupChatParticipation(long siteUserId) { | ||
| List<Long> chatParticipantIds = chatParticipantRepository.findAllIdsBySiteUserIdAndIsGroup(siteUserId, true); | ||
| if (chatParticipantIds.isEmpty()) { | ||
| return; | ||
| } | ||
| chatMessageRepository.unmarkDeletedBySenderIdIn(chatParticipantIds); | ||
| chatMessageRepository.deleteAllBySenderIdIn(chatParticipantIds); | ||
| chatReadStatusRepository.deleteAllByChatParticipantIdIn(chatParticipantIds); | ||
| chatParticipantRepository.deleteAllById(chatParticipantIds); | ||
| } | ||
|
|
||
| /* | ||
| * 멘티로 참여한 멘토링과 멘토로 참여한 멘토링을 모두 삭제한 뒤 멘토를 삭제한다. | ||
| * */ | ||
| private void deleteMentorings(long siteUserId) { | ||
| mentoringRepository.deleteAllByMenteeId(siteUserId); | ||
| List<Long> mentorIds = mentorRepository.findAllIdsBySiteUserId(siteUserId); | ||
| if (!mentorIds.isEmpty()) { | ||
| mentoringRepository.deleteAllByMentorIdIn(mentorIds); | ||
| } | ||
| mentorRepository.deleteAllBySiteUserId(siteUserId); | ||
| } | ||
|
|
||
| /* | ||
| * 탈퇴자를 대상으로 한 정지 기록은 삭제한다. | ||
| * 탈퇴자가 집행한 정지 기록은 다른 사용자의 이력이므로, 집행자 참조만 해제하고 보존한다. | ||
| * */ | ||
| private void deleteUserBans(long siteUserId) { | ||
| userBanRepository.deleteAllByBannedUserId(siteUserId); | ||
| userBanRepository.clearBannedBy(siteUserId); | ||
| userBanRepository.clearUnbannedBy(siteUserId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ALTER TABLE user_ban | ||
| MODIFY COLUMN banned_by BIGINT NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deleteAllByReporterId는 이 사용자가 "신고한" 기록만 지우는데, 이 사용자가 "신고당한" 기록(report.reported_id = siteUserId)이나 이 사용자의 게시글/채팅메시지를 대상(target_id)으로 한 신고 기록은 그대로 남아 고아 데이터가 발생할 수 있을 것 같습니다!
target_id/reported_id에는 FK가 없어서(ReportRepository, V25__create_report_table.sql 확인) 삭제 자체가 실패하지는 않지만, 대상이 사라진 report 행이 고아 데이터로 계속 쌓이게 됩니다. 이번 PR 범위 밖일 수 있지만 후속으로 reportedId/targetId 기준 정리도 필요해 보입니다.