110 lines
3.4 KiB
Go
110 lines
3.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"sno/internal/models"
|
|
"sno/internal/repository"
|
|
"sort"
|
|
)
|
|
|
|
// UserService defines the interface for user-related business logic.
|
|
type UserService interface {
|
|
GetUserProfile(ctx context.Context, userID int64) (*models.User, error)
|
|
GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error)
|
|
GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error)
|
|
GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error)
|
|
}
|
|
|
|
// userService implements the UserService interface.
|
|
type userService struct {
|
|
userRepo repository.UserRepository
|
|
purchaseRepo repository.PurchaseRepository
|
|
quizAttemptRepo repository.QuizAttemptRepository
|
|
}
|
|
|
|
// NewUserService creates a new instance of a user service.
|
|
func NewUserService(userRepo repository.UserRepository, purchaseRepo repository.PurchaseRepository, quizAttemptRepo repository.QuizAttemptRepository) UserService {
|
|
return &userService{userRepo: userRepo, purchaseRepo: purchaseRepo, quizAttemptRepo: quizAttemptRepo}
|
|
}
|
|
|
|
// GetUserProfile retrieves the user's profile.
|
|
func (s *userService) GetUserProfile(ctx context.Context, userID int64) (*models.User, error) {
|
|
return s.userRepo.GetByID(ctx, userID)
|
|
}
|
|
|
|
// GetOrCreateUser retrieves an existing user or creates a new one
|
|
func (s *userService) GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error) {
|
|
// Try to get existing user first
|
|
user, err := s.userRepo.GetByID(ctx, telegramID)
|
|
if err == nil {
|
|
return user, nil
|
|
}
|
|
|
|
// If user not found, create new one
|
|
newUser := &models.User{
|
|
TelegramID: telegramID,
|
|
FirstName: &firstName,
|
|
LastName: &lastName,
|
|
Username: &username,
|
|
StarsBalance: 0,
|
|
}
|
|
|
|
// Add photo URL if provided
|
|
if photoURL != "" {
|
|
newUser.PhotoURL = &photoURL
|
|
}
|
|
|
|
if err := s.userRepo.CreateUser(ctx, newUser); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newUser, nil
|
|
}
|
|
|
|
// GetUserPurchases retrieves the user's purchase history.
|
|
func (s *userService) GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error) {
|
|
return s.purchaseRepo.GetByUserID(ctx, userID)
|
|
}
|
|
|
|
// GetUserTransactions retrieves a unified list of all user transactions (earned and spent).
|
|
func (s *userService) GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error) {
|
|
var transactions []models.Transaction
|
|
|
|
// Get purchases (spent)
|
|
purchases, err := s.purchaseRepo.GetByUserID(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, p := range purchases {
|
|
transactions = append(transactions, models.Transaction{
|
|
Type: models.TransactionSpent,
|
|
Amount: p.StarsSpent,
|
|
Description: "Покупка приза",
|
|
CreatedAt: p.PurchasedAt,
|
|
})
|
|
}
|
|
|
|
// Get quiz attempts (earned)
|
|
attempts, err := s.quizAttemptRepo.GetByUserID(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, a := range attempts {
|
|
if a.StarsEarned > 0 {
|
|
transactions = append(transactions, models.Transaction{
|
|
Type: models.TransactionEarned,
|
|
Amount: a.StarsEarned,
|
|
Description: "Награда за викторину",
|
|
CreatedAt: a.CompletedAt,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Sort transactions by date descending
|
|
sort.Slice(transactions, func(i, j int) bool {
|
|
return transactions[i].CreatedAt.After(transactions[j].CreatedAt)
|
|
})
|
|
|
|
return transactions, nil
|
|
}
|