new file: "serv_nginx/api_bb/internal/handlers/training_plan_handler\321\216\320\277\321\211"

modified:   serv_nginx/api_bb/internal/models/training_plan.go
	new file:   serv_nginx/api_bb/internal/service/training_plan_service.go
create CRUD for traing_plan
This commit is contained in:
2025-10-20 05:23:57 +05:00
parent 7515a1314a
commit 5c9abf5f94
3 changed files with 858 additions and 0 deletions
@@ -0,0 +1,557 @@
// handlers/training_plan_handler.go
package handlers
import (
"encoding/json"
"net/http"
"strconv"
"time"
"api_bb/internal/models"
"api_bb/internal/service"
"api_bb/pkg/logger"
"api_bb/pkg/middleware"
"api_bb/pkg/utils"
"go.uber.org/zap"
)
type TrainingPlanHandler struct {
logger logger.LoggerInterface
trainingPlanService service.TrainingPlanService
}
func NewTrainingPlanHandler(trainingPlanService service.TrainingPlanService) *TrainingPlanHandler {
return &TrainingPlanHandler{
logger: logger.NewWrapper(logger.Get().With(zap.String("handler", "training_plan"))),
trainingPlanService: trainingPlanService,
}
}
// TrainingPlanResponse - DTO для ответа с планом тренировок
type TrainingPlanResponse struct {
ID uint `json:"id"`
UserID uint `json:"user_id"`
Title string `json:"title"`
Description string `json:"description"`
Weeks int `json:"weeks"`
WorkoutsPerWeek int `json:"workouts_per_week"`
TargetDistance string `json:"target_distance"`
TargetDate time.Time `json:"target_date"`
CurrentWeek int `json:"current_week"`
Completed bool `json:"completed"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Workouts []TrainingWorkoutResponse `json:"workouts,omitempty"`
}
// TrainingWorkoutResponse - DTO для ответа с тренировкой плана
type TrainingWorkoutResponse struct {
ID uint `json:"id"`
PlanID uint `json:"plan_id"`
Week int `json:"week"`
Day int `json:"day"`
Type models.WorkoutType `json:"type"`
Description string `json:"description"`
Distance float64 `json:"distance_km"`
Duration int `json:"duration_min"`
Completed bool `json:"completed"`
CompletedAt *time.Time `json:"completed_at"`
CreatedAt time.Time `json:"created_at"`
}
// CreateTrainingPlan создает новый план тренировок
func (h *TrainingPlanHandler) CreateTrainingPlan(w http.ResponseWriter, r *http.Request) {
h.logger.Info("handling create training plan request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("create training plan failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
var req models.TrainingPlanCreateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.logger.Error("failed to decode JSON payload", zap.Error(err))
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error())
return
}
h.logger.Debug("creating training plan",
zap.Uint("user_id", user.ID),
zap.String("title", req.Title),
zap.Int("weeks", req.Weeks),
zap.Int("workouts_per_week", req.WorkoutsPerWeek),
)
// Создаем план тренировок через сервис
plan, err := h.trainingPlanService.CreateTrainingPlan(user.ID, &req)
if err != nil {
h.logger.Error("failed to create training plan in service",
zap.Uint("user_id", user.ID),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create training plan: "+err.Error())
return
}
h.logger.Info("training plan created successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", plan.ID),
)
utils.RespondWithJSON(w, http.StatusCreated, map[string]interface{}{
"message": "Training plan created successfully",
"plan": toTrainingPlanResponse(plan),
})
}
// GetTrainingPlans возвращает все планы тренировок пользователя
func (h *TrainingPlanHandler) GetTrainingPlans(w http.ResponseWriter, r *http.Request) {
h.logger.Debug("handling get training plans request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("get training plans failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
h.logger.Debug("getting training plans for user", zap.Uint("user_id", user.ID))
// Получаем планы тренировок через сервис
plans, err := h.trainingPlanService.GetTrainingPlansByUserID(user.ID)
if err != nil {
h.logger.Error("failed to get training plans from service",
zap.Uint("user_id", user.ID),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get training plans: "+err.Error())
return
}
// Преобразуем в response формат
var planResponses []TrainingPlanResponse
for _, plan := range plans {
planResponses = append(planResponses, toTrainingPlanResponse(&plan))
}
h.logger.Debug("training plans retrieved successfully",
zap.Uint("user_id", user.ID),
zap.Int("plans_count", len(planResponses)),
)
utils.RespondWithJSON(w, http.StatusOK, planResponses)
}
// GetTrainingPlanByID возвращает план тренировок по ID
func (h *TrainingPlanHandler) GetTrainingPlanByID(w http.ResponseWriter, r *http.Request) {
h.logger.Debug("handling get training plan by ID request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("get training plan failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
// Извлекаем ID плана из URL параметров
planIDStr := r.URL.Query().Get("id")
if planIDStr == "" {
h.logger.Warn("get training plan failed - plan ID required")
utils.RespondWithError(w, http.StatusBadRequest, "Plan ID is required")
return
}
planID, err := strconv.ParseUint(planIDStr, 10, 32)
if err != nil {
h.logger.Warn("get training plan failed - invalid plan ID",
zap.String("plan_id", planIDStr),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, "Invalid plan ID")
return
}
h.logger.Debug("getting training plan by ID",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
// Получаем план тренировок через сервис
plan, err := h.trainingPlanService.GetTrainingPlanByID(user.ID, uint(planID))
if err != nil {
h.logger.Error("failed to get training plan from service",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get training plan: "+err.Error())
return
}
h.logger.Debug("training plan retrieved successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
utils.RespondWithJSON(w, http.StatusOK, toTrainingPlanResponse(plan))
}
// UpdateTrainingPlan обновляет план тренировок
func (h *TrainingPlanHandler) UpdateTrainingPlan(w http.ResponseWriter, r *http.Request) {
h.logger.Info("handling update training plan request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("update training plan failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
// Извлекаем ID плана из URL параметров
planIDStr := r.URL.Query().Get("id")
if planIDStr == "" {
h.logger.Warn("update training plan failed - plan ID required")
utils.RespondWithError(w, http.StatusBadRequest, "Plan ID is required")
return
}
planID, err := strconv.ParseUint(planIDStr, 10, 32)
if err != nil {
h.logger.Warn("update training plan failed - invalid plan ID",
zap.String("plan_id", planIDStr),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, "Invalid plan ID")
return
}
var req models.TrainingPlanUpdateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.logger.Error("failed to decode JSON payload", zap.Error(err))
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error())
return
}
h.logger.Info("updating training plan",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.String("title", req.Title),
)
// Обновляем план тренировок через сервис
plan, err := h.trainingPlanService.UpdateTrainingPlan(user.ID, uint(planID), &req)
if err != nil {
h.logger.Error("failed to update training plan in service",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update training plan: "+err.Error())
return
}
h.logger.Info("training plan updated successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"message": "Training plan updated successfully",
"plan": toTrainingPlanResponse(plan),
})
}
// DeleteTrainingPlan удаляет план тренировок
func (h *TrainingPlanHandler) DeleteTrainingPlan(w http.ResponseWriter, r *http.Request) {
h.logger.Info("handling delete training plan request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("delete training plan failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
// Извлекаем ID плана из URL параметров
planIDStr := r.URL.Query().Get("id")
if planIDStr == "" {
h.logger.Warn("delete training plan failed - plan ID required")
utils.RespondWithError(w, http.StatusBadRequest, "Plan ID is required")
return
}
planID, err := strconv.ParseUint(planIDStr, 10, 32)
if err != nil {
h.logger.Warn("delete training plan failed - invalid plan ID",
zap.String("plan_id", planIDStr),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, "Invalid plan ID")
return
}
h.logger.Info("deleting training plan",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
// Удаляем план тренировок через сервис
if err := h.trainingPlanService.DeleteTrainingPlan(user.ID, uint(planID)); err != nil {
h.logger.Error("failed to delete training plan in service",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete training plan: "+err.Error())
return
}
h.logger.Info("training plan deleted successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"message": "Training plan deleted successfully",
})
}
// GetActiveTrainingPlan возвращает активный план тренировок пользователя
func (h *TrainingPlanHandler) GetActiveTrainingPlan(w http.ResponseWriter, r *http.Request) {
h.logger.Debug("handling get active training plan request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("get active training plan failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
h.logger.Debug("getting active training plan for user", zap.Uint("user_id", user.ID))
// Получаем активный план тренировок через сервис
plan, err := h.trainingPlanService.GetActiveTrainingPlan(user.ID)
if err != nil {
h.logger.Error("failed to get active training plan from service",
zap.Uint("user_id", user.ID),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get active training plan: "+err.Error())
return
}
h.logger.Debug("active training plan retrieved successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", plan.ID),
)
utils.RespondWithJSON(w, http.StatusOK, toTrainingPlanResponse(plan))
}
// MarkTrainingPlanAsCompleted помечает план тренировок как завершенный
func (h *TrainingPlanHandler) MarkTrainingPlanAsCompleted(w http.ResponseWriter, r *http.Request) {
h.logger.Info("handling mark training plan as completed request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("mark training plan as completed failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
// Извлекаем ID плана из URL параметров
planIDStr := r.URL.Query().Get("id")
if planIDStr == "" {
h.logger.Warn("mark training plan as completed failed - plan ID required")
utils.RespondWithError(w, http.StatusBadRequest, "Plan ID is required")
return
}
planID, err := strconv.ParseUint(planIDStr, 10, 32)
if err != nil {
h.logger.Warn("mark training plan as completed failed - invalid plan ID",
zap.String("plan_id", planIDStr),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, "Invalid plan ID")
return
}
h.logger.Info("marking training plan as completed",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
// Помечаем план как завершенный через сервис
if err := h.trainingPlanService.MarkTrainingPlanAsCompleted(user.ID, uint(planID)); err != nil {
h.logger.Error("failed to mark training plan as completed in service",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to mark training plan as completed: "+err.Error())
return
}
h.logger.Info("training plan marked as completed successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
)
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"message": "Training plan marked as completed successfully",
})
}
// UpdateCurrentWeek обновляет текущую неделю плана тренировок
func (h *TrainingPlanHandler) UpdateCurrentWeek(w http.ResponseWriter, r *http.Request) {
h.logger.Info("handling update current week request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// Получаем пользователя из контекста
user, ok := middleware.GetUserFromContext(r.Context())
if !ok {
h.logger.Warn("update current week failed - authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return
}
// Извлекаем ID плана из URL параметров
planIDStr := r.URL.Query().Get("id")
if planIDStr == "" {
h.logger.Warn("update current week failed - plan ID required")
utils.RespondWithError(w, http.StatusBadRequest, "Plan ID is required")
return
}
planID, err := strconv.ParseUint(planIDStr, 10, 32)
if err != nil {
h.logger.Warn("update current week failed - invalid plan ID",
zap.String("plan_id", planIDStr),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, "Invalid plan ID")
return
}
var req struct {
CurrentWeek int `json:"current_week" validate:"required,min=1,max=52"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.logger.Error("failed to decode JSON payload", zap.Error(err))
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error())
return
}
h.logger.Info("updating current week for training plan",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Int("current_week", req.CurrentWeek),
)
// Обновляем текущую неделю через сервис
if err := h.trainingPlanService.UpdateCurrentWeek(user.ID, uint(planID), req.CurrentWeek); err != nil {
h.logger.Error("failed to update current week in service",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update current week: "+err.Error())
return
}
h.logger.Info("current week updated successfully",
zap.Uint("user_id", user.ID),
zap.Uint("plan_id", uint(planID)),
zap.Int("current_week", req.CurrentWeek),
)
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"message": "Current week updated successfully",
})
}
// Вспомогательные функции для преобразования моделей в DTO
func toTrainingPlanResponse(plan *models.TrainingPlan) TrainingPlanResponse {
response := TrainingPlanResponse{
ID: plan.ID,
UserID: plan.UserID,
Title: plan.Title,
Description: plan.Description,
Weeks: plan.Weeks,
WorkoutsPerWeek: plan.WorkoutsPerWeek,
TargetDistance: plan.TargetDistance,
TargetDate: plan.TargetDate,
CurrentWeek: plan.CurrentWeek,
Completed: plan.Completed,
CreatedAt: plan.CreatedAt,
UpdatedAt: plan.UpdatedAt,
}
// Преобразуем тренировки, если они загружены
if plan.Workouts != nil {
for _, workout := range plan.Workouts {
response.Workouts = append(response.Workouts, toTrainingWorkoutResponse(&workout))
}
}
return response
}
func toTrainingWorkoutResponse(workout *models.TrainingWorkout) TrainingWorkoutResponse {
return TrainingWorkoutResponse{
ID: workout.ID,
PlanID: workout.PlanID,
Week: workout.Week,
Day: workout.Day,
Type: workout.Type,
Description: workout.Description,
Distance: workout.Distance,
Duration: workout.Duration,
Completed: workout.Completed,
CompletedAt: workout.CompletedAt,
CreatedAt: workout.CreatedAt,
}
}
@@ -73,3 +73,13 @@ type TrainingPlanCreateRequest struct {
TargetDistance string `json:"target_distance" validate:"max=50"` TargetDistance string `json:"target_distance" validate:"max=50"`
TargetDate time.Time `json:"target_date"` TargetDate time.Time `json:"target_date"`
} }
// DTO для обновления плана тренировок
type TrainingPlanUpdateRequest struct {
Title string `json:"title" validate:"min=5,max=255"`
Description string `json:"description" validate:"max=1000"`
Weeks int `json:"weeks" validate:"min=1,max=52"`
WorkoutsPerWeek int `json:"workouts_per_week" validate:"min=1,max=7"`
TargetDistance string `json:"target_distance" validate:"max=50"`
TargetDate time.Time `json:"target_date"`
}
@@ -0,0 +1,291 @@
// 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
}