新增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
217 lines
5.3 KiB
Go
217 lines
5.3 KiB
Go
package service
|
|
|
|
import (
|
|
"carrotskin/internal/model"
|
|
"carrotskin/internal/repository"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// textureServiceImpl TextureService的实现
|
|
type textureServiceImpl struct {
|
|
textureRepo repository.TextureRepository
|
|
userRepo repository.UserRepository
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewTextureService 创建TextureService实例
|
|
func NewTextureService(
|
|
textureRepo repository.TextureRepository,
|
|
userRepo repository.UserRepository,
|
|
logger *zap.Logger,
|
|
) TextureService {
|
|
return &textureServiceImpl{
|
|
textureRepo: textureRepo,
|
|
userRepo: userRepo,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (s *textureServiceImpl) Create(uploaderID int64, name, description, textureType, url, hash string, size int, isPublic, isSlim bool) (*model.Texture, error) {
|
|
// 验证用户存在
|
|
user, err := s.userRepo.FindByID(uploaderID)
|
|
if err != nil || user == nil {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
|
|
// 检查Hash是否已存在
|
|
existingTexture, err := s.textureRepo.FindByHash(hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if existingTexture != nil {
|
|
return nil, errors.New("该材质已存在")
|
|
}
|
|
|
|
// 转换材质类型
|
|
textureTypeEnum, err := parseTextureTypeInternal(textureType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 创建材质
|
|
texture := &model.Texture{
|
|
UploaderID: uploaderID,
|
|
Name: name,
|
|
Description: description,
|
|
Type: textureTypeEnum,
|
|
URL: url,
|
|
Hash: hash,
|
|
Size: size,
|
|
IsPublic: isPublic,
|
|
IsSlim: isSlim,
|
|
Status: 1,
|
|
DownloadCount: 0,
|
|
FavoriteCount: 0,
|
|
}
|
|
|
|
if err := s.textureRepo.Create(texture); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return texture, nil
|
|
}
|
|
|
|
func (s *textureServiceImpl) GetByID(id int64) (*model.Texture, error) {
|
|
texture, err := s.textureRepo.FindByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if texture == nil {
|
|
return nil, ErrTextureNotFound
|
|
}
|
|
if texture.Status == -1 {
|
|
return nil, errors.New("材质已删除")
|
|
}
|
|
return texture, nil
|
|
}
|
|
|
|
func (s *textureServiceImpl) GetByUserID(uploaderID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
|
page, pageSize = NormalizePagination(page, pageSize)
|
|
return s.textureRepo.FindByUploaderID(uploaderID, page, pageSize)
|
|
}
|
|
|
|
func (s *textureServiceImpl) Search(keyword string, textureType model.TextureType, publicOnly bool, page, pageSize int) ([]*model.Texture, int64, error) {
|
|
page, pageSize = NormalizePagination(page, pageSize)
|
|
return s.textureRepo.Search(keyword, textureType, publicOnly, page, pageSize)
|
|
}
|
|
|
|
func (s *textureServiceImpl) Update(textureID, uploaderID int64, name, description string, isPublic *bool) (*model.Texture, error) {
|
|
// 获取材质并验证权限
|
|
texture, err := s.textureRepo.FindByID(textureID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if texture == nil {
|
|
return nil, ErrTextureNotFound
|
|
}
|
|
if texture.UploaderID != uploaderID {
|
|
return nil, ErrTextureNoPermission
|
|
}
|
|
|
|
// 更新字段
|
|
updates := make(map[string]interface{})
|
|
if name != "" {
|
|
updates["name"] = name
|
|
}
|
|
if description != "" {
|
|
updates["description"] = description
|
|
}
|
|
if isPublic != nil {
|
|
updates["is_public"] = *isPublic
|
|
}
|
|
|
|
if len(updates) > 0 {
|
|
if err := s.textureRepo.UpdateFields(textureID, updates); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return s.textureRepo.FindByID(textureID)
|
|
}
|
|
|
|
func (s *textureServiceImpl) Delete(textureID, uploaderID int64) error {
|
|
// 获取材质并验证权限
|
|
texture, err := s.textureRepo.FindByID(textureID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if texture == nil {
|
|
return ErrTextureNotFound
|
|
}
|
|
if texture.UploaderID != uploaderID {
|
|
return ErrTextureNoPermission
|
|
}
|
|
|
|
return s.textureRepo.Delete(textureID)
|
|
}
|
|
|
|
func (s *textureServiceImpl) ToggleFavorite(userID, textureID int64) (bool, error) {
|
|
// 确保材质存在
|
|
texture, err := s.textureRepo.FindByID(textureID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if texture == nil {
|
|
return false, ErrTextureNotFound
|
|
}
|
|
|
|
isFavorited, err := s.textureRepo.IsFavorited(userID, textureID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if isFavorited {
|
|
// 已收藏 -> 取消收藏
|
|
if err := s.textureRepo.RemoveFavorite(userID, textureID); err != nil {
|
|
return false, err
|
|
}
|
|
if err := s.textureRepo.DecrementFavoriteCount(textureID); err != nil {
|
|
return false, err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// 未收藏 -> 添加收藏
|
|
if err := s.textureRepo.AddFavorite(userID, textureID); err != nil {
|
|
return false, err
|
|
}
|
|
if err := s.textureRepo.IncrementFavoriteCount(textureID); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *textureServiceImpl) GetUserFavorites(userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
|
page, pageSize = NormalizePagination(page, pageSize)
|
|
return s.textureRepo.GetUserFavorites(userID, page, pageSize)
|
|
}
|
|
|
|
func (s *textureServiceImpl) CheckUploadLimit(uploaderID int64, maxTextures int) error {
|
|
count, err := s.textureRepo.CountByUploaderID(uploaderID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if count >= int64(maxTextures) {
|
|
return fmt.Errorf("已达到最大上传数量限制(%d)", maxTextures)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// parseTextureTypeInternal 解析材质类型
|
|
func parseTextureTypeInternal(textureType string) (model.TextureType, error) {
|
|
switch textureType {
|
|
case "SKIN":
|
|
return model.TextureTypeSkin, nil
|
|
case "CAPE":
|
|
return model.TextureTypeCape, nil
|
|
default:
|
|
return "", errors.New("无效的材质类型")
|
|
}
|
|
}
|
|
|