Files
stream.api/internal/database/model/common.go
claude e7fdd0e1ab feat: Add player_configs feature and migrate user preferences
- Implemented player_configs table to store multiple player configurations per user.
- Migrated existing player settings from user_preferences to player_configs.
- Removed player-related columns from user_preferences.
- Added referral state fields to user for tracking referral rewards.
- Created migration scripts for database changes and data migration.
- Added test cases for app services and usage helpers.
- Introduced video job service interfaces and implementations.
2026-03-24 16:08:36 +00:00

111 lines
2.8 KiB
Go

package model
import (
"context"
"strings"
"time"
"gorm.io/gorm"
)
// BoolPtr returns a pointer to the given bool value
func BoolPtr(b bool) *bool {
return &b
}
// StringPtr returns a pointer to the given string value
func StringPtr(s string) *string {
return &s
}
// StringValue returns the string value or empty string if nil
func StringValue(s *string) string {
if s == nil {
return ""
}
return *s
}
// BoolValue returns the bool value or false if nil
func BoolValue(b *bool) bool {
if b == nil {
return false
}
return *b
}
// Int64Ptr returns a pointer to the given int64 value
func Int64Ptr(i int64) *int64 {
return &i
}
// Float64Ptr returns a pointer to the given float64 value
func Float64Ptr(f float64) *float64 {
return &f
}
// TimePtr returns a pointer to the given time.Time value
func TimePtr(t time.Time) *time.Time {
return &t
}
// FindOrCreateUserPreference finds or creates a user preference record
func FindOrCreateUserPreference(ctx context.Context, db *gorm.DB, userID string) (*UserPreference, error) {
pref := &UserPreference{}
err := db.WithContext(ctx).
Where("user_id = ?", userID).
Attrs(&UserPreference{
Language: StringPtr("en"),
Locale: StringPtr("en"),
EmailNotifications: BoolPtr(true),
PushNotifications: BoolPtr(true),
MarketingNotifications: false,
TelegramNotifications: false,
}).
FirstOrCreate(pref).Error
// Handle race condition: if duplicate key error, fetch the existing record
if err != nil && strings.Contains(err.Error(), "duplicate key") {
err = db.WithContext(ctx).Where("user_id = ?", userID).First(pref).Error
}
return pref, err
}
// GetWalletBalance calculates the current wallet balance for a user
func GetWalletBalance(ctx context.Context, db *gorm.DB, userID string) (float64, error) {
var balance float64
if err := db.WithContext(ctx).
Model(&WalletTransaction{}).
Where("user_id = ?", userID).
Select("COALESCE(SUM(amount), 0)").
Scan(&balance).Error; err != nil {
return 0, err
}
return balance, nil
}
// GetLatestPlanSubscription finds the latest plan subscription for a user
func GetLatestPlanSubscription(ctx context.Context, db *gorm.DB, userID string) (*PlanSubscription, error) {
sub := &PlanSubscription{}
err := db.WithContext(ctx).
Where("user_id = ?", userID).
Order("expires_at DESC").
First(sub).Error
if err != nil {
return nil, err
}
return sub, nil
}
// IsSubscriptionExpiringSoon checks if subscription expires within threshold days
func IsSubscriptionExpiringSoon(sub *PlanSubscription, thresholdDays int) bool {
if sub == nil {
return false
}
now := time.Now()
hoursUntilExpiry := sub.ExpiresAt.Sub(now).Hours()
thresholdHours := float64(thresholdDays) * 24
return hoursUntilExpiry > 0 && hoursUntilExpiry <= thresholdHours
}