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 @@ -67,4 +67,22 @@ WHERE cm.id IN (SELECT r.target_id FROM report r WHERE r.target_type = 'CHAT')
AND cm.sender_id IN (SELECT cp.id FROM chat_participant cp WHERE cp.site_user_id IN :siteUserIds)
""", nativeQuery = true)
void bulkUpdateReportedChatMessagesIsDeleted(@Param("siteUserIds") List<Long> siteUserIds, @Param("isDeleted") boolean isDeleted);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(value = """
UPDATE chat_message cm SET cm.is_deleted = false
WHERE cm.chat_room_id IN :chatRoomIds
""", nativeQuery = true)
void unmarkDeletedByChatRoomIdIn(@Param("chatRoomIds") List<Long> chatRoomIds);

void deleteAllByChatRoomIdIn(List<Long> chatRoomIds);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(value = """
UPDATE chat_message cm SET cm.is_deleted = false
WHERE cm.sender_id IN :senderIds
""", nativeQuery = true)
void unmarkDeletedBySenderIdIn(@Param("senderIds") List<Long> senderIds);

void deleteAllBySenderIdIn(List<Long> senderIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,17 @@ public interface ChatParticipantRepository extends JpaRepository<ChatParticipant

Optional<ChatParticipant> findByChatRoomIdAndSiteUserId(long chatRoomId, long siteUserId);

void deleteAllBySiteUserId(long siteUserId);
void deleteAllByChatRoomIdIn(List<Long> chatRoomIds);

@Query("SELECT cp.id FROM ChatParticipant cp WHERE cp.siteUserId = :siteUserId")
List<Long> findAllIdsBySiteUserId(@Param("siteUserId") long siteUserId);
@Query("""
SELECT cp.chatRoom.id FROM ChatParticipant cp
WHERE cp.siteUserId = :siteUserId AND cp.chatRoom.isGroup = :isGroup
""")
List<Long> findAllChatRoomIdsBySiteUserIdAndIsGroup(@Param("siteUserId") long siteUserId, @Param("isGroup") boolean isGroup);

@Query("""
SELECT cp.id FROM ChatParticipant cp
WHERE cp.siteUserId = :siteUserId AND cp.chatRoom.isGroup = :isGroup
""")
List<Long> findAllIdsBySiteUserIdAndIsGroup(@Param("siteUserId") long siteUserId, @Param("isGroup") boolean isGroup);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ INSERT INTO chat_read_status (chat_room_id, chat_participant_id, created_at, upd
""", nativeQuery = true)
void upsertReadStatus(@Param("chatRoomId") long chatRoomId, @Param("chatParticipantId") long chatParticipantId);

void deleteAllByChatRoomIdIn(List<Long> chatRoomIds);

