481 lines
13 KiB
Go
481 lines
13 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/topfans/backend/pkg/logger"
|
||
assetPb "github.com/topfans/backend/pkg/proto/asset"
|
||
pbCommon "github.com/topfans/backend/pkg/proto/common"
|
||
pb "github.com/topfans/backend/pkg/proto/social"
|
||
"github.com/topfans/backend/services/socialService/client"
|
||
"github.com/topfans/backend/services/socialService/repository"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// AssetLikeService 资产点赞业务逻辑层
|
||
type AssetLikeService struct {
|
||
assetClient *client.AssetClient
|
||
socialRepo repository.SocialRepository
|
||
}
|
||
|
||
// NewAssetLikeService 创建资产点赞Service实例
|
||
func NewAssetLikeService(assetClient *client.AssetClient, socialRepo repository.SocialRepository) *AssetLikeService {
|
||
return &AssetLikeService{
|
||
assetClient: assetClient,
|
||
socialRepo: socialRepo,
|
||
}
|
||
}
|
||
|
||
// LikeAsset 点赞资产
|
||
func (s *AssetLikeService) LikeAsset(ctx context.Context, assetID, userID, starID int64) error {
|
||
logger.Logger.Debug("AssetLikeService.LikeAsset called",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
// 1. 验证资产是否存在(使用内部RPC,不验证所有权)
|
||
getAssetReq := &assetPb.GetAssetForRPCRequest{
|
||
AssetId: assetID,
|
||
}
|
||
getAssetResp, err := s.assetClient.GetAssetForRPC(ctx, getAssetReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get asset for RPC",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return fmt.Errorf("failed to get asset: %w", err)
|
||
}
|
||
|
||
if getAssetResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
logger.Logger.Warn("Asset not found or error",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("code", int32(getAssetResp.Base.Code)),
|
||
zap.String("message", getAssetResp.Base.Message),
|
||
)
|
||
return fmt.Errorf("asset not found: %s", getAssetResp.Base.Message)
|
||
}
|
||
|
||
// 2. 检查是否已点赞
|
||
checkLikeReq := &assetPb.CheckAssetLikeRequest{
|
||
AssetId: assetID,
|
||
}
|
||
checkLikeResp, err := s.assetClient.CheckAssetLike(ctx, checkLikeReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to check asset like",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return fmt.Errorf("failed to check asset like: %w", err)
|
||
}
|
||
|
||
if checkLikeResp.IsLiked {
|
||
logger.Logger.Warn("Already liked asset",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
)
|
||
return fmt.Errorf("already liked this asset")
|
||
}
|
||
|
||
// 3. 调用 Asset Service 点赞接口
|
||
likeReq := &assetPb.LikeAssetRequest{
|
||
AssetId: assetID,
|
||
}
|
||
likeResp, err := s.assetClient.LikeAsset(ctx, likeReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to like asset",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return fmt.Errorf("failed to like asset: %w", err)
|
||
}
|
||
|
||
if likeResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
logger.Logger.Warn("Like asset failed",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("code", int32(likeResp.Base.Code)),
|
||
zap.String("message", likeResp.Base.Message),
|
||
)
|
||
return fmt.Errorf("like asset failed: %s", likeResp.Base.Message)
|
||
}
|
||
|
||
logger.Logger.Info("Successfully liked asset",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
return nil
|
||
}
|
||
|
||
// UnlikeAsset 取消点赞资产
|
||
func (s *AssetLikeService) UnlikeAsset(ctx context.Context, assetID, userID, starID int64) error {
|
||
logger.Logger.Debug("AssetLikeService.UnlikeAsset called",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
// 1. 检查是否已点赞
|
||
checkLikeReq := &assetPb.CheckAssetLikeRequest{
|
||
AssetId: assetID,
|
||
}
|
||
checkLikeResp, err := s.assetClient.CheckAssetLike(ctx, checkLikeReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to check asset like",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return fmt.Errorf("failed to check asset like: %w", err)
|
||
}
|
||
|
||
if !checkLikeResp.IsLiked {
|
||
logger.Logger.Warn("Not liked asset yet",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
)
|
||
return fmt.Errorf("not liked this asset yet")
|
||
}
|
||
|
||
// 2. 调用 Asset Service 取消点赞接口
|
||
unlikeReq := &assetPb.UnlikeAssetRequest{
|
||
AssetId: assetID,
|
||
}
|
||
unlikeResp, err := s.assetClient.UnlikeAsset(ctx, unlikeReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to unlike asset",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return fmt.Errorf("failed to unlike asset: %w", err)
|
||
}
|
||
|
||
if unlikeResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
logger.Logger.Warn("Unlike asset failed",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("code", int32(unlikeResp.Base.Code)),
|
||
zap.String("message", unlikeResp.Base.Message),
|
||
)
|
||
return fmt.Errorf("unlike asset failed: %s", unlikeResp.Base.Message)
|
||
}
|
||
|
||
logger.Logger.Info("Successfully unliked asset",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
return nil
|
||
}
|
||
|
||
// CheckAssetLike 检查是否已点赞资产
|
||
func (s *AssetLikeService) CheckAssetLike(ctx context.Context, assetID, userID, starID int64) (bool, error) {
|
||
logger.Logger.Debug("AssetLikeService.CheckAssetLike called",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
checkLikeReq := &assetPb.CheckAssetLikeRequest{
|
||
AssetId: assetID,
|
||
}
|
||
checkLikeResp, err := s.assetClient.CheckAssetLike(ctx, checkLikeReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to check asset like",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return false, fmt.Errorf("failed to check asset like: %w", err)
|
||
}
|
||
|
||
if checkLikeResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
logger.Logger.Warn("Check asset like failed",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("code", int32(checkLikeResp.Base.Code)),
|
||
zap.String("message", checkLikeResp.Base.Message),
|
||
)
|
||
return false, fmt.Errorf("check asset like failed: %s", checkLikeResp.Base.Message)
|
||
}
|
||
|
||
return checkLikeResp.IsLiked, nil
|
||
}
|
||
|
||
// GetAssetLikes 获取资产点赞列表
|
||
func (s *AssetLikeService) GetAssetLikes(ctx context.Context, assetID int64, page, pageSize int32) (*assetPb.GetAssetLikesResponse, error) {
|
||
logger.Logger.Debug("AssetLikeService.GetAssetLikes called",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("page", page),
|
||
zap.Int32("page_size", pageSize),
|
||
)
|
||
|
||
getLikesReq := &assetPb.GetAssetLikesRequest{
|
||
AssetId: assetID,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
}
|
||
|
||
getLikesResp, err := s.assetClient.GetAssetLikes(ctx, getLikesReq)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get asset likes",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", assetID),
|
||
)
|
||
return nil, fmt.Errorf("failed to get asset likes: %w", err)
|
||
}
|
||
|
||
if getLikesResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
logger.Logger.Warn("Get asset likes failed",
|
||
zap.Int64("asset_id", assetID),
|
||
zap.Int32("code", int32(getLikesResp.Base.Code)),
|
||
zap.String("message", getLikesResp.Base.Message),
|
||
)
|
||
return nil, fmt.Errorf("get asset likes failed: %s", getLikesResp.Base.Message)
|
||
}
|
||
|
||
return getLikesResp, nil
|
||
}
|
||
|
||
// GetMyLikedAssets 获取我点赞的作品列表
|
||
func (s *AssetLikeService) GetMyLikedAssets(ctx context.Context, req *pb.GetMyLikedAssetsRequest, userID, starID int64) (*pb.GetMyLikedAssetsResponse, error) {
|
||
page := req.Page
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
pageSize := req.PageSize
|
||
if pageSize <= 0 {
|
||
pageSize = 20
|
||
}
|
||
if pageSize > 100 {
|
||
pageSize = 100
|
||
}
|
||
|
||
items, total, err := s.socialRepo.GetMyLikedAssets(userID, starID, int(page), int(pageSize))
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get my liked assets",
|
||
zap.Error(err),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
return &pb.GetMyLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to get my liked assets: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 转换为 proto 类型
|
||
pbItems := make([]*pb.LikedAssetItem, 0, len(items))
|
||
for _, item := range items {
|
||
pbItems = append(pbItems, &pb.LikedAssetItem{
|
||
AssetId: item.AssetID,
|
||
Name: item.Name,
|
||
CoverUrl: item.CoverURL,
|
||
LikeCount: item.LikeCount,
|
||
LikedAt: item.LikedAt,
|
||
Earnings: item.Earnings,
|
||
})
|
||
}
|
||
|
||
hasMore := int64(page)*int64(pageSize) < total
|
||
|
||
return &pb.GetMyLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_OK,
|
||
Message: "success",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
Data: &pb.LikedAssetsData{
|
||
Items: pbItems,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
Total: total,
|
||
HasMore: hasMore,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// GetMyTodayLikedAssets 获取我今日点赞的作品列表
|
||
func (s *AssetLikeService) GetMyTodayLikedAssets(ctx context.Context, req *pb.GetMyTodayLikedAssetsRequest, userID, starID int64) (*pb.GetMyTodayLikedAssetsResponse, error) {
|
||
page := req.Page
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
pageSize := req.PageSize
|
||
if pageSize <= 0 {
|
||
pageSize = 20
|
||
}
|
||
if pageSize > 100 {
|
||
pageSize = 100
|
||
}
|
||
|
||
items, total, err := s.socialRepo.GetMyTodayLikedAssets(userID, starID, int(page), int(pageSize))
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get my today liked assets",
|
||
zap.Error(err),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
return &pb.GetMyTodayLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to get my today liked assets: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
pbItems := make([]*pb.LikedAssetItem, 0, len(items))
|
||
for _, item := range items {
|
||
pbItems = append(pbItems, &pb.LikedAssetItem{
|
||
AssetId: item.AssetID,
|
||
Name: item.Name,
|
||
CoverUrl: item.CoverURL,
|
||
LikeCount: item.LikeCount,
|
||
LikedAt: item.LikedAt,
|
||
Earnings: item.Earnings,
|
||
})
|
||
}
|
||
|
||
hasMore := int64(page)*int64(pageSize) < total
|
||
|
||
return &pb.GetMyTodayLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_OK,
|
||
Message: "success",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
Data: &pb.LikedAssetsData{
|
||
Items: pbItems,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
Total: total,
|
||
HasMore: hasMore,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// GetMyWeekLikedAssets 获取我本周点赞的作品列表
|
||
func (s *AssetLikeService) GetMyWeekLikedAssets(ctx context.Context, req *pb.GetMyWeekLikedAssetsRequest, userID, starID int64) (*pb.GetMyWeekLikedAssetsResponse, error) {
|
||
page := req.Page
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
pageSize := req.PageSize
|
||
if pageSize <= 0 {
|
||
pageSize = 20
|
||
}
|
||
if pageSize > 100 {
|
||
pageSize = 100
|
||
}
|
||
|
||
items, total, err := s.socialRepo.GetMyWeekLikedAssets(userID, starID, int(page), int(pageSize))
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get my week liked assets",
|
||
zap.Error(err),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
return &pb.GetMyWeekLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to get my week liked assets: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
pbItems := make([]*pb.LikedAssetItem, 0, len(items))
|
||
for _, item := range items {
|
||
pbItems = append(pbItems, &pb.LikedAssetItem{
|
||
AssetId: item.AssetID,
|
||
Name: item.Name,
|
||
CoverUrl: item.CoverURL,
|
||
LikeCount: item.LikeCount,
|
||
LikedAt: item.LikedAt,
|
||
Earnings: item.Earnings,
|
||
})
|
||
}
|
||
|
||
hasMore := int64(page)*int64(pageSize) < total
|
||
|
||
return &pb.GetMyWeekLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_OK,
|
||
Message: "success",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
Data: &pb.LikedAssetsData{
|
||
Items: pbItems,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
Total: total,
|
||
HasMore: hasMore,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// GetUserLikedAssets 获取他人点赞的作品列表
|
||
func (s *AssetLikeService) GetUserLikedAssets(ctx context.Context, req *pb.GetUserLikedAssetsRequest, userID, starID int64) (*pb.GetUserLikedAssetsResponse, error) {
|
||
page := req.Page
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
pageSize := req.PageSize
|
||
if pageSize <= 0 {
|
||
pageSize = 20
|
||
}
|
||
if pageSize > 100 {
|
||
pageSize = 100
|
||
}
|
||
|
||
items, total, err := s.socialRepo.GetUserLikedAssets(userID, starID, int(page), int(pageSize))
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to get user liked assets",
|
||
zap.Error(err),
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
return &pb.GetUserLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to get user liked assets: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
pbItems := make([]*pb.LikedAssetItem, 0, len(items))
|
||
for _, item := range items {
|
||
pbItems = append(pbItems, &pb.LikedAssetItem{
|
||
AssetId: item.AssetID,
|
||
Name: item.Name,
|
||
CoverUrl: item.CoverURL,
|
||
LikeCount: item.LikeCount,
|
||
LikedAt: item.LikedAt,
|
||
Earnings: item.Earnings,
|
||
})
|
||
}
|
||
|
||
hasMore := int64(page)*int64(pageSize) < total
|
||
|
||
return &pb.GetUserLikedAssetsResponse{
|
||
Base: &pbCommon.BaseResponse{
|
||
Code: pbCommon.StatusCode_STATUS_OK,
|
||
Message: "success",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
Data: &pb.LikedAssetsData{
|
||
Items: pbItems,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
Total: total,
|
||
HasMore: hasMore,
|
||
},
|
||
}, nil
|
||
}
|
||
|