feat(privacy): add user privacy settings and account deletion system
All checks were successful
Build Backend / build (push) Successful in 5m16s
Build Backend / build-docker (push) Successful in 3m44s

Add privacy settings allowing users to control visibility of their followers, following, posts, and favorites lists with three visibility levels: everyone, following, and self. Also implement account deletion workflow with 30-day cooldown period.

- Add PrivacySettings model with visibility levels
- Add DTOs for privacy settings and account deletion
- Add repository methods for privacy settings and deletion
- Add service methods to check visibility permissions
- Add handlers for get/update privacy settings and account deletion
- Add new routes for privacy settings and account management
- Add account cleanup service for hard-deleting expired accounts
- Modify login to cancel deletion when user logs in

BREAKING CHANGE: Users with pending_deletion status can no longer log in; logging in now automatically cancels deletion requests.
This commit is contained in:
lafay
2026-04-08 14:55:50 +08:00
parent 9440df66ba
commit 539bec6f63
9 changed files with 642 additions and 76 deletions

View File

@@ -3,6 +3,7 @@ package repository
import (
"carrot_bbs/internal/model"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
@@ -43,6 +44,16 @@ type UserRepository interface {
AdminList(page, pageSize int, keyword, status string) ([]*model.User, int64, error)
GetCommentsCount(userID string) (int64, error)
UpdateStatus(userID string, status model.UserStatus) error
// 隐私设置
UpdatePrivacySettings(userID string, settings *model.PrivacySettings) error
GetPrivacySettings(userID string) (*model.PrivacySettings, error)
// 账号注销
RequestDeletion(userID string) error
CancelDeletion(userID string) error
GetPendingDeletionUsers(beforeTime time.Time) ([]*model.User, error)
HardDeleteUser(userID string) error
}
// userRepository 用户仓储实现
@@ -544,3 +555,54 @@ func (r *userRepository) GetCommentsCount(userID string) (int64, error) {
func (r *userRepository) UpdateStatus(userID string, status model.UserStatus) error {
return r.db.Model(&model.User{}).Where("id = ?", userID).Update("status", status).Error
}
// UpdatePrivacySettings 更新隐私设置
func (r *userRepository) UpdatePrivacySettings(userID string, settings *model.PrivacySettings) error {
return r.db.Model(&model.User{}).Where("id = ?", userID).Updates(map[string]interface{}{
"privacy_followers_visibility": settings.FollowersVisibility,
"privacy_following_visibility": settings.FollowingVisibility,
"privacy_posts_visibility": settings.PostsVisibility,
"privacy_favorites_visibility": settings.FavoritesVisibility,
}).Error
}
// GetPrivacySettings 获取隐私设置
func (r *userRepository) GetPrivacySettings(userID string) (*model.PrivacySettings, error) {
var user model.User
err := r.db.Select("privacy_followers_visibility, privacy_following_visibility, privacy_posts_visibility, privacy_favorites_visibility").
First(&user, "id = ?", userID).Error
if err != nil {
return nil, err
}
return &user.PrivacySettings, nil
}
// RequestDeletion 申请注销账号
func (r *userRepository) RequestDeletion(userID string) error {
now := time.Now()
return r.db.Model(&model.User{}).Where("id = ?", userID).Updates(map[string]interface{}{
"deletion_requested_at": &now,
"status": model.UserStatusPendingDeletion,
}).Error
}
// CancelDeletion 取消注销
func (r *userRepository) CancelDeletion(userID string) error {
return r.db.Model(&model.User{}).Where("id = ?", userID).Updates(map[string]interface{}{
"deletion_requested_at": nil,
"status": model.UserStatusActive,
}).Error
}
// GetPendingDeletionUsers 获取待删除的用户列表(注销申请时间早于指定时间)
func (r *userRepository) GetPendingDeletionUsers(beforeTime time.Time) ([]*model.User, error) {
var users []*model.User
err := r.db.Where("deletion_requested_at IS NOT NULL AND deletion_requested_at < ?", beforeTime).
Find(&users).Error
return users, err
}
// HardDeleteUser 硬删除用户(永久删除)
func (r *userRepository) HardDeleteUser(userID string) error {
return r.db.Unscoped().Delete(&model.User{}, "id = ?", userID).Error
}