sno-quiz/backend/internal/service/user_service.go
2025-09-17 22:22:14 +03:00

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
}