diff --git a/internal/common/pagination.go b/internal/common/pagination.go index 4cb9294..ae2ff22 100644 --- a/internal/common/pagination.go +++ b/internal/common/pagination.go @@ -8,15 +8,6 @@ type Pagination struct { PageSize int `form:"page_size" json:"page_size" binding:"min=1,max=100"` } -// PaginatedResult 分页响应 -type PaginatedResult struct { - Items interface{} `json:"items"` - Total int64 `json:"total"` - Page int `json:"page"` - PageSize int `json:"page_size"` - TotalPages int `json:"total_pages"` -} - // DefaultPagination 默认分页(未传参时使用) func (p *Pagination) DefaultPagination() { if p.Page < 1 { @@ -32,20 +23,5 @@ func (p *Pagination) Offset() int { return (p.Page - 1) * p.PageSize } -// NewPaginatedResult 构建分页响应 -func NewPaginatedResult(items interface{}, total int64, page, pageSize int) *PaginatedResult { - totalPages := int(total) / pageSize - if int(total)%pageSize > 0 { - totalPages++ - } - return &PaginatedResult{ - Items: items, - Total: total, - Page: page, - PageSize: pageSize, - TotalPages: totalPages, - } -} - // 固定时间格式,前后端统一 const TimeFormat = time.RFC3339 diff --git a/internal/controller/admin/interfaces.go b/internal/controller/admin/interfaces.go index 7fcfead..c6bc09a 100644 --- a/internal/controller/admin/interfaces.go +++ b/internal/controller/admin/interfaces.go @@ -13,14 +13,14 @@ type adminUseCase interface { CountUsers() (int64, error) } -// auditUseCase AuditController 对 AuditService 的最小依赖(ISP:4 个方法) +// auditUseCase AuditController 对 AuditService 的最小依赖(ISP:3 个方法) type auditUseCase interface { List(auditType, status string, page, pageSize int) (*service.AuditListResult, error) Approve(reviewerID uint, submissionID uint) error Reject(reviewerID uint, submissionID uint, reason string) error } -// siteSettingUseCase SiteSettingController 对 SiteSettingService 的最小依赖(ISP:3 个方法) +// siteSettingUseCase SiteSettingController 对 SiteSettingService 的最小依赖(ISP:4 个方法) type siteSettingUseCase interface { GetSettings() map[string]string UpdateSetting(key, value string) error @@ -31,5 +31,4 @@ type siteSettingUseCase interface { // auditStatusProvider 审核控制器所需的用户信息查询(ISP) type auditStatusProvider interface { FindByID(id uint) (*model.User, error) - FindByUsername(username string) (*model.User, error) } diff --git a/internal/controller/message_controller.go b/internal/controller/message_controller.go index 6c2888d..97d2ce8 100644 --- a/internal/controller/message_controller.go +++ b/internal/controller/message_controller.go @@ -10,7 +10,7 @@ import ( "github.com/gin-gonic/gin" ) -// notifProvider MessageController 所需的通知服务接口(ISP:5 个方法) +// notifProvider MessageController 所需的通知服务接口(ISP:4 个方法) type notifProvider interface { List(userID uint, page, pageSize int) (*model.NotificationListResult, error) CountUnread(userID uint) (int64, error) diff --git a/internal/model/dto.go b/internal/model/dto.go index d0fc7f6..6139b6b 100644 --- a/internal/model/dto.go +++ b/internal/model/dto.go @@ -20,14 +20,4 @@ type CheckEmailRequest struct { Email string `json:"email" binding:"required,email"` } -// ChangePasswordRequest 修改密码请求 -type ChangePasswordRequest struct { - CurrentPassword string `json:"current_password" binding:"required"` - NewPassword string `json:"new_password" binding:"required,min=8"` -} -// DeleteAccountRequest 注销账号请求 -type DeleteAccountRequest struct { - Password string `json:"password" binding:"required"` - Reason string `json:"reason"` -} diff --git a/internal/repository/audit_repo.go b/internal/repository/audit_repo.go index b58dd48..794e9cf 100644 --- a/internal/repository/audit_repo.go +++ b/internal/repository/audit_repo.go @@ -16,11 +16,6 @@ func NewAuditRepo(db *gorm.DB) *AuditRepo { return &AuditRepo{db: db} } -// AutoMigrate 自动迁移审核表 -func (r *AuditRepo) AutoMigrate() error { - return r.db.AutoMigrate(&model.AuditSubmission{}) -} - // Create 创建审核提交 func (r *AuditRepo) Create(audit *model.AuditSubmission) error { return r.db.Create(audit).Error diff --git a/internal/repository/notification_repo.go b/internal/repository/notification_repo.go index 89ff7cb..e585ab2 100644 --- a/internal/repository/notification_repo.go +++ b/internal/repository/notification_repo.go @@ -16,11 +16,6 @@ func NewNotificationRepo(db *gorm.DB) *NotificationRepo { return &NotificationRepo{db: db} } -// AutoMigrate 自动迁移消息表 -func (r *NotificationRepo) AutoMigrate() error { - return r.db.AutoMigrate(&model.Notification{}) -} - // Create 创建消息 func (r *NotificationRepo) Create(n *model.Notification) error { return r.db.Create(n).Error diff --git a/internal/repository/site_setting_repo.go b/internal/repository/site_setting_repo.go deleted file mode 100644 index bb8e02c..0000000 --- a/internal/repository/site_setting_repo.go +++ /dev/null @@ -1,34 +0,0 @@ -package repository - -import ( - "metazone.cc/metalab/internal/model" - - "gorm.io/gorm" -) - -// SiteSettingRepo 站点设置数据访问 -type SiteSettingRepo struct { - db *gorm.DB -} - -// NewSiteSettingRepo 构造函数 -func NewSiteSettingRepo(db *gorm.DB) *SiteSettingRepo { - return &SiteSettingRepo{db: db} -} - -// AutoMigrate 自动迁移站点设置表 -func (r *SiteSettingRepo) AutoMigrate() error { - return r.db.AutoMigrate(&model.SiteSetting{}) -} - -// Upsert 创建或更新站点设置 -func (r *SiteSettingRepo) Upsert(key, value string) error { - return r.db.Save(&model.SiteSetting{Key: key, Value: value}).Error -} - -// GetAll 获取所有站点设置 -func (r *SiteSettingRepo) GetAll() ([]model.SiteSetting, error) { - var settings []model.SiteSetting - err := r.db.Find(&settings).Error - return settings, err -} diff --git a/internal/repository/user_repo.go b/internal/repository/user_repo.go index 3710538..323fa00 100644 --- a/internal/repository/user_repo.go +++ b/internal/repository/user_repo.go @@ -170,9 +170,3 @@ func (r *UserRepo) CountSearchUsers(keyword, role, status string) (int64, error) return count, err } -// FindByStatus 按状态分页查询(回收站用,暂未暴露前端) -func (r *UserRepo) FindByStatus(status string, offset, limit int) ([]model.User, error) { - var users []model.User - err := r.db.Where("status = ?", status).Order("uid ASC").Offset(offset).Limit(limit).Find(&users).Error - return users, err -} diff --git a/internal/service/audit_service.go b/internal/service/audit_service.go index 95220e1..2bd2216 100644 --- a/internal/service/audit_service.go +++ b/internal/service/audit_service.go @@ -59,14 +59,6 @@ func NewAuditService(auditRepo auditRepo, userRepo userProfileStore, settings si } } -// ErrXxx 重导出 -var ( - ErrAuditNotFound = common.ErrAuditNotFound - ErrAuditNotPending = common.ErrAuditNotPending - ErrAuditDisabled = common.ErrAuditDisabled - ErrAuditTypeOff = common.ErrAuditTypeOff -) - // ShouldAudit 判断指定用户是否需要走审核流程 // 规则:admin 及以上角色免审 func (s *AuditService) ShouldAudit(userID uint) (bool, error) { @@ -85,12 +77,12 @@ func (s *AuditService) ShouldAudit(userID uint) (bool, error) { func (s *AuditService) Submit(userID uint, auditType, newValue string) error { // 检查总开关 if !s.settings.IsAuditEnabled() { - return ErrAuditDisabled + return common.ErrAuditDisabled } // 检查类型开关 if !s.settings.IsAuditTypeEnabled(auditType, s.typeDefault(auditType)) { - return ErrAuditTypeOff + return common.ErrAuditTypeOff } // 用户名冲突检查(提交时即拦截,避免提交到后台后审核失败) @@ -101,7 +93,7 @@ func (s *AuditService) Submit(userID uint, auditType, newValue string) error { return err } if exists { - return ErrUsernameTaken + return common.ErrUsernameTaken } // 2) 审核表中已有其他用户提交了同名 pending pendingExists, err := s.auditRepo.ExistsPendingByTypeAndValue(auditType, newValue, userID) @@ -109,7 +101,7 @@ func (s *AuditService) Submit(userID uint, auditType, newValue string) error { return err } if pendingExists { - return ErrUsernameTaken + return common.ErrUsernameTaken } } @@ -164,14 +156,14 @@ func (s *AuditService) review(reviewerID uint, submissionID uint, approved bool, submission, err := s.auditRepo.FindByID(submissionID) if err != nil { if err == gorm.ErrRecordNotFound { - return ErrAuditNotFound + return common.ErrAuditNotFound } return err } // 2. 必须 pending if submission.Status != model.AuditStatusPending { - return ErrAuditNotPending + return common.ErrAuditNotPending } // 3. 查审核人信息 @@ -220,7 +212,7 @@ func (s *AuditService) applyApproval(submission *model.AuditSubmission) error { return err } if exists { - return ErrUsernameTaken + return common.ErrUsernameTaken } user.Username = submission.NewValue case model.AuditTypeAvatar: diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go index 65ce43c..a8f989f 100644 --- a/internal/service/auth_service.go +++ b/internal/service/auth_service.go @@ -25,24 +25,6 @@ func NewAuthService(userRepo userAuthStore, tokenSvc tokenProvider, cfg *config. return &AuthService{userRepo: userRepo, tokenService: tokenSvc, cfg: cfg} } -var ( - ErrEmailExists = common.ErrEmailExists - ErrUsernameTaken = common.ErrUsernameTaken - ErrInvalidCred = common.ErrInvalidCred - ErrUserNotFound = common.ErrUserNotFound - ErrUserBanned = common.ErrUserBanned - ErrUserLocked = common.ErrUserLocked - ErrUserDeleted = common.ErrUserDeleted - ErrWeakPassword = common.ErrWeakPassword - ErrTokenExpired = common.ErrTokenExpired - ErrTokenInvalid = common.ErrTokenInvalid - ErrTokenRevoked = common.ErrTokenRevoked - ErrPermissionDenied = common.ErrPermissionDenied - ErrIncorrectPassword = common.ErrIncorrectPassword - ErrNeedsConfirmRestore = common.ErrNeedsConfirmRestore - ErrOwnerCannotDelete = common.ErrOwnerCannotDelete -) - var pwLetter = regexp.MustCompile(`[a-zA-Z]`) var pwDigit = regexp.MustCompile(`\d`) @@ -64,7 +46,7 @@ func init() { // validatePassword 密码强度:至少 8 位 + 包含字母 + 包含数字 func validatePassword(pw string) error { if len(pw) < 8 || !pwLetter.MatchString(pw) || !pwDigit.MatchString(pw) { - return ErrWeakPassword + return common.ErrWeakPassword } return nil } @@ -85,7 +67,7 @@ func (s *AuthService) Register(req model.RegisterRequest, regIP string) (string, return "", "", nil, err } if exists { - return "", "", nil, ErrEmailExists + return "", "", nil, common.ErrEmailExists } // 3. 哈希密码 @@ -138,31 +120,31 @@ func (s *AuthService) Login(req model.LoginRequest, loginIP string) (string, str user, err := s.userRepo.FindByEmail(req.Email) if err != nil { _ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password)) - return "", "", nil, ErrInvalidCred + return "", "", nil, common.ErrInvalidCred } // 已注销(deleted)→ 验证密码后要求二次确认,不自动恢复 if user.Status == model.StatusDeleted { if !common.CheckPassword(req.Password, user.PasswordHash) { _ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password)) - return "", "", nil, ErrInvalidCred + return "", "", nil, common.ErrInvalidCred } - return "", "", nil, ErrNeedsConfirmRestore + return "", "", nil, common.ErrNeedsConfirmRestore } // 永久锁定 if user.Status == model.StatusLocked { _ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password)) - return "", "", nil, ErrUserLocked + return "", "", nil, common.ErrUserLocked } // 封禁 if user.Status == model.StatusBanned { - return "", "", nil, ErrUserBanned + return "", "", nil, common.ErrUserBanned } if !common.CheckPassword(req.Password, user.PasswordHash) { - return "", "", nil, ErrInvalidCred + return "", "", nil, common.ErrInvalidCred } // 记录登录 IP 和时间 @@ -194,16 +176,16 @@ func (s *AuthService) ConfirmRestore(req model.LoginRequest, loginIP string) (st user, err := s.userRepo.FindByEmail(req.Email) if err != nil { _ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password)) - return "", "", nil, ErrInvalidCred + return "", "", nil, common.ErrInvalidCred } // 仅 deleted 状态允许恢复 if user.Status != model.StatusDeleted { - return "", "", nil, ErrUserNotFound + return "", "", nil, common.ErrUserNotFound } if !common.CheckPassword(req.Password, user.PasswordHash) { - return "", "", nil, ErrInvalidCred + return "", "", nil, common.ErrInvalidCred } // 恢复账号 @@ -249,7 +231,7 @@ func (s *AuthService) ChangePassword(userID uint, currentPassword, newPassword s // 验证当前密码 if !common.CheckPassword(currentPassword, user.PasswordHash) { - return ErrIncorrectPassword + return common.ErrIncorrectPassword } // 新密码强度校验 @@ -282,12 +264,12 @@ func (s *AuthService) DeleteAccount(userID uint, password, reason string) error // 站长不允许自主注销(避免权限体系死锁) if user.Role == model.RoleOwner { - return ErrOwnerCannotDelete + return common.ErrOwnerCannotDelete } // 验证当前密码(防止 CSRF 或未授权操作) if !common.CheckPassword(password, user.PasswordHash) { - return ErrIncorrectPassword + return common.ErrIncorrectPassword } user.Status = model.StatusDeleted diff --git a/internal/service/token_service.go b/internal/service/token_service.go index c4c3da9..a44ea6c 100644 --- a/internal/service/token_service.go +++ b/internal/service/token_service.go @@ -74,24 +74,24 @@ func (ts *TokenService) BuildRefreshToken(user *model.User, rememberMe bool) (st // 校验 token_version:若 DB 中版本已递增,拒绝刷新 → 即时吊销 func (ts *TokenService) RefreshAccessToken(refreshTokenStr string) (string, *model.User, error) { if refreshTokenStr == "" { - return "", nil, ErrTokenInvalid + return "", nil, common.ErrTokenInvalid } token, err := jwt.Parse(refreshTokenStr, func(t *jwt.Token) (interface{}, error) { return []byte(ts.cfg.JWT.Secret), nil }) if err != nil || !token.Valid { - return "", nil, ErrTokenExpired + return "", nil, common.ErrTokenExpired } claims, ok := token.Claims.(jwt.MapClaims) if !ok { - return "", nil, ErrTokenInvalid + return "", nil, common.ErrTokenInvalid } // 只接受 refresh 用途的 token,防止 access token 被用于刷新 if purpose, _ := claims["purpose"].(string); purpose != "refresh" { - return "", nil, ErrTokenInvalid + return "", nil, common.ErrTokenInvalid } uid := uint(claims["uid"].(float64))