Files
tp/serv_nginx/api_bb/internal/service/user_stats_service.go
T
valitovgaziz c55310e2e0 modified: serv_nginx/api_bb/internal/handlers/handlers.go
new file:   serv_nginx/api_bb/internal/handlers/user_stats_handler.go
	modified:   serv_nginx/api_bb/internal/routes/routes.go
	modified:   serv_nginx/api_bb/internal/service/user_stats_service.go
add EndPoints for user stats
2025-10-19 05:56:09 +05:00

258 lines
7.0 KiB
Go

// service/user_stats_service.go
package service
import (
"time"
"api_bb/internal/models"
"api_bb/internal/repository"
"api_bb/pkg/logger"
"go.uber.org/zap"
)
type UserStatsService interface {
GetUserStats(userID uint) (*models.UserStatsResponse, error)
UpdatePersonalBest(userID uint, distanceType string, time string) error
IncrementWorkout(userID uint, distance float64, duration int) error
ResetWeeklyDistance(userID uint) error
ResetMonthlyDistance(userID uint) error
CreateUserStats(userID uint) error
}
type userStatsService struct {
logger logger.LoggerInterface
userStatsRepo repository.UserStatsRepository
}
func NewUserStatsService(userStatsRepo repository.UserStatsRepository) UserStatsService {
return &userStatsService{
logger: logger.NewWrapper(logger.Get().With(zap.String("service", "user_stats"))),
userStatsRepo: userStatsRepo,
}
}
// GetUserStats возвращает статистику пользователя в формате DTO
func (s *userStatsService) GetUserStats(userID uint) (*models.UserStatsResponse, error) {
s.logger.Info("getting user stats",
zap.Uint("user_id", userID),
)
stats, err := s.userStatsRepo.GetUserStatsResponse(userID)
if err != nil {
s.logger.Error("failed to get user stats from repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return nil, err
}
s.logger.Debug("user stats retrieved successfully",
zap.Uint("user_id", userID),
zap.Float64("total_distance", stats.TotalDistance),
zap.Int("workouts_count", stats.WorkoutsCount),
)
return stats, nil
}
// UpdatePersonalBest обновляет личный рекорд пользователя
func (s *userStatsService) UpdatePersonalBest(userID uint, distanceType string, time string) error {
s.logger.Info("updating personal best",
zap.Uint("user_id", userID),
zap.String("distance_type", distanceType),
zap.String("time", time),
)
// Проверяем существование статистики пользователя
_, err := s.userStatsRepo.GetByUserID(userID)
if err != nil {
s.logger.Warn("user stats not found, creating new stats",
zap.Uint("user_id", userID),
)
if err := s.CreateUserStats(userID); err != nil {
return err
}
}
if err := s.userStatsRepo.UpdatePersonalBest(userID, distanceType, time); err != nil {
s.logger.Error("failed to update personal best in repository",
zap.Uint("user_id", userID),
zap.String("distance_type", distanceType),
zap.Error(err),
)
return err
}
s.logger.Info("personal best updated successfully",
zap.Uint("user_id", userID),
zap.String("distance_type", distanceType),
zap.String("time", time),
)
return nil
}
// IncrementWorkout увеличивает счетчик тренировок и обновляет статистику
func (s *userStatsService) IncrementWorkout(userID uint, distance float64, duration int) error {
s.logger.Info("incrementing workout stats",
zap.Uint("user_id", userID),
zap.Float64("distance", distance),
zap.Int("duration", duration),
)
// Проверяем существование статистики пользователя
_, err := s.userStatsRepo.GetByUserID(userID)
if err != nil {
s.logger.Warn("user stats not found, creating new stats",
zap.Uint("user_id", userID),
)
if err := s.CreateUserStats(userID); err != nil {
return err
}
}
// Обновляем серии тренировок
currentTime := time.Now()
if err := s.userStatsRepo.UpdateStreaks(userID, currentTime); err != nil {
s.logger.Error("failed to update streaks in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
// Обновляем недельный и месячный пробег
if err := s.userStatsRepo.UpdateWeeklyDistance(userID, distance); err != nil {
s.logger.Error("failed to update weekly distance in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
if err := s.userStatsRepo.UpdateMonthlyDistance(userID, distance); err != nil {
s.logger.Error("failed to update monthly distance in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
// Увеличиваем счетчик тренировок и обновляем общие показатели
if err := s.userStatsRepo.IncrementWorkouts(userID, distance, duration); err != nil {
s.logger.Error("failed to increment workouts in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
s.logger.Info("workout stats incremented successfully",
zap.Uint("user_id", userID),
zap.Float64("distance", distance),
zap.Int("duration", duration),
)
return nil
}
// ResetWeeklyDistance сбрасывает недельный пробег
func (s *userStatsService) ResetWeeklyDistance(userID uint) error {
s.logger.Info("resetting weekly distance",
zap.Uint("user_id", userID),
)
userStats, err := s.userStatsRepo.GetByUserID(userID)
if err != nil {
s.logger.Error("failed to get user stats for weekly reset",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
userStats.WeeklyDistance = 0
if err := s.userStatsRepo.Update(userStats); err != nil {
s.logger.Error("failed to reset weekly distance in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
s.logger.Info("weekly distance reset successfully",
zap.Uint("user_id", userID),
)
return nil
}
// ResetMonthlyDistance сбрасывает месячный пробег
func (s *userStatsService) ResetMonthlyDistance(userID uint) error {
s.logger.Info("resetting monthly distance",
zap.Uint("user_id", userID),
)
userStats, err := s.userStatsRepo.GetByUserID(userID)
if err != nil {
s.logger.Error("failed to get user stats for monthly reset",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
userStats.MonthlyDistance = 0
if err := s.userStatsRepo.Update(userStats); err != nil {
s.logger.Error("failed to reset monthly distance in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
s.logger.Info("monthly distance reset successfully",
zap.Uint("user_id", userID),
)
return nil
}
// CreateUserStats создает начальную статистику для пользователя
func (s *userStatsService) CreateUserStats(userID uint) error {
s.logger.Info("creating user stats",
zap.Uint("user_id", userID),
)
userStats := &models.UserStats{
UserID: userID,
TotalDistance: 0,
TotalTime: 0,
AvgPace: "0:00",
WorkoutsCount: 0,
CurrentStreak: 0,
LongestStreak: 0,
WeeklyDistance: 0,
MonthlyDistance: 0,
Best5K: "",
Best10K: "",
BestHalf: "",
BestMarathon: "",
LastWorkout: time.Time{},
}
if err := s.userStatsRepo.Create(userStats); err != nil {
s.logger.Error("failed to create user stats in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return err
}
s.logger.Info("user stats created successfully",
zap.Uint("user_id", userID),
)
return nil
}