## CI 修复 (P0/P1) P0 — 编译阻塞: - interfaces.go: postUseCase ISP 接口移除不用的 Create/Update/Delete P1 — 必须修复: - ST1000: 为 13 个包添加包注释 (common/config/model/service/...) - ST1005: redis_store.go 全部错误消息改为小写开头 - errcheck (19处): defer Close()→闭包忽略, notifier.Create→_=, r.Run→检查error - errorlint (9处): switch-on-error→errors.Is 链, ==→errors.Is - ST1020/ST1022: 导出符号注释以符号名开头 P2 — 安全评审: - gosec (12处): G203/G301/G304/G306 添加 nolint 注释并附理由 P3 — 清理: - unused: 移除 hasUnicode/energyStore/current/energyAdminUseCase - gofumpt + goimports 全量格式化 (35+ 文件)
131 lines
3.6 KiB
Go
131 lines
3.6 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"metazone.cc/mce/internal/common"
|
|
"metazone.cc/mce/internal/model"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// review 通用审核操作
|
|
func (s *AuditService) review(reviewerID uint, submissionID uint, approved bool, reason string) error {
|
|
// 1. 查审核记录
|
|
submission, err := s.auditRepo.FindByID(submissionID)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return common.ErrAuditNotFound
|
|
}
|
|
return err
|
|
}
|
|
|
|
// 2. 必须 pending
|
|
if submission.Status != model.AuditStatusPending {
|
|
return common.ErrAuditNotPending
|
|
}
|
|
|
|
// 3. 查审核人信息
|
|
reviewer, err := s.userRepo.FindByID(reviewerID)
|
|
if err != nil {
|
|
return common.ErrUserNotFound
|
|
}
|
|
|
|
// 4. 标记审核结果
|
|
submission.ReviewedBy = &reviewerID
|
|
submission.ReviewerName = &reviewer.Username
|
|
if approved {
|
|
submission.Status = model.AuditStatusApproved
|
|
// 更新 User 表对应字段
|
|
if err := s.applyApproval(submission); err != nil {
|
|
return err
|
|
}
|
|
// 通知用户审核通过
|
|
if s.notifier != nil {
|
|
s.notifier.NotifyAuditApproved(submission.UserID, submission.AuditType, submission.ID)
|
|
}
|
|
} else {
|
|
submission.Status = model.AuditStatusRejected
|
|
submission.RejectReason = &reason
|
|
|
|
// 改名审核被拒 → 仅非首次改名(已扣费)才退还域能
|
|
// 首次改名免费,被拒不退还
|
|
shouldRefund := false
|
|
if submission.AuditType == model.AuditTypeUsername && s.energyRefundSvc != nil {
|
|
if s.levelSvc != nil {
|
|
hasCompleted, _ := s.levelSvc.HasCompletedTask(submission.UserID, "username")
|
|
shouldRefund = hasCompleted
|
|
}
|
|
if shouldRefund {
|
|
_ = s.energyRefundSvc.RefundOnRenameReject(submission.UserID)
|
|
}
|
|
}
|
|
|
|
// 通知用户审核被拒(仅实际退款时追加域能返还提示)
|
|
if s.notifier != nil {
|
|
reasonMsg := reason
|
|
if shouldRefund {
|
|
reasonMsg += "。扣除的域能已被返还"
|
|
}
|
|
s.notifier.NotifyAuditRejected(submission.UserID, submission.AuditType, reasonMsg, submission.ID)
|
|
}
|
|
|
|
// 头像审核被拒 → 删除提交的新头像文件
|
|
if submission.AuditType == model.AuditTypeAvatar && s.avatarCleaner != nil {
|
|
_ = s.avatarCleaner.DeleteAvatarFile(submission.NewValue)
|
|
}
|
|
}
|
|
return s.auditRepo.Update(submission)
|
|
}
|
|
|
|
// applyApproval 将审核通过的内容写入 User 表
|
|
// 用户名审批前再次检查冲突(防止提交到审批期间被其他用户抢占)
|
|
func (s *AuditService) applyApproval(submission *model.AuditSubmission) error {
|
|
user, err := s.userRepo.FindByID(submission.UserID)
|
|
if err != nil {
|
|
return common.ErrUserNotFound
|
|
}
|
|
|
|
switch submission.AuditType {
|
|
case model.AuditTypeUsername:
|
|
exists, err := s.userRepo.ExistsByUsername(submission.NewValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
return common.ErrUsernameTaken
|
|
}
|
|
user.Username = submission.NewValue
|
|
case model.AuditTypeAvatar:
|
|
oldAvatar := user.Avatar
|
|
user.Avatar = submission.NewValue
|
|
if err := s.userRepo.Update(user); err != nil {
|
|
return err
|
|
}
|
|
// 审核通过,删除旧头像文件
|
|
if s.avatarCleaner != nil {
|
|
_ = s.avatarCleaner.DeleteAvatarFile(oldAvatar)
|
|
}
|
|
return nil
|
|
case model.AuditTypeBio:
|
|
user.Bio = submission.NewValue
|
|
}
|
|
if err := s.userRepo.Update(user); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 触发首次任务奖励(静默失败不影响主流程)
|
|
if s.levelSvc != nil {
|
|
switch submission.AuditType {
|
|
case model.AuditTypeUsername:
|
|
_, _, _ = s.levelSvc.CompleteTask(submission.UserID, "username")
|
|
case model.AuditTypeAvatar:
|
|
_, _, _ = s.levelSvc.CompleteTask(submission.UserID, "avatar")
|
|
case model.AuditTypeBio:
|
|
_, _, _ = s.levelSvc.CompleteTask(submission.UserID, "bio")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|