void deleteAllByChatParticipantIdIn(List<Long> chatParticipantIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,12 @@ default Post getById(Long id) {
.orElseThrow(() -> new CustomException(INVALID_POST_ID));
}

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(value = """
UPDATE post p SET p.is_deleted = false
WHERE p.site_user_id = :siteUserId
""", nativeQuery = true)
void unmarkDeletedBySiteUserId(@Param("siteUserId") long siteUserId);

void deleteAllBySiteUserId(long siteUserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ public interface MentorRepository extends JpaRepository<Mentor, Long> {

List<Mentor> findAllBySiteUserIdIn(Set<Long> siteUserIds);

@Query("SELECT m.id FROM Mentor m WHERE m.siteUserId = :siteUserId")
List<Long> findAllIdsBySiteUserId(@Param("siteUserId") long siteUserId);

void deleteAllBySiteUserId(long siteUserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ public interface MentoringRepository extends JpaRepository<Mentoring, Long> {
Slice<Mentoring> findApprovedMentoringsByMenteeId(long menteeId, @Param("verifyStatus") VerifyStatus verifyStatus, Pageable pageable);

void deleteAllByMenteeId(long menteeId);

void deleteAllByMentorIdIn(List<Long> mentorIds);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.solidconnection.news.repository;

import com.example.solidconnection.news.domain.LikedNews;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

Expand All @@ -11,4 +12,6 @@ public interface LikedNewsRepository extends JpaRepository<LikedNews, Long> {
Optional<LikedNews> findByNewsIdAndSiteUserId(long newsId, long siteUserId);

void deleteAllBySiteUserId(long siteUserId);

void deleteAllByNewsIdIn(List<Long> newsIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
import com.example.solidconnection.news.repository.custom.NewsCustomRepository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface NewsRepository extends JpaRepository<News, Long>, NewsCustomRepository {

List<News> findAllByOrderByUpdatedAtDesc();

List<News> findAllBySiteUserIdOrderByUpdatedAtDesc(long siteUserId);

@Query("SELECT n.id FROM News n WHERE n.siteUserId = :siteUserId")
List<Long> findAllIdsBySiteUserId(@Param("siteUserId") long siteUserId);

void deleteAllBySiteUserId(long siteUserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public class Report extends BaseEntity {
@Column(name = "id")
private Long id;

@Column(name = "reporter_id", nullable = false)
private long reporterId;
@Column(name = "reporter_id", nullable = true)
private Long reporterId;

@Column(name = "reported_id", nullable = false)
private long reportedId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
import com.example.solidconnection.report.domain.Report;
import com.example.solidconnection.report.domain.TargetType;
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 ReportRepository extends JpaRepository<Report, Long> {

boolean existsByReporterIdAndTargetTypeAndTargetId(long reporterId, TargetType targetType, long targetId);

boolean existsByReportedId(long reportedId);

void deleteAllByReporterId(long reporterId);
void deleteAllByReportedId(long reportedId);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("UPDATE Report r SET r.reporterId = null WHERE r.reporterId = :siteUserId")
void clearReporter(@Param("siteUserId") long siteUserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ public void deleteExProfile(long siteUserId) {
SiteUser siteUser = siteUserRepository.findById(siteUserId)
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));
String key = siteUser.getProfileImageUrl();
if (key == null || key.isBlank()) {
return;
}
deleteFile(key);
}

Expand Down
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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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);
deleteReports(siteUserId);
userBlockRepository.deleteAllByBlockerIdOrBlockedId(siteUserId, siteUserId);
deleteUserBans(siteUserId);

applicationRepository.deleteAllBySiteUserId(siteUserId);
gpaScoreRepository.deleteAllBySiteUserId(siteUserId);
Expand All @@ -99,4 +103,92 @@ 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);
Comment thread
whqtker marked this conversation as resolved.
}

/*
* 신고로 가려진 게시글은 조회 필터에 걸려 삭제되지 않으므로, 플래그를 되돌린 뒤 삭제한다.
* */
private void deletePosts(long siteUserId) {
postRepository.unmarkDeletedBySiteUserId(siteUserId);
postRepository.deleteAllBySiteUserId(siteUserId);
Comment thread
whqtker marked this conversation as resolved.
}

/*
* 신고로 가려진 메시지는 조회 필터에 걸리므로, 플래그를 되돌린 뒤 삭제한다.
* 채팅방이 멘토링을 참조하므로 멘토링보다 먼저 삭제한다.
* */
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);
Comment thread
whqtker marked this conversation as resolved.
chatReadStatusRepository.deleteAllByChatRoomIdIn(chatRoomIds);
chatParticipantRepository.deleteAllByChatRoomIdIn(chatRoomIds);
chatRoomRepository.deleteAllById(chatRoomIds);
Comment thread
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 deleteReports(long siteUserId) {
reportRepository.deleteAllByReportedId(siteUserId);
reportRepository.clearReporter(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
Expand Up @@ -27,7 +27,7 @@ public class UserBan extends BaseEntity {
@Column(name = "banned_user_id", nullable = false)
private Long bannedUserId;

@Column(name = "banned_by", nullable = false)
@Column(name = "banned_by", nullable = true)
private Long bannedBy;

@Column(name = "duration", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ public interface UserBanRepository extends JpaRepository<UserBan, Long> {
@Modifying
@Query("UPDATE UserBan ub SET ub.isExpired = true WHERE ub.isExpired = false AND ub.expiredAt < :current")
void bulkExpireUserBans(@Param("current") ZonedDateTime current);

void deleteAllByBannedUserId(long bannedUserId);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("UPDATE UserBan ub SET ub.bannedBy = null WHERE ub.bannedBy = :siteUserId")
void clearBannedBy(@Param("siteUserId") long siteUserId);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("UPDATE UserBan ub SET ub.unbannedBy = null WHERE ub.unbannedBy = :siteUserId")
void clearUnbannedBy(@Param("siteUserId") long 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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE report
MODIFY COLUMN reporter_id BIGINT NULL;
Loading