Files
backend/internal/service/profile_service_impl.go
lan e05ba3b041 feat: Service层接口化
新增Service接口定义(internal/service/interfaces.go):
- UserService: 用户认证、查询、更新等接口
- ProfileService: 档案CRUD、状态管理接口
- TextureService: 材质管理、收藏功能接口
- TokenService: 令牌生命周期管理接口
- VerificationService: 验证码服务接口
- CaptchaService: 滑动验证码接口
- UploadService: 上传服务接口
- YggdrasilService: Yggdrasil API接口

新增Service实现:
- user_service_impl.go: 用户服务实现
- profile_service_impl.go: 档案服务实现
- texture_service_impl.go: 材质服务实现
- token_service_impl.go: 令牌服务实现

更新Container:
- 添加Service层字段
- 初始化Service实例
- 添加With*Service选项函数

遵循Go最佳实践:
- 接口定义与实现分离
- 依赖通过构造函数注入
- 便于单元测试mock
2025-12-02 17:50:52 +08:00

234 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"carrotskin/internal/model"
"carrotskin/internal/repository"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
// profileServiceImpl ProfileService的实现
type profileServiceImpl struct {
profileRepo repository.ProfileRepository
userRepo repository.UserRepository
logger *zap.Logger
}
// NewProfileService 创建ProfileService实例
func NewProfileService(
profileRepo repository.ProfileRepository,
userRepo repository.UserRepository,
logger *zap.Logger,
) ProfileService {
return &profileServiceImpl{
profileRepo: profileRepo,
userRepo: userRepo,
logger: logger,
}
}
func (s *profileServiceImpl) Create(userID int64, name string) (*model.Profile, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(userID)
if err != nil || user == nil {
return nil, errors.New("用户不存在")
}
if user.Status != 1 {
return nil, errors.New("用户状态异常")
}
// 检查角色名是否已存在
existingName, err := s.profileRepo.FindByName(name)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("查询角色名失败: %w", err)
}
if existingName != nil {
return nil, errors.New("角色名已被使用")
}
// 生成UUID和RSA密钥
profileUUID := uuid.New().String()
privateKey, err := generateRSAPrivateKeyInternal()
if err != nil {
return nil, fmt.Errorf("生成RSA密钥失败: %w", err)
}
// 创建档案
profile := &model.Profile{
UUID: profileUUID,
UserID: userID,
Name: name,
RSAPrivateKey: privateKey,
IsActive: true,
}
if err := s.profileRepo.Create(profile); err != nil {
return nil, fmt.Errorf("创建档案失败: %w", err)
}
// 设置活跃状态
if err := s.profileRepo.SetActive(profileUUID, userID); err != nil {
return nil, fmt.Errorf("设置活跃状态失败: %w", err)
}
return profile, nil
}
func (s *profileServiceImpl) GetByUUID(uuid string) (*model.Profile, error) {
profile, err := s.profileRepo.FindByUUID(uuid)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrProfileNotFound
}
return nil, fmt.Errorf("查询档案失败: %w", err)
}
return profile, nil
}
func (s *profileServiceImpl) GetByUserID(userID int64) ([]*model.Profile, error) {
profiles, err := s.profileRepo.FindByUserID(userID)
if err != nil {
return nil, fmt.Errorf("查询档案列表失败: %w", err)
}
return profiles, nil
}
func (s *profileServiceImpl) Update(uuid string, userID int64, name *string, skinID, capeID *int64) (*model.Profile, error) {
// 获取档案并验证权限
profile, err := s.profileRepo.FindByUUID(uuid)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrProfileNotFound
}
return nil, fmt.Errorf("查询档案失败: %w", err)
}
if profile.UserID != userID {
return nil, ErrProfileNoPermission
}
// 检查角色名是否重复
if name != nil && *name != profile.Name {
existingName, err := s.profileRepo.FindByName(*name)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("查询角色名失败: %w", err)
}
if existingName != nil {
return nil, errors.New("角色名已被使用")
}
profile.Name = *name
}
// 更新皮肤和披风
if skinID != nil {
profile.SkinID = skinID
}
if capeID != nil {
profile.CapeID = capeID
}
if err := s.profileRepo.Update(profile); err != nil {
return nil, fmt.Errorf("更新档案失败: %w", err)
}
return s.profileRepo.FindByUUID(uuid)
}
func (s *profileServiceImpl) Delete(uuid string, userID int64) error {
// 获取档案并验证权限
profile, err := s.profileRepo.FindByUUID(uuid)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrProfileNotFound
}
return fmt.Errorf("查询档案失败: %w", err)
}
if profile.UserID != userID {
return ErrProfileNoPermission
}
if err := s.profileRepo.Delete(uuid); err != nil {
return fmt.Errorf("删除档案失败: %w", err)
}
return nil
}
func (s *profileServiceImpl) SetActive(uuid string, userID int64) error {
// 获取档案并验证权限
profile, err := s.profileRepo.FindByUUID(uuid)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrProfileNotFound
}
return fmt.Errorf("查询档案失败: %w", err)
}
if profile.UserID != userID {
return ErrProfileNoPermission
}
if err := s.profileRepo.SetActive(uuid, userID); err != nil {
return fmt.Errorf("设置活跃状态失败: %w", err)
}
if err := s.profileRepo.UpdateLastUsedAt(uuid); err != nil {
return fmt.Errorf("更新使用时间失败: %w", err)
}
return nil
}
func (s *profileServiceImpl) CheckLimit(userID int64, maxProfiles int) error {
count, err := s.profileRepo.CountByUserID(userID)
if err != nil {
return fmt.Errorf("查询档案数量失败: %w", err)
}
if int(count) >= maxProfiles {
return fmt.Errorf("已达到档案数量上限(%d个", maxProfiles)
}
return nil
}
func (s *profileServiceImpl) GetByNames(names []string) ([]*model.Profile, error) {
profiles, err := s.profileRepo.GetByNames(names)
if err != nil {
return nil, fmt.Errorf("查找失败: %w", err)
}
return profiles, nil
}
func (s *profileServiceImpl) GetByProfileName(name string) (*model.Profile, error) {
profile, err := s.profileRepo.FindByName(name)
if err != nil {
return nil, errors.New("用户角色未创建")
}
return profile, nil
}
// generateRSAPrivateKeyInternal 生成RSA-2048私钥PEM格式
func generateRSAPrivateKeyInternal() (string, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return "", err
}
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyBytes,
})
return string(privateKeyPEM), nil
}