refactor: 文件行数超标拆解(Service + Controller 9/16 完成)

- Service 层:energy_service → energize/operations/admin/query 四文件
- Service 层:post_service → helpers/audit + 核心 CRUD 保留
- Service 层:favorite_service → items + 核心文件夹操作保留
- Service 层:auth_service → password + 核心注册/登录保留
- Service 层:notification_service → notify + 核心列表/已读保留
- Service 层:audit_service → review + 核心列表/详情保留
- Controller 层:studio_controller → page/write/api/post_api/action 五文件
- Controller 层:post_controller → page/api/upload 三文件
- Controller 层:comment_controller → list/write/action/upload 四文件
- 清理未使用导入(notification_service.go 移除 fmt)
This commit is contained in:
2026-06-02 15:45:54 +08:00
parent 7cdb4d6698
commit ff9886f08b
31 changed files with 2409 additions and 2237 deletions

View File

@ -0,0 +1,128 @@
package service
import (
"regexp"
"time"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
var pwLetter = regexp.MustCompile(`[a-zA-Z]`)
var pwDigit = regexp.MustCompile(`\d`)
// dummyHash 防时序攻击:当用户不存在时,仍对虚拟哈希执行完整的 bcrypt 比对
var dummyHash []byte
func init() {
hash, err := bcrypt.GenerateFromPassword([]byte("metazone-dummy-hash-2026"), 12)
if err != nil {
panic("failed to generate bcrypt dummy hash: " + err.Error())
}
dummyHash = hash
}
// validatePassword 密码强度:至少 8 位 + 包含字母 + 包含数字
func validatePassword(pw string) error {
if len(pw) < 8 || !pwLetter.MatchString(pw) || !pwDigit.MatchString(pw) {
return common.ErrWeakPassword
}
return nil
}
// ChangePassword 修改密码
// 流程:验证当前密码 → 校验新密码强度 → 哈希 → 更新 → 删除所有 session强制重新登录
func (s *AuthService) ChangePassword(userID uint, currentPassword, newPassword string) error {
user, err := s.userRepo.FindByID(userID)
if err != nil {
return common.ErrUserNotFound
}
if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(currentPassword)) != nil {
return common.ErrIncorrectPassword
}
if err := validatePassword(newPassword); err != nil {
return err
}
hash, err := common.HashPassword(newPassword, s.cfg.Bcrypt.Cost)
if err != nil {
return err
}
user.PasswordHash = hash
if err := s.userRepo.Update(user); err != nil {
return err
}
// 删除所有 session强制所有设备重新登录
return s.invalidateSessions(userID)
}
// DeleteAccount 用户自主注销
func (s *AuthService) DeleteAccount(userID uint, password, reason string) error {
user, err := s.userRepo.FindByID(userID)
if err != nil {
return common.ErrUserNotFound
}
if user.Role == model.RoleOwner {
return common.ErrOwnerCannotDelete
}
if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) != nil {
return common.ErrIncorrectPassword
}
user.Status = model.StatusDeleted
user.DeleteReason = reason
if err := s.userRepo.Update(user); err != nil {
return err
}
return s.invalidateSessions(userID)
}
// invalidateSessions 销毁某用户的所有 session内部方法
func (s *AuthService) invalidateSessions(userID uint) error {
return s.sessionManager.DestroyByUID(userID)
}
// InvalidateSessions 公开方法:销毁用户所有 session供 admin 等外部调用)
func (s *AuthService) InvalidateSessions(userID uint) error {
return s.sessionManager.DestroyByUID(userID)
}
// ConfirmRestore 二次确认恢复已注销账号
func (s *AuthService) ConfirmRestore(req model.LoginRequest, loginIP string) (*model.User, error) {
user, err := s.userRepo.FindByEmail(req.Email)
if err != nil {
_ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password))
return nil, common.ErrInvalidCred
}
if user.Status != model.StatusDeleted {
return nil, common.ErrUserNotFound
}
if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)) != nil {
return nil, common.ErrInvalidCred
}
// 恢复账号
user.Status = model.StatusActive
user.DeletedAt = gorm.DeletedAt{}
now := time.Now()
user.LastLoginIP = loginIP
user.LastLoginAt = &now
if err := s.userRepo.Update(user); err != nil {
return nil, err
}
return user, nil
}