修改了皮肤收藏部分
This commit is contained in:
@@ -56,17 +56,12 @@ type TextureRepository interface {
|
|||||||
Delete(ctx context.Context, id int64) error
|
Delete(ctx context.Context, id int64) error
|
||||||
BatchDelete(ctx context.Context, ids []int64) (int64, error) // 批量删除
|
BatchDelete(ctx context.Context, ids []int64) (int64, error) // 批量删除
|
||||||
IncrementDownloadCount(ctx context.Context, id int64) error
|
IncrementDownloadCount(ctx context.Context, id int64) error
|
||||||
IncrementFavoriteCount(ctx context.Context, id int64) error
|
|
||||||
DecrementFavoriteCount(ctx context.Context, id int64) error
|
|
||||||
CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error
|
CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error
|
||||||
IsFavorited(ctx context.Context, userID, textureID int64) (bool, error)
|
ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error)
|
||||||
AddFavorite(ctx context.Context, userID, textureID int64) error
|
|
||||||
RemoveFavorite(ctx context.Context, userID, textureID int64) error
|
|
||||||
GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error)
|
GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error)
|
||||||
CountByUploaderID(ctx context.Context, uploaderID int64) (int64, error)
|
CountByUploaderID(ctx context.Context, uploaderID int64) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// YggdrasilRepository Yggdrasil仓储接口
|
// YggdrasilRepository Yggdrasil仓储接口
|
||||||
type YggdrasilRepository interface {
|
type YggdrasilRepository interface {
|
||||||
GetPasswordByID(ctx context.Context, id int64) (string, error)
|
GetPasswordByID(ctx context.Context, id int64) (string, error)
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ func TestProfileRepository_Basic(t *testing.T) {
|
|||||||
t.Fatalf("CountByUserID mismatch: %d err=%v", count, err)
|
t.Fatalf("CountByUserID mismatch: %d err=%v", count, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if err := profileRepo.UpdateLastUsedAt(ctx, "p-uuid"); err != nil {
|
if err := profileRepo.UpdateLastUsedAt(ctx, "p-uuid"); err != nil {
|
||||||
t.Fatalf("UpdateLastUsedAt err: %v", err)
|
t.Fatalf("UpdateLastUsedAt err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -150,22 +149,20 @@ func TestTextureRepository_Basic(t *testing.T) {
|
|||||||
t.Fatalf("FindByHashAndUploaderID mismatch")
|
t.Fatalf("FindByHashAndUploaderID mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = textureRepo.IncrementFavoriteCount(ctx, tex.ID)
|
_, _ = textureRepo.ToggleFavorite(ctx, u.ID, tex.ID)
|
||||||
_ = textureRepo.DecrementFavoriteCount(ctx, tex.ID)
|
favList, _, _ := textureRepo.GetUserFavorites(ctx, u.ID, 1, 10)
|
||||||
|
if len(favList) == 0 {
|
||||||
|
t.Fatalf("GetUserFavorites expected at least 1 favorite")
|
||||||
|
}
|
||||||
|
_, _ = textureRepo.ToggleFavorite(ctx, u.ID, tex.ID)
|
||||||
|
favList, _, _ = textureRepo.GetUserFavorites(ctx, u.ID, 1, 10)
|
||||||
|
if len(favList) != 0 {
|
||||||
|
t.Fatalf("GetUserFavorites expected 0 favorites after toggle off")
|
||||||
|
}
|
||||||
|
|
||||||
_ = textureRepo.IncrementDownloadCount(ctx, tex.ID)
|
_ = textureRepo.IncrementDownloadCount(ctx, tex.ID)
|
||||||
_ = textureRepo.CreateDownloadLog(ctx, &model.TextureDownloadLog{TextureID: tex.ID, UserID: &u.ID, IPAddress: "127.0.0.1"})
|
_ = textureRepo.CreateDownloadLog(ctx, &model.TextureDownloadLog{TextureID: tex.ID, UserID: &u.ID, IPAddress: "127.0.0.1"})
|
||||||
|
|
||||||
// 收藏
|
|
||||||
_ = textureRepo.AddFavorite(ctx, u.ID, tex.ID)
|
|
||||||
if fav, err := textureRepo.IsFavorited(ctx, u.ID, tex.ID); err == nil {
|
|
||||||
if !fav {
|
|
||||||
t.Fatalf("IsFavorited expected true")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Skipf("IsFavorited not supported by sqlite: %v", err)
|
|
||||||
}
|
|
||||||
_ = textureRepo.RemoveFavorite(ctx, u.ID, tex.ID)
|
|
||||||
|
|
||||||
// 批量更新与删除
|
// 批量更新与删除
|
||||||
if affected, err := textureRepo.BatchUpdate(ctx, []int64{tex.ID}, map[string]interface{}{"name": "tex-new"}); err != nil || affected != 1 {
|
if affected, err := textureRepo.BatchUpdate(ctx, []int64{tex.ID}, map[string]interface{}{"name": "tex-new"}); err != nil || affected != 1 {
|
||||||
t.Fatalf("BatchUpdate mismatch, affected=%d err=%v", affected, err)
|
t.Fatalf("BatchUpdate mismatch, affected=%d err=%v", affected, err)
|
||||||
@@ -187,7 +184,7 @@ func TestTextureRepository_Basic(t *testing.T) {
|
|||||||
if list, total, err := textureRepo.Search(ctx, "search", model.TextureTypeCape, true, 1, 10); err != nil || total == 0 || len(list) == 0 {
|
if list, total, err := textureRepo.Search(ctx, "search", model.TextureTypeCape, true, 1, 10); err != nil || total == 0 || len(list) == 0 {
|
||||||
t.Fatalf("Search mismatch, total=%d len=%d err=%v", total, len(list), err)
|
t.Fatalf("Search mismatch, total=%d len=%d err=%v", total, len(list), err)
|
||||||
}
|
}
|
||||||
_ = textureRepo.AddFavorite(ctx, u.ID, tex.ID+1)
|
_, _ = textureRepo.ToggleFavorite(ctx, u.ID, tex.ID+1)
|
||||||
if favList, total, err := textureRepo.GetUserFavorites(ctx, u.ID, 1, 10); err != nil || total == 0 || len(favList) == 0 {
|
if favList, total, err := textureRepo.GetUserFavorites(ctx, u.ID, 1, 10); err != nil || total == 0 || len(favList) == 0 {
|
||||||
t.Fatalf("GetUserFavorites mismatch, total=%d len=%d err=%v", total, len(favList), err)
|
t.Fatalf("GetUserFavorites mismatch, total=%d len=%d err=%v", total, len(favList), err)
|
||||||
}
|
}
|
||||||
@@ -206,7 +203,6 @@ func TestTextureRepository_Basic(t *testing.T) {
|
|||||||
_ = textureRepo.Delete(ctx, tex.ID)
|
_ = textureRepo.Delete(ctx, tex.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestClientRepository_Basic(t *testing.T) {
|
func TestClientRepository_Basic(t *testing.T) {
|
||||||
db := testutil.NewTestDB(t)
|
db := testutil.NewTestDB(t)
|
||||||
repo := NewClientRepository(db)
|
repo := NewClientRepository(db)
|
||||||
|
|||||||
@@ -138,42 +138,52 @@ func (r *textureRepository) IncrementDownloadCount(ctx context.Context, id int64
|
|||||||
UpdateColumn("download_count", gorm.Expr("download_count + ?", 1)).Error
|
UpdateColumn("download_count", gorm.Expr("download_count + ?", 1)).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *textureRepository) IncrementFavoriteCount(ctx context.Context, id int64) error {
|
|
||||||
return r.db.WithContext(ctx).Model(&model.Texture{}).Where("id = ?", id).
|
|
||||||
UpdateColumn("favorite_count", gorm.Expr("favorite_count + ?", 1)).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *textureRepository) DecrementFavoriteCount(ctx context.Context, id int64) error {
|
|
||||||
return r.db.WithContext(ctx).Model(&model.Texture{}).Where("id = ?", id).
|
|
||||||
UpdateColumn("favorite_count", gorm.Expr("favorite_count - ?", 1)).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *textureRepository) CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error {
|
func (r *textureRepository) CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error {
|
||||||
return r.db.WithContext(ctx).Create(log).Error
|
return r.db.WithContext(ctx).Create(log).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *textureRepository) IsFavorited(ctx context.Context, userID, textureID int64) (bool, error) {
|
func (r *textureRepository) ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error) {
|
||||||
|
var isAdded bool
|
||||||
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
var count int64
|
var count int64
|
||||||
// 使用 Select("1") 优化,只查询是否存在,不需要查询所有字段
|
err := tx.Model(&model.UserTextureFavorite{}).
|
||||||
err := r.db.WithContext(ctx).Model(&model.UserTextureFavorite{}).
|
|
||||||
Select("1").
|
|
||||||
Where("user_id = ? AND texture_id = ?", userID, textureID).
|
Where("user_id = ? AND texture_id = ?", userID, textureID).
|
||||||
Limit(1).
|
|
||||||
Count(&count).Error
|
Count(&count).Error
|
||||||
return count > 0, err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
result := tx.Where("user_id = ? AND texture_id = ?", userID, textureID).
|
||||||
|
Delete(&model.UserTextureFavorite{})
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
if result.RowsAffected > 0 {
|
||||||
|
if err := tx.Model(&model.Texture{}).Where("id = ?", textureID).
|
||||||
|
UpdateColumn("favorite_count", gorm.Expr("GREATEST(favorite_count - 1, 0)")).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isAdded = false
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *textureRepository) AddFavorite(ctx context.Context, userID, textureID int64) error {
|
|
||||||
favorite := &model.UserTextureFavorite{
|
favorite := &model.UserTextureFavorite{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
TextureID: textureID,
|
TextureID: textureID,
|
||||||
}
|
}
|
||||||
return r.db.WithContext(ctx).Create(favorite).Error
|
if err := tx.Create(favorite).Error; err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
if err := tx.Model(&model.Texture{}).Where("id = ?", textureID).
|
||||||
func (r *textureRepository) RemoveFavorite(ctx context.Context, userID, textureID int64) error {
|
UpdateColumn("favorite_count", gorm.Expr("favorite_count + 1")).Error; err != nil {
|
||||||
return r.db.WithContext(ctx).Where("user_id = ? AND texture_id = ?", userID, textureID).
|
return err
|
||||||
Delete(&model.UserTextureFavorite{}).Error
|
}
|
||||||
|
isAdded = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return isAdded, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *textureRepository) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
func (r *textureRepository) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
||||||
|
|||||||
@@ -391,37 +391,24 @@ func (m *MockTextureRepository) IncrementFavoriteCount(ctx context.Context, id i
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockTextureRepository) DecrementFavoriteCount(ctx context.Context, id int64) error {
|
|
||||||
if texture, ok := m.textures[id]; ok && texture.FavoriteCount > 0 {
|
|
||||||
texture.FavoriteCount--
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockTextureRepository) CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error {
|
func (m *MockTextureRepository) CreateDownloadLog(ctx context.Context, log *model.TextureDownloadLog) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockTextureRepository) IsFavorited(ctx context.Context, userID, textureID int64) (bool, error) {
|
func (m *MockTextureRepository) ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error) {
|
||||||
if userFavs, ok := m.favorites[userID]; ok {
|
|
||||||
return userFavs[textureID], nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockTextureRepository) AddFavorite(ctx context.Context, userID, textureID int64) error {
|
|
||||||
if m.favorites[userID] == nil {
|
if m.favorites[userID] == nil {
|
||||||
m.favorites[userID] = make(map[int64]bool)
|
m.favorites[userID] = make(map[int64]bool)
|
||||||
}
|
}
|
||||||
m.favorites[userID][textureID] = true
|
isFavorited := m.favorites[userID][textureID]
|
||||||
return nil
|
m.favorites[userID][textureID] = !isFavorited
|
||||||
|
if texture, ok := m.textures[textureID]; ok {
|
||||||
|
if !isFavorited {
|
||||||
|
texture.FavoriteCount++
|
||||||
|
} else if texture.FavoriteCount > 0 {
|
||||||
|
texture.FavoriteCount--
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockTextureRepository) RemoveFavorite(ctx context.Context, userID, textureID int64) error {
|
|
||||||
if userFavs, ok := m.favorites[userID]; ok {
|
|
||||||
delete(userFavs, textureID)
|
|
||||||
}
|
}
|
||||||
return nil
|
return !isFavorited, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockTextureRepository) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
func (m *MockTextureRepository) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
||||||
@@ -474,7 +461,6 @@ func (m *MockTextureRepository) BatchDelete(ctx context.Context, ids []int64) (i
|
|||||||
return deleted, nil
|
return deleted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Service Mocks
|
// Service Mocks
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -219,7 +219,6 @@ func (s *textureService) Delete(ctx context.Context, textureID, uploaderID int64
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *textureService) ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error) {
|
func (s *textureService) ToggleFavorite(ctx context.Context, userID, textureID int64) (bool, error) {
|
||||||
// 确保材质存在
|
|
||||||
texture, err := s.textureRepo.FindByID(ctx, textureID)
|
texture, err := s.textureRepo.FindByID(ctx, textureID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -228,30 +227,14 @@ func (s *textureService) ToggleFavorite(ctx context.Context, userID, textureID i
|
|||||||
return false, ErrTextureNotFound
|
return false, ErrTextureNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
isFavorited, err := s.textureRepo.IsFavorited(ctx, userID, textureID)
|
isAdded, err := s.textureRepo.ToggleFavorite(ctx, userID, textureID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFavorited {
|
s.cacheInv.BatchInvalidate(ctx, s.cacheKeys.UserFavoritesPattern(userID))
|
||||||
// 已收藏 -> 取消收藏
|
|
||||||
if err := s.textureRepo.RemoveFavorite(ctx, userID, textureID); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if err := s.textureRepo.DecrementFavoriteCount(ctx, textureID); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未收藏 -> 添加收藏
|
return isAdded, nil
|
||||||
if err := s.textureRepo.AddFavorite(ctx, userID, textureID); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if err := s.textureRepo.IncrementFavoriteCount(ctx, textureID); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *textureService) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
func (s *textureService) GetUserFavorites(ctx context.Context, userID int64, page, pageSize int) ([]*model.Texture, int64, error) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"carrotskin/internal/model"
|
"carrotskin/internal/model"
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -564,7 +565,7 @@ func TestTextureServiceImpl_Create(t *testing.T) {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// UploadTexture需要文件数据,这里创建一个简单的测试数据
|
// UploadTexture需要文件数据,这里创建一个简单的测试数据
|
||||||
fileData := []byte("fake png data for testing")
|
fileData := []byte(strings.Repeat("x", 512))
|
||||||
texture, err := textureService.UploadTexture(
|
texture, err := textureService.UploadTexture(
|
||||||
ctx,
|
ctx,
|
||||||
tt.uploaderID,
|
tt.uploaderID,
|
||||||
@@ -760,7 +761,7 @@ func TestTextureServiceImpl_FavoritesAndLimit(t *testing.T) {
|
|||||||
UploaderID: 1,
|
UploaderID: 1,
|
||||||
Name: "T",
|
Name: "T",
|
||||||
})
|
})
|
||||||
_ = textureRepo.AddFavorite(context.Background(), 1, i)
|
_, _ = textureRepo.ToggleFavorite(context.Background(), 1, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheManager := NewMockCacheManager()
|
cacheManager := NewMockCacheManager()
|
||||||
|
|||||||
@@ -369,6 +369,11 @@ func (b *CacheKeyBuilder) ProfilePattern(userID int64) string {
|
|||||||
return fmt.Sprintf("%sprofile:*:%d*", b.prefix, userID)
|
return fmt.Sprintf("%sprofile:*:%d*", b.prefix, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserFavoritesPattern 用户收藏相关的所有缓存键模式
|
||||||
|
func (b *CacheKeyBuilder) UserFavoritesPattern(userID int64) string {
|
||||||
|
return fmt.Sprintf("%sfavorites:*:%d*", b.prefix, userID)
|
||||||
|
}
|
||||||
|
|
||||||
// Exists 检查缓存键是否存在
|
// Exists 检查缓存键是否存在
|
||||||
func (cm *CacheManager) Exists(ctx context.Context, key string) (bool, error) {
|
func (cm *CacheManager) Exists(ctx context.Context, key string) (bool, error) {
|
||||||
if !cm.config.Enabled || cm.redis == nil {
|
if !cm.config.Enabled || cm.redis == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user