topfans/backend/services/taskService/repository/daily_task_repo.go

190 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"errors"
"time"
"github.com/topfans/backend/services/taskService/model"
"gorm.io/gorm"
)
// DailyTaskRepository 每日任务数据访问层接口
type DailyTaskRepository interface {
// GetUserDailyProgress 获取用户指定每日任务的进度
GetUserDailyProgress(userID, starID int64, taskKey string) (*model.UserDailyTaskProgress, error)
// GetOrCreateDailyProgress 获取或创建用户每日任务进度
GetOrCreateDailyProgress(userID, starID int64, taskKey string, def *model.TaskDefinition) (*model.UserDailyTaskProgress, error)
// ListDailyTasksByUser 获取用户的所有每日任务进度
ListDailyTasksByUser(userID, starID int64) ([]*model.UserDailyTaskProgress, error)
// ListActiveDailyTaskDefinitions 获取所有活跃的每日任务定义包括star特定和全局默认
ListActiveDailyTaskDefinitions(starID int64) ([]*model.TaskDefinition, error)
// UpdateDailyProgress 更新每日任务进度
UpdateDailyProgress(progress *model.UserDailyTaskProgress) error
// ResetAllDailyTasks 重置所有非pending状态的每日任务为pending
ResetAllDailyTasks() (int64, error)
// InitDailyTasksForUser 为用户初始化该star的所有每日任务进度
InitDailyTasksForUser(userID, starID int64) error
// AcquireAdvisoryLock 获取PostgreSQL advisory lock
AcquireAdvisoryLock(lockID int64) bool
// ReleaseAdvisoryLock 释放PostgreSQL advisory lock
ReleaseAdvisoryLock(lockID int64)
}
// dailyTaskRepository Repository实现
type dailyTaskRepository struct {
db *gorm.DB
}
// NewDailyTaskRepository 创建Repository实例
func NewDailyTaskRepository(db *gorm.DB) DailyTaskRepository {
return &dailyTaskRepository{db: db}
}
// GetUserDailyProgress 获取用户指定每日任务的进度
func (r *dailyTaskRepository) GetUserDailyProgress(userID, starID int64, taskKey string) (*model.UserDailyTaskProgress, error) {
var progress model.UserDailyTaskProgress
err := r.db.Where("user_id = ? AND star_id = ? AND task_key = ?", userID, starID, taskKey).
First(&progress).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &progress, nil
}
// GetOrCreateDailyProgress 获取或创建用户每日任务进度
func (r *dailyTaskRepository) GetOrCreateDailyProgress(userID, starID int64, taskKey string, def *model.TaskDefinition) (*model.UserDailyTaskProgress, error) {
progress, err := r.GetUserDailyProgress(userID, starID, taskKey)
if err != nil {
return nil, err
}
if progress != nil {
return progress, nil
}
// 创建新的进度记录
now := time.Now().UnixMilli()
progress = &model.UserDailyTaskProgress{
UserID: userID,
StarID: starID,
TaskKey: taskKey,
Status: "pending",
CreatedAt: now,
UpdatedAt: now,
}
if def != nil {
progress.CreatedAt = now
progress.UpdatedAt = now
}
err = r.db.Create(progress).Error
if err != nil {
return nil, err
}
return progress, nil
}
// ListDailyTasksByUser 获取用户的所有每日任务进度
func (r *dailyTaskRepository) ListDailyTasksByUser(userID, starID int64) ([]*model.UserDailyTaskProgress, error) {
var progressList []*model.UserDailyTaskProgress
err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).
Order("id ASC").
Find(&progressList).Error
return progressList, err
}
// ListActiveDailyTaskDefinitions 获取所有活跃的每日任务定义包括star特定和全局默认
func (r *dailyTaskRepository) ListActiveDailyTaskDefinitions(starID int64) ([]*model.TaskDefinition, error) {
var definitions []*model.TaskDefinition
err := r.db.Where("is_active = true AND (star_id = ? OR star_id IS NULL)", starID).
Where("task_type = ?", "daily").
Order("sort_order ASC, id ASC").
Find(&definitions).Error
return definitions, err
}
// UpdateDailyProgress 更新每日任务进度
func (r *dailyTaskRepository) UpdateDailyProgress(progress *model.UserDailyTaskProgress) error {
progress.UpdatedAt = time.Now().UnixMilli()
return r.db.Save(progress).Error
}
// ResetAllDailyTasks 重置所有非pending状态的每日任务为pending
func (r *dailyTaskRepository) ResetAllDailyTasks() (int64, error) {
now := time.Now().UnixMilli()
result := r.db.Model(&model.UserDailyTaskProgress{}).
Where("status != ?", "pending").
Updates(map[string]interface{}{
"status": "pending",
"completed_at": nil,
"claimed_at": nil,
"updated_at": now,
})
return result.RowsAffected, result.Error
}
// InitDailyTasksForUser 为用户初始化该star的所有每日任务进度
func (r *dailyTaskRepository) InitDailyTasksForUser(userID, starID int64) error {
// 获取所有活跃的每日任务定义
definitions, err := r.ListActiveDailyTaskDefinitions(starID)
if err != nil {
return err
}
if len(definitions) == 0 {
return nil
}
now := time.Now().UnixMilli()
return r.db.Transaction(func(tx *gorm.DB) error {
for _, def := range definitions {
// 检查是否已存在该任务的进度
var count int64
err := tx.Model(&model.UserDailyTaskProgress{}).
Where("user_id = ? AND star_id = ? AND task_key = ?", userID, starID, def.TaskKey).
Count(&count).Error
if err != nil {
return err
}
// 如果已存在,跳过
if count > 0 {
continue
}
// 创建新的进度记录
progress := &model.UserDailyTaskProgress{
UserID: userID,
StarID: starID,
TaskKey: def.TaskKey,
Status: "pending",
CreatedAt: now,
UpdatedAt: now,
}
if err := tx.Create(progress).Error; err != nil {
return err
}
}
return nil
})
}
// AcquireAdvisoryLock 获取PostgreSQL advisory lock
func (r *dailyTaskRepository) AcquireAdvisoryLock(lockID int64) bool {
var result bool
err := r.db.Raw("SELECT pg_try_advisory_lock(?)", lockID).Scan(&result).Error
if err != nil {
return false
}
return result
}
// ReleaseAdvisoryLock 释放PostgreSQL advisory lock
func (r *dailyTaskRepository) ReleaseAdvisoryLock(lockID int64) {
r.db.Exec("SELECT pg_advisory_unlock(?)", lockID)
}