190 lines
5.9 KiB
Go
190 lines
5.9 KiB
Go
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)
|
||
}
|