Initial backend repository commit.
Set up project files and add .gitignore to exclude local build/runtime artifacts. Made-with: Cursor
This commit is contained in:
139
internal/service/sticker_service.go
Normal file
139
internal/service/sticker_service.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"carrot_bbs/internal/model"
|
||||
"carrot_bbs/internal/repository"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrStickerAlreadyExists = errors.New("sticker already exists")
|
||||
ErrInvalidStickerURL = errors.New("invalid sticker url")
|
||||
)
|
||||
|
||||
// StickerService 自定义表情服务接口
|
||||
type StickerService interface {
|
||||
// 获取用户的所有表情
|
||||
GetUserStickers(userID string) ([]model.UserSticker, error)
|
||||
// 添加表情
|
||||
AddSticker(userID string, url string, width, height int) (*model.UserSticker, error)
|
||||
// 删除表情
|
||||
DeleteSticker(userID string, stickerID string) error
|
||||
// 检查表情是否已存在
|
||||
CheckExists(userID string, url string) (bool, error)
|
||||
// 重新排序
|
||||
ReorderStickers(userID string, orders map[string]int) error
|
||||
// 获取用户表情数量
|
||||
GetStickerCount(userID string) (int64, error)
|
||||
}
|
||||
|
||||
// stickerService 自定义表情服务实现
|
||||
type stickerService struct {
|
||||
stickerRepo repository.StickerRepository
|
||||
}
|
||||
|
||||
// NewStickerService 创建自定义表情服务
|
||||
func NewStickerService(stickerRepo repository.StickerRepository) StickerService {
|
||||
return &stickerService{
|
||||
stickerRepo: stickerRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserStickers 获取用户的所有表情
|
||||
func (s *stickerService) GetUserStickers(userID string) ([]model.UserSticker, error) {
|
||||
stickers, err := s.stickerRepo.GetByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 兼容历史脏数据:过滤本地文件 URI,避免客户端加载 file:// 报错
|
||||
filtered := make([]model.UserSticker, 0, len(stickers))
|
||||
for _, sticker := range stickers {
|
||||
if isValidStickerURL(sticker.URL) {
|
||||
filtered = append(filtered, sticker)
|
||||
}
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// AddSticker 添加表情
|
||||
func (s *stickerService) AddSticker(userID string, url string, width, height int) (*model.UserSticker, error) {
|
||||
if !isValidStickerURL(url) {
|
||||
return nil, ErrInvalidStickerURL
|
||||
}
|
||||
|
||||
// 检查是否已存在
|
||||
exists, err := s.stickerRepo.Exists(userID, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exists {
|
||||
return nil, ErrStickerAlreadyExists
|
||||
}
|
||||
|
||||
// 获取当前数量用于设置排序
|
||||
count, err := s.stickerRepo.CountByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sticker := &model.UserSticker{
|
||||
UserID: userID,
|
||||
URL: url,
|
||||
Width: width,
|
||||
Height: height,
|
||||
SortOrder: int(count), // 新表情添加到末尾
|
||||
}
|
||||
|
||||
if err := s.stickerRepo.Create(sticker); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sticker, nil
|
||||
}
|
||||
|
||||
func isValidStickerURL(raw string) bool {
|
||||
trimmed := strings.TrimSpace(raw)
|
||||
if trimmed == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(trimmed)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
scheme := strings.ToLower(parsed.Scheme)
|
||||
return scheme == "http" || scheme == "https"
|
||||
}
|
||||
|
||||
// DeleteSticker 删除表情
|
||||
func (s *stickerService) DeleteSticker(userID string, stickerID string) error {
|
||||
// 先检查表情是否属于该用户
|
||||
sticker, err := s.stickerRepo.GetByID(stickerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sticker.UserID != userID {
|
||||
return errors.New("sticker not found")
|
||||
}
|
||||
|
||||
return s.stickerRepo.Delete(stickerID)
|
||||
}
|
||||
|
||||
// CheckExists 检查表情是否已存在
|
||||
func (s *stickerService) CheckExists(userID string, url string) (bool, error) {
|
||||
return s.stickerRepo.Exists(userID, url)
|
||||
}
|
||||
|
||||
// ReorderStickers 重新排序
|
||||
func (s *stickerService) ReorderStickers(userID string, orders map[string]int) error {
|
||||
return s.stickerRepo.BatchUpdateSortOrder(userID, orders)
|
||||
}
|
||||
|
||||
// GetStickerCount 获取用户表情数量
|
||||
func (s *stickerService) GetStickerCount(userID string) (int64, error) {
|
||||
return s.stickerRepo.CountByUserID(userID)
|
||||
}
|
||||
Reference in New Issue
Block a user