217 lines
7.7 KiB
Go
217 lines
7.7 KiB
Go
package repository
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/topfans/backend/pkg/logger"
|
|
"github.com/topfans/backend/services/taskService/model"
|
|
"go.uber.org/zap"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type OnboardingRepository interface {
|
|
GetOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error)
|
|
GetOrCreateOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error)
|
|
GetUserOnboardingStatuses(userID int64) ([]*model.UserOnboardingStatus, error)
|
|
UpdateOnboardingStatus(status *model.UserOnboardingStatus) error
|
|
UpdateOnboardingProgress(progress *model.UserOnboardingProgress) error
|
|
GetUserOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error)
|
|
GetOrCreateOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error)
|
|
ListActiveStageConfigs() ([]*model.OnboardingStageConfig, error)
|
|
ListUserOnboardingProgressByUser(userID int64) ([]*model.UserOnboardingProgress, error)
|
|
GetStageConfig(stage int64) (*model.OnboardingStageConfig, error)
|
|
SaveStageConfigs(configs []*model.OnboardingStageConfig) error
|
|
CountStageConfigs() (int64, error)
|
|
}
|
|
|
|
type onboardingRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewOnboardingRepository(db *gorm.DB) OnboardingRepository {
|
|
return &onboardingRepository{db: db}
|
|
}
|
|
|
|
func (r *onboardingRepository) GetOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) {
|
|
var status model.UserOnboardingStatus
|
|
err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).First(&status).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &status, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) GetOrCreateOnboardingStatus(userID int64, starID int64) (*model.UserOnboardingStatus, error) {
|
|
var status model.UserOnboardingStatus
|
|
err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).First(&status).Error
|
|
if err == nil {
|
|
return &status, nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
logger.Logger.Error("Failed to GetOrCreateOnboardingStatus", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
now := time.Now().Unix()
|
|
status = model.UserOnboardingStatus{
|
|
UserID: userID,
|
|
StarID: starID,
|
|
CurrentStage: 0,
|
|
Status: "pending",
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
if err := r.db.Create(&status).Error; err != nil {
|
|
logger.Logger.Error("Failed to Create OnboardingStatus", zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
return &status, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) GetUserOnboardingStatuses(userID int64) ([]*model.UserOnboardingStatus, error) {
|
|
var statuses []*model.UserOnboardingStatus
|
|
err := r.db.Where("user_id = ?", userID).Order("star_id DESC").Find(&statuses).Error
|
|
if err != nil {
|
|
logger.Logger.Error("Failed to GetUserOnboardingStatuses", zap.Int64("user_id", userID), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
return statuses, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) UpdateOnboardingStatus(status *model.UserOnboardingStatus) error {
|
|
status.UpdatedAt = time.Now().Unix()
|
|
if err := r.db.Save(status).Error; err != nil {
|
|
logger.Logger.Error("Failed to UpdateOnboardingStatus", zap.Int64("user_id", status.UserID), zap.Error(err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *onboardingRepository) UpdateOnboardingProgress(progress *model.UserOnboardingProgress) error {
|
|
progress.UpdatedAt = time.Now().Unix()
|
|
if err := r.db.Save(progress).Error; err != nil {
|
|
logger.Logger.Error("Failed to UpdateOnboardingProgress", zap.Int64("user_id", progress.UserID), zap.String("task_key", progress.TaskKey), zap.Error(err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *onboardingRepository) GetUserOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) {
|
|
var progress model.UserOnboardingProgress
|
|
err := r.db.Where("user_id = ? AND task_key = ?", userID, taskKey).First(&progress).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &progress, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) GetOrCreateOnboardingProgress(userID int64, taskKey string) (*model.UserOnboardingProgress, error) {
|
|
var progress model.UserOnboardingProgress
|
|
err := r.db.Where("user_id = ? AND task_key = ?", userID, taskKey).First(&progress).Error
|
|
if err == nil {
|
|
return &progress, nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
logger.Logger.Error("Failed to GetOrCreateOnboardingProgress", zap.Int64("user_id", userID), zap.String("task_key", taskKey), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
now := time.Now().Unix()
|
|
progress = model.UserOnboardingProgress{
|
|
UserID: userID,
|
|
TaskKey: taskKey,
|
|
Status: "pending",
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
if err := r.db.Create(&progress).Error; err != nil {
|
|
logger.Logger.Error("Failed to Create OnboardingProgress", zap.Int64("user_id", userID), zap.String("task_key", taskKey), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
return &progress, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) ListActiveStageConfigs() ([]*model.OnboardingStageConfig, error) {
|
|
var configs []*model.OnboardingStageConfig
|
|
err := r.db.Where("is_active = ?", true).Order("sort_order ASC").Find(&configs).Error
|
|
if err != nil {
|
|
logger.Logger.Error("Failed to ListActiveStageConfigs", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
return configs, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) ListUserOnboardingProgressByUser(userID int64) ([]*model.UserOnboardingProgress, error) {
|
|
var progressList []*model.UserOnboardingProgress
|
|
err := r.db.Where("user_id = ?", userID).Find(&progressList).Error
|
|
if err != nil {
|
|
logger.Logger.Error("Failed to ListUserOnboardingProgressByUser", zap.Int64("user_id", userID), zap.Error(err))
|
|
return nil, err
|
|
}
|
|
return progressList, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) GetStageConfig(stage int64) (*model.OnboardingStageConfig, error) {
|
|
var config model.OnboardingStageConfig
|
|
logger.Logger.Info("GetStageConfig: querying",
|
|
zap.Int64("stage", stage))
|
|
err := r.db.Where("stage = ? AND is_active = ?", stage, true).First(&config).Error
|
|
if err != nil {
|
|
logger.Logger.Error("GetStageConfig: query failed",
|
|
zap.Int64("stage", stage),
|
|
zap.Error(err))
|
|
return nil, err
|
|
}
|
|
logger.Logger.Info("GetStageConfig: found",
|
|
zap.Int64("stage", stage),
|
|
zap.String("name", config.Name))
|
|
return &config, nil
|
|
}
|
|
|
|
func (r *onboardingRepository) SaveStageConfigs(configs []*model.OnboardingStageConfig) error {
|
|
if len(configs) == 0 {
|
|
logger.Logger.Warn("SaveStageConfigs: configs is empty, returning")
|
|
return nil
|
|
}
|
|
now := time.Now().Unix()
|
|
|
|
logger.Logger.Info("SaveStageConfigs: starting save",
|
|
zap.Int("count", len(configs)))
|
|
|
|
for _, cfg := range configs {
|
|
logger.Logger.Info("SaveStageConfigs: processing config",
|
|
zap.Int("stage", cfg.Stage),
|
|
zap.String("name", cfg.Name),
|
|
zap.Strings("required_task_keys", cfg.RequiredTaskKeys),
|
|
zap.Int64("crystal_reward", cfg.CrystalReward),
|
|
zap.Int64("exp_reward", cfg.ExpReward))
|
|
|
|
cfg.UpdatedAt = now
|
|
// Use upsert via ON CONFLICT to properly handle JSON serialization
|
|
upsert := clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "stage"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{
|
|
"name", "required_task_keys", "crystal_reward", "exp_reward", "is_active", "updated_at",
|
|
}),
|
|
}
|
|
if err := r.db.Clauses(upsert).Create(cfg).Error; err != nil {
|
|
logger.Logger.Error("SaveStageConfigs: failed to upsert config",
|
|
zap.Int("stage", cfg.Stage),
|
|
zap.Error(err))
|
|
return err
|
|
}
|
|
logger.Logger.Info("SaveStageConfigs: upserted config",
|
|
zap.Int("stage", cfg.Stage),
|
|
zap.String("name", cfg.Name))
|
|
}
|
|
|
|
logger.Logger.Info("SaveStageConfigs: all configs saved successfully")
|
|
return nil
|
|
}
|
|
|
|
func (r *onboardingRepository) CountStageConfigs() (int64, error) {
|
|
var count int64
|
|
err := r.db.Model(&model.OnboardingStageConfig{}).Where("is_active = ?", true).Count(&count).Error
|
|
return count, err
|
|
}
|