mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-05-28 21:47:44 +08:00
feat(model): 为 Comment 和 PointHistory 实体添加逻辑删除功能
This commit is contained in:
@@ -5,6 +5,8 @@ import lombok.Getter;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.SQLDelete;
|
||||||
|
import org.hibernate.annotations.Where;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@@ -13,6 +15,8 @@ import java.time.LocalDateTime;
|
|||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Table(name = "comments")
|
@Table(name = "comments")
|
||||||
|
@SQLDelete(sql = "UPDATE comments SET deleted_at = CURRENT_TIMESTAMP(6) WHERE id = ?")
|
||||||
|
@Where(clause = "deleted_at IS NULL")
|
||||||
public class Comment {
|
public class Comment {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@@ -41,4 +45,7 @@ public class Comment {
|
|||||||
@Column
|
@Column
|
||||||
private LocalDateTime pinnedAt;
|
private LocalDateTime pinnedAt;
|
||||||
|
|
||||||
|
@Column(name = "deleted_at")
|
||||||
|
private LocalDateTime deletedAt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import jakarta.persistence.*;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.hibernate.annotations.SQLDelete;
|
||||||
|
import org.hibernate.annotations.Where;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@@ -13,6 +15,8 @@ import java.time.LocalDateTime;
|
|||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Table(name = "point_histories")
|
@Table(name = "point_histories")
|
||||||
|
@SQLDelete(sql = "UPDATE point_histories SET deleted_at = CURRENT_TIMESTAMP(6) WHERE id = ?")
|
||||||
|
@Where(clause = "deleted_at IS NULL")
|
||||||
public class PointHistory {
|
public class PointHistory {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@@ -46,4 +50,7 @@ public class PointHistory {
|
|||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "deleted_at")
|
||||||
|
private LocalDateTime deletedAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.openisle.repository;
|
|||||||
|
|
||||||
import com.openisle.model.PointHistory;
|
import com.openisle.model.PointHistory;
|
||||||
import com.openisle.model.User;
|
import com.openisle.model.User;
|
||||||
|
import com.openisle.model.Comment;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -12,4 +13,6 @@ public interface PointHistoryRepository extends JpaRepository<PointHistory, Long
|
|||||||
long countByUser(User user);
|
long countByUser(User user);
|
||||||
|
|
||||||
List<PointHistory> findByUserAndCreatedAtAfterOrderByCreatedAtDesc(User user, LocalDateTime createdAt);
|
List<PointHistory> findByUserAndCreatedAtAfterOrderByCreatedAtDesc(User user, LocalDateTime createdAt);
|
||||||
|
|
||||||
|
List<PointHistory> findByComment(Comment comment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.openisle.repository.UserRepository;
|
|||||||
import com.openisle.repository.ReactionRepository;
|
import com.openisle.repository.ReactionRepository;
|
||||||
import com.openisle.repository.CommentSubscriptionRepository;
|
import com.openisle.repository.CommentSubscriptionRepository;
|
||||||
import com.openisle.repository.NotificationRepository;
|
import com.openisle.repository.NotificationRepository;
|
||||||
|
import com.openisle.repository.PointHistoryRepository;
|
||||||
import com.openisle.service.NotificationService;
|
import com.openisle.service.NotificationService;
|
||||||
import com.openisle.service.SubscriptionService;
|
import com.openisle.service.SubscriptionService;
|
||||||
import com.openisle.model.Role;
|
import com.openisle.model.Role;
|
||||||
@@ -37,6 +38,7 @@ public class CommentService {
|
|||||||
private final ReactionRepository reactionRepository;
|
private final ReactionRepository reactionRepository;
|
||||||
private final CommentSubscriptionRepository commentSubscriptionRepository;
|
private final CommentSubscriptionRepository commentSubscriptionRepository;
|
||||||
private final NotificationRepository notificationRepository;
|
private final NotificationRepository notificationRepository;
|
||||||
|
private final PointHistoryRepository pointHistoryRepository;
|
||||||
private final ImageUploader imageUploader;
|
private final ImageUploader imageUploader;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -235,10 +237,14 @@ public class CommentService {
|
|||||||
for (Comment c : replies) {
|
for (Comment c : replies) {
|
||||||
deleteCommentCascade(c);
|
deleteCommentCascade(c);
|
||||||
}
|
}
|
||||||
|
// 逻辑删除相关的积分历史记录
|
||||||
|
pointHistoryRepository.findByComment(comment).forEach(pointHistoryRepository::delete);
|
||||||
|
// 删除其他相关数据
|
||||||
reactionRepository.findByComment(comment).forEach(reactionRepository::delete);
|
reactionRepository.findByComment(comment).forEach(reactionRepository::delete);
|
||||||
commentSubscriptionRepository.findByComment(comment).forEach(commentSubscriptionRepository::delete);
|
commentSubscriptionRepository.findByComment(comment).forEach(commentSubscriptionRepository::delete);
|
||||||
notificationRepository.deleteAll(notificationRepository.findByComment(comment));
|
notificationRepository.deleteAll(notificationRepository.findByComment(comment));
|
||||||
imageUploader.removeReferences(imageUploader.extractUrls(comment.getContent()));
|
imageUploader.removeReferences(imageUploader.extractUrls(comment.getContent()));
|
||||||
|
// 逻辑删除评论
|
||||||
commentRepository.delete(comment);
|
commentRepository.delete(comment);
|
||||||
log.debug("deleteCommentCascade removed comment {}", comment.getId());
|
log.debug("deleteCommentCascade removed comment {}", comment.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- Add logical delete support for comments and point_histories tables
|
||||||
|
|
||||||
|
-- Add deleted_at column to comments table
|
||||||
|
ALTER TABLE comments ADD COLUMN deleted_at DATETIME(6) NULL;
|
||||||
|
|
||||||
|
-- Add deleted_at column to point_histories table
|
||||||
|
ALTER TABLE point_histories ADD COLUMN deleted_at DATETIME(6) NULL;
|
||||||
|
|
||||||
|
-- Add index for better performance on logical delete queries
|
||||||
|
CREATE INDEX idx_comments_deleted_at ON comments(deleted_at);
|
||||||
|
CREATE INDEX idx_point_histories_deleted_at ON point_histories(deleted_at);
|
||||||
@@ -6,6 +6,7 @@ import com.openisle.repository.UserRepository;
|
|||||||
import com.openisle.repository.ReactionRepository;
|
import com.openisle.repository.ReactionRepository;
|
||||||
import com.openisle.repository.CommentSubscriptionRepository;
|
import com.openisle.repository.CommentSubscriptionRepository;
|
||||||
import com.openisle.repository.NotificationRepository;
|
import com.openisle.repository.NotificationRepository;
|
||||||
|
import com.openisle.repository.PointHistoryRepository;
|
||||||
import com.openisle.exception.RateLimitException;
|
import com.openisle.exception.RateLimitException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -24,10 +25,11 @@ class CommentServiceTest {
|
|||||||
ReactionRepository reactionRepo = mock(ReactionRepository.class);
|
ReactionRepository reactionRepo = mock(ReactionRepository.class);
|
||||||
CommentSubscriptionRepository subRepo = mock(CommentSubscriptionRepository.class);
|
CommentSubscriptionRepository subRepo = mock(CommentSubscriptionRepository.class);
|
||||||
NotificationRepository nRepo = mock(NotificationRepository.class);
|
NotificationRepository nRepo = mock(NotificationRepository.class);
|
||||||
|
PointHistoryRepository pointHistoryRepo = mock(PointHistoryRepository.class);
|
||||||
ImageUploader imageUploader = mock(ImageUploader.class);
|
ImageUploader imageUploader = mock(ImageUploader.class);
|
||||||
|
|
||||||
CommentService service = new CommentService(commentRepo, postRepo, userRepo,
|
CommentService service = new CommentService(commentRepo, postRepo, userRepo,
|
||||||
notifService, subService, reactionRepo, subRepo, nRepo, imageUploader);
|
notifService, subService, reactionRepo, subRepo, nRepo, pointHistoryRepo, imageUploader);
|
||||||
|
|
||||||
when(commentRepo.countByAuthorAfter(eq("alice"), any())).thenReturn(3L);
|
when(commentRepo.countByAuthorAfter(eq("alice"), any())).thenReturn(3L);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user