修复冻结用户强制下线

This commit is contained in:
yml2213
2026-08-18 20:02:21 +08:00
parent 0bc6cf9f46
commit c91423a19b
16 changed files with 297 additions and 19 deletions
@@ -19,8 +19,9 @@ import (
)
type Repository struct {
db *gorm.DB
encryptor crypto.Encryptor
db *gorm.DB
encryptor crypto.Encryptor
statusChangeNotifier func(userID uint64)
}
type AuditMeta = auditlog.Meta
@@ -33,6 +34,11 @@ func NewRepository(db *gorm.DB, encryptors ...crypto.Encryptor) *Repository {
return &Repository{db: db, encryptor: encryptor}
}
// SetStatusChangeNotifier 设置状态变更后的会话撤销通知。
func (r *Repository) SetStatusChangeNotifier(notifier func(userID uint64)) {
r.statusChangeNotifier = notifier
}
func (r *Repository) List(ctx context.Context, page, pageSize int, query ListQuery) (*PaginatedResult, error) {
growthConfig, err := rentergrowth.ConfigForTx(r.db.WithContext(ctx))
if err != nil {
@@ -207,6 +213,7 @@ func (r *Repository) AdjustGrowthPoints(ctx context.Context, adminID uint64, use
}
func (r *Repository) updateStatus(ctx context.Context, adminID uint64, userID uint64, status string, riskStatus string, action string, reason string, meta AuditMeta) (*UserDTO, error) {
statusChanged := false
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var user model.User
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
@@ -214,23 +221,33 @@ func (r *Repository) updateStatus(ctx context.Context, adminID uint64, userID ui
}
beforeStatus := user.Status
beforeRisk := user.RiskStatus
beforeTokenVersion := user.TokenVersion
user.Status = status
user.RiskStatus = riskStatus
if beforeStatus != status {
user.TokenVersion++
statusChanged = true
}
if err := tx.Save(&user).Error; err != nil {
return err
}
return appendAuditLog(tx, adminID, action, user.ID, meta, map[string]any{
"user_id": user.ID,
"reason": reason,
"before_status": beforeStatus,
"after_status": status,
"before_risk_status": beforeRisk,
"after_risk_status": riskStatus,
"user_id": user.ID,
"reason": reason,
"before_status": beforeStatus,
"after_status": status,
"before_risk_status": beforeRisk,
"after_risk_status": riskStatus,
"before_token_version": beforeTokenVersion,
"after_token_version": user.TokenVersion,
})
})
if err != nil {
return nil, err
}
if statusChanged && r.statusChangeNotifier != nil {
r.statusChangeNotifier(userID)
}
return r.Find(ctx, userID)
}
@@ -293,6 +293,38 @@ func TestAdjustWalletInsufficientBalance(t *testing.T) {
}
}
func TestFreezeAndUnfreezeBumpUserTokenVersion(t *testing.T) {
db := setupAdminUserTestDB(t)
user := model.User{Phone: "13900000006", Status: "active", TokenVersion: 0}
if err := db.Create(&user).Error; err != nil {
t.Fatalf("创建用户失败:%v", err)
}
repo := NewRepository(db)
got, err := repo.Freeze(t.Context(), 66, user.ID, FreezeRequest{Reason: "风险处置"}, AuditMeta{})
if err != nil {
t.Fatalf("冻结用户失败:%v", err)
}
var saved model.User
if err := db.First(&saved, user.ID).Error; err != nil {
t.Fatalf("查询冻结用户失败:%v", err)
}
if got.Status != "frozen" || saved.TokenVersion != 1 {
t.Fatalf("冻结后状态/版本 = %s/%d, want frozen/1", got.Status, saved.TokenVersion)
}
got, err = repo.Unfreeze(t.Context(), 66, user.ID, AuditMeta{})
if err != nil {
t.Fatalf("解冻用户失败:%v", err)
}
if err := db.First(&saved, user.ID).Error; err != nil {
t.Fatalf("查询解冻用户失败:%v", err)
}
if got.Status != "active" || saved.TokenVersion != 2 {
t.Fatalf("解冻后状态/版本 = %s/%d, want active/2", got.Status, saved.TokenVersion)
}
}
func setupAdminUserTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
@@ -37,6 +37,13 @@ func NewService(repo *Repository) *Service {
return &Service{repo: repo}
}
// SetSessionRevoker 设置用户会话撤销回调,例如关闭用户的实时连接。
func (s *Service) SetSessionRevoker(revoker func(userID uint64)) {
if s.repo != nil {
s.repo.SetStatusChangeNotifier(revoker)
}
}
func (s *Service) List(ctx context.Context, page, pageSize int, query ListQuery) (*PaginatedResult, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable