555 lines
18 KiB
Go
555 lines
18 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/topfans/backend/pkg/logger"
|
||
pbCommon "github.com/topfans/backend/pkg/proto/common"
|
||
pb "github.com/topfans/backend/pkg/proto/task"
|
||
"github.com/topfans/backend/services/taskService/client"
|
||
"github.com/topfans/backend/services/taskService/model"
|
||
"github.com/topfans/backend/services/taskService/repository"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// OnboardingService 引导流程Service接口
|
||
type OnboardingService interface {
|
||
CompleteGuide(ctx context.Context, userID int64, taskKey string, stages []*pb.OnboardingStage) (*pb.CompleteGuideResponse, error)
|
||
GetOnboardingStatus(ctx context.Context, userID, starID int64) (*pb.GetOnboardingStatusResponse, error)
|
||
AdvanceStage(ctx context.Context, userID, starID int64, targetStage int32) (*pb.AdvanceStageResponse, error)
|
||
ClaimOnboardingReward(ctx context.Context, userID, starID int64, stage int32) (*pb.ClaimOnboardingRewardResponse, error)
|
||
InitUserTasks(ctx context.Context, userID, starID int64) error
|
||
}
|
||
|
||
// onboardingService 引导流程Service实现
|
||
type onboardingService struct {
|
||
onboardingRepo repository.OnboardingRepository
|
||
dailyRepo repository.DailyTaskRepository
|
||
userRPCClient client.UserServiceClient
|
||
}
|
||
|
||
// NewOnboardingService 创建引导Service实例
|
||
func NewOnboardingService(
|
||
onboardingRepo repository.OnboardingRepository,
|
||
dailyRepo repository.DailyTaskRepository,
|
||
userRPCClient client.UserServiceClient,
|
||
) OnboardingService {
|
||
return &onboardingService{
|
||
onboardingRepo: onboardingRepo,
|
||
dailyRepo: dailyRepo,
|
||
userRPCClient: userRPCClient,
|
||
}
|
||
}
|
||
|
||
// CompleteGuide 完成引导任务
|
||
func (s *onboardingService) CompleteGuide(ctx context.Context, userID int64, taskKey string, stages []*pb.OnboardingStage) (*pb.CompleteGuideResponse, error) {
|
||
logger.Logger.Info("CompleteGuide",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey),
|
||
zap.Int("stages_count", len(stages)))
|
||
|
||
// 如果前端传了 stages 配置,则存储到数据库
|
||
if len(stages) > 0 {
|
||
logger.Logger.Info("CompleteGuide: saving stage configs",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int("count", len(stages)))
|
||
for i, stage := range stages {
|
||
logger.Logger.Info("CompleteGuide: stage detail",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int("index", i),
|
||
zap.Int32("stage", stage.Stage),
|
||
zap.String("name", stage.Name),
|
||
zap.Strings("required_task_keys", stage.RequiredTaskKeys))
|
||
}
|
||
configs := make([]*model.OnboardingStageConfig, 0, len(stages))
|
||
for _, stage := range stages {
|
||
configs = append(configs, &model.OnboardingStageConfig{
|
||
Stage: int(stage.Stage),
|
||
Name: stage.Name,
|
||
RequiredTaskKeys: stage.RequiredTaskKeys,
|
||
CrystalReward: stage.CrystalReward,
|
||
IsActive: true,
|
||
})
|
||
}
|
||
if err := s.onboardingRepo.SaveStageConfigs(configs); err != nil {
|
||
logger.Logger.Error("CompleteGuide: failed to save stage configs",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(err))
|
||
// 不阻塞主流程,继续
|
||
} else {
|
||
logger.Logger.Info("CompleteGuide: stage configs saved successfully",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int("count", len(configs)))
|
||
}
|
||
} else {
|
||
logger.Logger.Info("CompleteGuide: stages is empty, skipping save",
|
||
zap.Int64("user_id", userID))
|
||
}
|
||
|
||
// 获取或创建引导进度
|
||
progress, err := s.onboardingRepo.GetOrCreateOnboardingProgress(userID, taskKey)
|
||
if err != nil {
|
||
logger.Logger.Error("CompleteGuide: failed to get or create progress",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey),
|
||
zap.Error(err))
|
||
return &pb.CompleteGuideResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
// 如果已完成,跳过进度更新,但仍然返回传入的 stages
|
||
if progress.Status == "completed" {
|
||
logger.Logger.Info("CompleteGuide: already completed, returning stages",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey))
|
||
return &pb.CompleteGuideResponse{
|
||
Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_OK},
|
||
UserId: userID,
|
||
CurrentStage: int32(0),
|
||
Status: progress.Status,
|
||
Stages: stages,
|
||
}, nil
|
||
}
|
||
|
||
// 更新进度
|
||
now := time.Now().Unix()
|
||
progress.Status = "completed"
|
||
progress.CompletedAt = &now
|
||
|
||
if err := s.onboardingRepo.UpdateOnboardingProgress(progress); err != nil {
|
||
logger.Logger.Error("CompleteGuide: failed to update progress",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey),
|
||
zap.Error(err))
|
||
return &pb.CompleteGuideResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
logger.Logger.Info("CompleteGuide: success",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey))
|
||
|
||
return &pb.CompleteGuideResponse{
|
||
Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_OK},
|
||
UserId: userID,
|
||
CurrentStage: int32(0),
|
||
Status: "completed",
|
||
Stages: stages,
|
||
}, nil
|
||
}
|
||
|
||
// GetOnboardingStatus 获取引导状态
|
||
func (s *onboardingService) GetOnboardingStatus(ctx context.Context, userID, starID int64) (*pb.GetOnboardingStatusResponse, error) {
|
||
logger.Logger.Debug("GetOnboardingStatus",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID))
|
||
|
||
// 获取或创建用户引导状态
|
||
status, err := s.onboardingRepo.GetOrCreateOnboardingStatus(userID, starID)
|
||
if err != nil {
|
||
logger.Logger.Error("GetOnboardingStatus: failed to get status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.GetOnboardingStatusResponse{}, err
|
||
}
|
||
|
||
// 获取用户所有引导进度
|
||
progressList, err := s.onboardingRepo.ListUserOnboardingProgressByUser(userID)
|
||
if err != nil {
|
||
logger.Logger.Error("GetOnboardingStatus: failed to list progress",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.GetOnboardingStatusResponse{}, err
|
||
}
|
||
|
||
// 构建 taskKey -> progress 映射
|
||
progressMap := make(map[string]*model.UserOnboardingProgress)
|
||
for _, p := range progressList {
|
||
progressMap[p.TaskKey] = p
|
||
}
|
||
|
||
// 获取所有活跃的阶段配置
|
||
stageConfigs, err := s.onboardingRepo.ListActiveStageConfigs()
|
||
if err != nil {
|
||
logger.Logger.Error("GetOnboardingStatus: failed to list stage configs",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.GetOnboardingStatusResponse{}, err
|
||
}
|
||
|
||
// 转换为 pb.OnboardingStage
|
||
stages := make([]*pb.OnboardingStage, 0, len(stageConfigs))
|
||
for _, cfg := range stageConfigs {
|
||
stage := &pb.OnboardingStage{
|
||
Stage: int32(cfg.Stage),
|
||
Name: cfg.Name,
|
||
RequiredTaskKeys: cfg.RequiredTaskKeys,
|
||
CrystalReward: cfg.CrystalReward,
|
||
Status: "locked",
|
||
}
|
||
|
||
// 判断阶段状态
|
||
if int64(cfg.Stage) < status.CurrentStage {
|
||
stage.Status = "completed"
|
||
} else if int64(cfg.Stage) == status.CurrentStage {
|
||
if status.Status == "completed" {
|
||
stage.Status = "completed"
|
||
} else {
|
||
stage.Status = "in_progress"
|
||
}
|
||
}
|
||
|
||
// 判断是否为当前阶段
|
||
if int64(cfg.Stage) == status.CurrentStage {
|
||
stage.IsCurrent = true
|
||
}
|
||
|
||
// 检查阶段任务是否全部完成
|
||
allCompleted := true
|
||
for _, taskKey := range cfg.RequiredTaskKeys {
|
||
progress, ok := progressMap[taskKey]
|
||
if !ok || progress.Status != "completed" {
|
||
allCompleted = false
|
||
break
|
||
}
|
||
}
|
||
stage.AllTasksCompleted = allCompleted
|
||
|
||
// 检查该阶段奖励是否已领取(需要 proto 重新生成后生效)
|
||
// stage.IsRewardClaimed = containsInt64(status.ClaimedStages, int64(cfg.Stage))
|
||
|
||
stages = append(stages, stage)
|
||
}
|
||
|
||
return &pb.GetOnboardingStatusResponse{
|
||
Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_OK},
|
||
UserId: userID,
|
||
CurrentStage: int32(status.CurrentStage),
|
||
Status: status.Status,
|
||
Stages: stages,
|
||
}, nil
|
||
}
|
||
|
||
// AdvanceStage 进入下一阶段
|
||
func (s *onboardingService) AdvanceStage(ctx context.Context, userID, starID int64, targetStage int32) (*pb.AdvanceStageResponse, error) {
|
||
logger.Logger.Info("AdvanceStage",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("target_stage", targetStage))
|
||
|
||
// 获取当前状态
|
||
status, err := s.onboardingRepo.GetOnboardingStatus(userID, starID)
|
||
if err != nil {
|
||
logger.Logger.Error("AdvanceStage: failed to get status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
// 获取目标阶段配置
|
||
targetConfig, err := s.onboardingRepo.GetStageConfig(int64(targetStage))
|
||
if err != nil {
|
||
logger.Logger.Error("AdvanceStage: failed to get target stage config",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("target_stage", targetStage),
|
||
zap.Error(err))
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
// 获取用户所有引导进度
|
||
progressList, err := s.onboardingRepo.ListUserOnboardingProgressByUser(userID)
|
||
if err != nil {
|
||
logger.Logger.Error("AdvanceStage: failed to list progress",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
// 构建 taskKey -> progress 映射
|
||
progressMap := make(map[string]*model.UserOnboardingProgress)
|
||
for _, p := range progressList {
|
||
progressMap[p.TaskKey] = p
|
||
}
|
||
|
||
// 检查目标阶段的前置任务是否全部完成
|
||
for _, taskKey := range targetConfig.RequiredTaskKeys {
|
||
progress, ok := progressMap[taskKey]
|
||
if !ok || progress.Status != "completed" {
|
||
logger.Logger.Warn("AdvanceStage: required task not completed",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey))
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 400, Message: "required task not completed"},
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
// 更新状态
|
||
status.CurrentStage = int64(targetStage)
|
||
if int64(targetConfig.Stage) == 0 {
|
||
status.Status = "in_progress"
|
||
}
|
||
|
||
if err := s.onboardingRepo.UpdateOnboardingStatus(status); err != nil {
|
||
logger.Logger.Error("AdvanceStage: failed to update status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(err))
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
}, err
|
||
}
|
||
|
||
logger.Logger.Info("AdvanceStage: success",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int32("new_stage", targetStage))
|
||
|
||
return &pb.AdvanceStageResponse{
|
||
Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_OK},
|
||
CurrentStage: targetStage,
|
||
Status: status.Status,
|
||
}, nil
|
||
}
|
||
|
||
// ClaimOnboardingReward 领取引导阶段奖励
|
||
func (s *onboardingService) ClaimOnboardingReward(ctx context.Context, userID, starID int64, stage int32) (*pb.ClaimOnboardingRewardResponse, error) {
|
||
logger.Logger.Info("ClaimOnboardingReward",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("stage", stage))
|
||
|
||
// 获取阶段配置
|
||
config, err := s.onboardingRepo.GetStageConfig(int64(stage))
|
||
if err != nil {
|
||
logger.Logger.Error("ClaimOnboardingReward: failed to get stage config",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("stage", stage),
|
||
zap.Error(err))
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: err.Error()},
|
||
Success: false,
|
||
}, nil
|
||
}
|
||
logger.Logger.Info("ClaimOnboardingReward: got stage config",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int32("stage", stage),
|
||
zap.String("name", config.Name),
|
||
zap.Int64("crystal_reward", config.CrystalReward))
|
||
|
||
// 获取用户引导状态
|
||
status, err := s.onboardingRepo.GetOnboardingStatus(userID, starID)
|
||
if err != nil {
|
||
logger.Logger.Error("ClaimOnboardingReward: failed to get status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: "user onboarding status not found"},
|
||
Success: false,
|
||
}, nil
|
||
}
|
||
|
||
// 检查是否已经领取过该阶段奖励
|
||
if containsInt64(status.ClaimedStages, int64(stage)) {
|
||
logger.Logger.Warn("ClaimOnboardingReward: reward already claimed",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("stage", stage))
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 400, Message: "reward already claimed"},
|
||
Success: false,
|
||
}, nil
|
||
}
|
||
|
||
// 检查该阶段的前置任务是否全部完成
|
||
progressList, errProgress := s.onboardingRepo.ListUserOnboardingProgressByUser(userID)
|
||
if errProgress != nil {
|
||
logger.Logger.Error("ClaimOnboardingReward: failed to list progress",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(errProgress))
|
||
}
|
||
progressMap := make(map[string]*model.UserOnboardingProgress)
|
||
for _, p := range progressList {
|
||
progressMap[p.TaskKey] = p
|
||
}
|
||
for _, taskKey := range config.RequiredTaskKeys {
|
||
progress, ok := progressMap[taskKey]
|
||
if !ok || progress.Status != "completed" {
|
||
logger.Logger.Warn("ClaimOnboardingReward: required task not completed",
|
||
zap.Int64("user_id", userID),
|
||
zap.String("task_key", taskKey))
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 400, Message: "required task not completed"},
|
||
Success: false,
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
// 使用传入的 starID,如果为0则从 onboarding_status 中获取该用户的有效 starID
|
||
balanceStarID := starID
|
||
if balanceStarID == 0 {
|
||
// 从用户已有的 onboarding_status 记录中获取非0的 starID
|
||
statuses, err := s.onboardingRepo.GetUserOnboardingStatuses(userID)
|
||
if err == nil && len(statuses) > 0 {
|
||
for _, s := range statuses {
|
||
if s.StarID > 0 {
|
||
balanceStarID = s.StarID
|
||
break
|
||
}
|
||
}
|
||
}
|
||
// 如果仍然为0,使用传入的starID(可能是0)
|
||
if balanceStarID == 0 {
|
||
logger.Logger.Warn("ClaimOnboardingReward: no valid star_id found",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID))
|
||
balanceStarID = starID
|
||
}
|
||
}
|
||
|
||
// 获取当前用户余额
|
||
currentProfile, errProfile := s.userRPCClient.GetFanProfile(ctx, userID, balanceStarID)
|
||
var currentCrystal int64
|
||
if errProfile != nil {
|
||
logger.Logger.Warn("ClaimOnboardingReward: failed to get fan profile",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("balance_star_id", balanceStarID),
|
||
zap.Error(errProfile))
|
||
} else if currentProfile != nil {
|
||
currentCrystal = currentProfile.CrystalBalance
|
||
}
|
||
|
||
// 发放水晶奖励
|
||
var newCrystalBalance int64
|
||
logger.Logger.Info("ClaimOnboardingReward: about to update crystal",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("balance_star_id", balanceStarID),
|
||
zap.Int64("crystal_reward", config.CrystalReward),
|
||
zap.Int64("current_crystal", currentCrystal))
|
||
if config.CrystalReward > 0 {
|
||
newCrystalBalance, err = s.userRPCClient.UpdateCrystalBalance(ctx, userID, balanceStarID, config.CrystalReward,
|
||
"onboarding_reward", strconv.FormatInt(int64(stage), 10), fmt.Sprintf("引导阶段%d奖励", stage))
|
||
if err != nil {
|
||
logger.Logger.Error("ClaimOnboardingReward: failed to update crystal",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(err))
|
||
newCrystalBalance = currentCrystal
|
||
}
|
||
logger.Logger.Info("ClaimOnboardingReward: crystal update result",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("new_balance", newCrystalBalance),
|
||
zap.Error(err))
|
||
} else {
|
||
logger.Logger.Info("ClaimOnboardingReward: crystal_reward is 0, skipping update")
|
||
newCrystalBalance = currentCrystal
|
||
}
|
||
|
||
// 重新获取最新的余额,确保返回准确的数值(解决RPC返回值可能为0的问题)
|
||
if config.CrystalReward > 0 {
|
||
latestProfile, errLatest := s.userRPCClient.GetFanProfile(ctx, userID, balanceStarID)
|
||
if errLatest != nil {
|
||
logger.Logger.Warn("ClaimOnboardingReward: failed to get latest profile, using computed values",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("balance_star_id", balanceStarID),
|
||
zap.Error(errLatest))
|
||
} else if latestProfile != nil {
|
||
newCrystalBalance = latestProfile.CrystalBalance
|
||
logger.Logger.Info("ClaimOnboardingReward: updated with latest profile values",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("new_crystal_balance", newCrystalBalance))
|
||
}
|
||
}
|
||
|
||
// 更新状态
|
||
now := time.Now().Unix()
|
||
// 标记为已领取
|
||
status.IsOnboardingClaimed = true
|
||
status.OnboardingClaimedAt = &now
|
||
status.Status = "claimed"
|
||
// 添加到已领取阶段列表
|
||
if !containsInt64(status.ClaimedStages, int64(stage)) {
|
||
status.ClaimedStages = append(status.ClaimedStages, int64(stage))
|
||
}
|
||
|
||
if err := s.onboardingRepo.UpdateOnboardingStatus(status); err != nil {
|
||
logger.Logger.Error("ClaimOnboardingReward: failed to update status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(err))
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: 500, Message: "failed to update status"},
|
||
Success: false,
|
||
}, err
|
||
}
|
||
|
||
logger.Logger.Info("ClaimOnboardingReward: success",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int32("stage", stage),
|
||
zap.Int64("balance_star_id", balanceStarID),
|
||
zap.Int64("new_crystal", newCrystalBalance))
|
||
|
||
return &pb.ClaimOnboardingRewardResponse{
|
||
Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_OK},
|
||
Success: true,
|
||
CrystalBalance: strconv.FormatInt(newCrystalBalance, 10),
|
||
}, nil
|
||
}
|
||
|
||
// containsInt64 检查切片是否包含指定值
|
||
func containsInt64(slice []int64, val int64) bool {
|
||
for _, v := range slice {
|
||
if v == val {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// InitUserTasks 初始化用户任务
|
||
// 由 userService 或其他服务在用户注册/新增粉丝身份时调用
|
||
func (s *onboardingService) InitUserTasks(ctx context.Context, userID, starID int64) error {
|
||
logger.Logger.Info("InitUserTasks",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID))
|
||
|
||
// 确保引导状态存在
|
||
_, err := s.onboardingRepo.GetOrCreateOnboardingStatus(userID, starID)
|
||
if err != nil {
|
||
logger.Logger.Error("InitUserTasks: failed to get or create onboarding status",
|
||
zap.Int64("user_id", userID),
|
||
zap.Error(err))
|
||
return err
|
||
}
|
||
|
||
// 初始化每日任务
|
||
if err := s.dailyRepo.InitDailyTasksForUser(userID, starID); err != nil {
|
||
logger.Logger.Error("InitUserTasks: failed to init daily tasks",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Error(err))
|
||
return err
|
||
}
|
||
|
||
logger.Logger.Info("InitUserTasks: success",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID))
|
||
|
||
return nil
|
||
}
|