Files
tp/main_dc/api_bb/internal/service/training_plan_service.go
T

291 lines
8.5 KiB
Go

// service/training_plan_service.go
package service
import (
"api_bb/internal/models"
"api_bb/internal/repository"
"api_bb/pkg/logger"
"go.uber.org/zap"
)
type TrainingPlanService interface {
CreateTrainingPlan(userID uint, req *models.TrainingPlanCreateRequest) (*models.TrainingPlan, error)
GetTrainingPlansByUserID(userID uint) ([]models.TrainingPlan, error)
GetTrainingPlanByID(userID uint, planID uint) (*models.TrainingPlan, error)
UpdateTrainingPlan(userID uint, planID uint, req *models.TrainingPlanUpdateRequest) (*models.TrainingPlan, error)
DeleteTrainingPlan(userID uint, planID uint) error
GetActiveTrainingPlan(userID uint) (*models.TrainingPlan, error)
MarkTrainingPlanAsCompleted(userID uint, planID uint) error
UpdateCurrentWeek(userID uint, planID uint, currentWeek int) error
}
type trainingPlanService struct {
trainingPlanRepo repository.TrainingPlanRepository
logger logger.LoggerInterface
}
func NewTrainingPlanService(trainingPlanRepo repository.TrainingPlanRepository) TrainingPlanService {
return &trainingPlanService{
trainingPlanRepo: trainingPlanRepo,
logger: logger.NewWrapper(logger.Get().With(zap.String("service", "training_plan"))),
}
}
// CreateTrainingPlan создает новый план тренировок
func (s *trainingPlanService) CreateTrainingPlan(userID uint, req *models.TrainingPlanCreateRequest) (*models.TrainingPlan, error) {
s.logger.Debug("creating training plan",
zap.Uint("user_id", userID),
zap.String("title", req.Title),
)
plan := &models.TrainingPlan{
UserID: userID,
Title: req.Title,
Description: req.Description,
Weeks: req.Weeks,
WorkoutsPerWeek: req.WorkoutsPerWeek,
TargetDistance: req.TargetDistance,
TargetDate: req.TargetDate,
CurrentWeek: 1,
Completed: false,
}
if err := s.trainingPlanRepo.Create(plan); err != nil {
s.logger.Error("failed to create training plan in repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return nil, err
}
s.logger.Debug("training plan created successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", plan.ID),
)
return plan, nil
}
// GetTrainingPlansByUserID возвращает все планы тренировок пользователя
func (s *trainingPlanService) GetTrainingPlansByUserID(userID uint) ([]models.TrainingPlan, error) {
s.logger.Debug("getting training plans for user", zap.Uint("user_id", userID))
plans, err := s.trainingPlanRepo.GetByUserID(userID)
if err != nil {
s.logger.Error("failed to get training plans from repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return nil, err
}
s.logger.Debug("training plans retrieved successfully",
zap.Uint("user_id", userID),
zap.Int("count", len(plans)),
)
return plans, nil
}
// GetTrainingPlanByID возвращает план тренировок по ID
func (s *trainingPlanService) GetTrainingPlanByID(userID uint, planID uint) (*models.TrainingPlan, error) {
s.logger.Debug("getting training plan by ID",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
plan, err := s.trainingPlanRepo.GetByID(planID)
if err != nil {
s.logger.Error("failed to get training plan from repository",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Error(err),
)
return nil, err
}
// Проверяем, что план принадлежит пользователю
if plan.UserID != userID {
s.logger.Warn("training plan access denied - user mismatch",
zap.Uint("user_id", userID),
zap.Uint("plan_user_id", plan.UserID),
zap.Uint("plan_id", planID),
)
return nil, repository.ErrNotFound
}
s.logger.Debug("training plan retrieved successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
return plan, nil
}
// UpdateTrainingPlan обновляет план тренировок
func (s *trainingPlanService) UpdateTrainingPlan(userID uint, planID uint, req *models.TrainingPlanUpdateRequest) (*models.TrainingPlan, error) {
s.logger.Debug("updating training plan",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
// Сначала получаем существующий план
plan, err := s.GetTrainingPlanByID(userID, planID)
if err != nil {
return nil, err
}
// Обновляем только переданные поля
if req.Title != "" {
plan.Title = req.Title
}
if req.Description != "" {
plan.Description = req.Description
}
if req.Weeks > 0 {
plan.Weeks = req.Weeks
}
if req.WorkoutsPerWeek > 0 {
plan.WorkoutsPerWeek = req.WorkoutsPerWeek
}
if req.TargetDistance != "" {
plan.TargetDistance = req.TargetDistance
}
if !req.TargetDate.IsZero() {
plan.TargetDate = req.TargetDate
}
// Сохраняем обновления
if err := s.trainingPlanRepo.Update(plan); err != nil {
s.logger.Error("failed to update training plan in repository",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Error(err),
)
return nil, err
}
s.logger.Debug("training plan updated successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
return plan, nil
}
// DeleteTrainingPlan удаляет план тренировок
func (s *trainingPlanService) DeleteTrainingPlan(userID uint, planID uint) error {
s.logger.Debug("deleting training plan",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
// Проверяем, что план существует и принадлежит пользователю
_, err := s.GetTrainingPlanByID(userID, planID)
if err != nil {
return err
}
// Удаляем план
if err := s.trainingPlanRepo.Delete(planID); err != nil {
s.logger.Error("failed to delete training plan from repository",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Error(err),
)
return err
}
s.logger.Debug("training plan deleted successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
return nil
}
// GetActiveTrainingPlan возвращает активный план тренировок пользователя
func (s *trainingPlanService) GetActiveTrainingPlan(userID uint) (*models.TrainingPlan, error) {
s.logger.Debug("getting active training plan for user", zap.Uint("user_id", userID))
plan, err := s.trainingPlanRepo.GetActivePlan(userID)
if err != nil {
s.logger.Error("failed to get active training plan from repository",
zap.Uint("user_id", userID),
zap.Error(err),
)
return nil, err
}
s.logger.Debug("active training plan retrieved successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", plan.ID),
)
return plan, nil
}
// MarkTrainingPlanAsCompleted помечает план тренировок как завершенный
func (s *trainingPlanService) MarkTrainingPlanAsCompleted(userID uint, planID uint) error {
s.logger.Debug("marking training plan as completed",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
// Проверяем, что план существует и принадлежит пользователю
_, err := s.GetTrainingPlanByID(userID, planID)
if err != nil {
return err
}
// Помечаем как завершенный
if err := s.trainingPlanRepo.MarkAsCompleted(planID); err != nil {
s.logger.Error("failed to mark training plan as completed in repository",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Error(err),
)
return err
}
s.logger.Debug("training plan marked as completed successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
)
return nil
}
// UpdateCurrentWeek обновляет текущую неделю плана тренировок
func (s *trainingPlanService) UpdateCurrentWeek(userID uint, planID uint, currentWeek int) error {
s.logger.Debug("updating current week for training plan",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Int("current_week", currentWeek),
)
// Проверяем, что план существует и принадлежит пользователю
_, err := s.GetTrainingPlanByID(userID, planID)
if err != nil {
return err
}
// Обновляем текущую неделю
if err := s.trainingPlanRepo.UpdateCurrentWeek(planID, currentWeek); err != nil {
s.logger.Error("failed to update current week in repository",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Error(err),
)
return err
}
s.logger.Debug("current week updated successfully",
zap.Uint("user_id", userID),
zap.Uint("plan_id", planID),
zap.Int("current_week", currentWeek),
)
return nil
}