6422d85727
new file: serv_nginx/api_bb/internal/handlers/event_handler.go new file: serv_nginx/api_bb/internal/handlers/event_registration_handler.go modified: serv_nginx/api_bb/internal/handlers/handlers.go modified: serv_nginx/api_bb/internal/models/event.go modified: serv_nginx/api_bb/internal/routes/routes.go new file: serv_nginx/api_bb/internal/service/event_registration_service.go new file: serv_nginx/api_bb/internal/service/event_service.go new file: serv_nginx/api_bb/pkg/middleware/admin_middleware.go add admin middleware, add event and eventRegistration handlers, routes, services, EndPoints
381 lines
13 KiB
Go
381 lines
13 KiB
Go
// service/event_registration_service.go
|
|
package service
|
|
|
|
import (
|
|
"api_bb/internal/models"
|
|
"api_bb/internal/repository"
|
|
"api_bb/pkg/logger"
|
|
"fmt"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type EventRegistrationService interface {
|
|
RegisterForEvent(registration *models.EventRegistration) error
|
|
GetRegistrationByID(id uint) (*models.EventRegistration, error)
|
|
GetRegistrationsByEventID(eventID uint) ([]models.EventRegistration, error)
|
|
GetRegistrationsByUserID(userID uint) ([]models.EventRegistration, error)
|
|
GetRegistrationByEventAndUser(eventID, userID uint) (*models.EventRegistration, error)
|
|
UpdateRegistration(registration *models.EventRegistration) error
|
|
CancelRegistration(id uint) error
|
|
UpdateRegistrationStatus(registrationID uint, status string) error
|
|
UpdateResultTime(registrationID uint, resultTime string) error
|
|
CheckEventAvailability(eventID uint) (bool, error)
|
|
}
|
|
|
|
type eventRegistrationService struct {
|
|
registrationRepo repository.EventRegistrationRepository
|
|
eventRepo repository.EventRepository
|
|
logger logger.LoggerInterface
|
|
}
|
|
|
|
func NewEventRegistrationService(
|
|
registrationRepo repository.EventRegistrationRepository,
|
|
eventRepo repository.EventRepository,
|
|
log logger.LoggerInterface,
|
|
) EventRegistrationService {
|
|
serviceLogger := log.With(zap.String("service", "event_registration"))
|
|
|
|
return &eventRegistrationService{
|
|
registrationRepo: registrationRepo,
|
|
eventRepo: eventRepo,
|
|
logger: serviceLogger,
|
|
}
|
|
}
|
|
|
|
// RegisterForEvent регистрирует пользователя на событие
|
|
func (s *eventRegistrationService) RegisterForEvent(registration *models.EventRegistration) error {
|
|
s.logger.Info("Registering user for event",
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
)
|
|
|
|
// Проверяем существование события
|
|
event, err := s.eventRepo.FindByID(registration.EventID)
|
|
if err != nil {
|
|
s.logger.Warn("Event not found for registration",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("event not found")
|
|
}
|
|
|
|
// Проверяем, открыта ли регистрация
|
|
if !event.RegistrationOpen {
|
|
s.logger.Warn("Registration is closed for event",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.String("event_title", event.Title),
|
|
)
|
|
return fmt.Errorf("registration is closed for this event")
|
|
}
|
|
|
|
// Проверяем, не зарегистрирован ли пользователь уже
|
|
existingRegistration, err := s.registrationRepo.FindByEventAndUser(registration.EventID, registration.UserID)
|
|
if err == nil && existingRegistration != nil {
|
|
s.logger.Warn("User already registered for event",
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
)
|
|
return fmt.Errorf("user already registered for this event")
|
|
}
|
|
|
|
// Проверяем доступность мест
|
|
available, err := s.CheckEventAvailability(registration.EventID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to check event availability",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to check event availability: %w", err)
|
|
}
|
|
|
|
if !available {
|
|
s.logger.Warn("Event is full",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.String("event_title", event.Title),
|
|
)
|
|
return fmt.Errorf("event is full")
|
|
}
|
|
|
|
// Создаем регистрацию
|
|
if err := s.registrationRepo.Create(registration); err != nil {
|
|
s.logger.Error("Failed to create registration",
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to register for event: %w", err)
|
|
}
|
|
|
|
// Обновляем счетчик участников
|
|
if err := s.eventRepo.UpdateParticipantsCount(registration.EventID, event.ParticipantsCount+1); err != nil {
|
|
s.logger.Error("Failed to update participants count",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.Error(err),
|
|
)
|
|
// Не прерываем выполнение, только логируем ошибку
|
|
}
|
|
|
|
s.logger.Info("User registered for event successfully",
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.String("status", registration.Status),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// GetRegistrationByID возвращает регистрацию по ID
|
|
func (s *eventRegistrationService) GetRegistrationByID(id uint) (*models.EventRegistration, error) {
|
|
s.logger.Debug("Getting registration by ID", zap.Uint("registration_id", id))
|
|
|
|
registration, err := s.registrationRepo.FindByID(id)
|
|
if err != nil {
|
|
s.logger.Warn("Registration not found",
|
|
zap.Uint("registration_id", id),
|
|
zap.Error(err),
|
|
)
|
|
return nil, fmt.Errorf("registration not found: %w", err)
|
|
}
|
|
|
|
s.logger.Debug("Registration retrieved successfully",
|
|
zap.Uint("registration_id", id),
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
)
|
|
return registration, nil
|
|
}
|
|
|
|
// GetRegistrationsByEventID возвращает все регистрации на событие
|
|
func (s *eventRegistrationService) GetRegistrationsByEventID(eventID uint) ([]models.EventRegistration, error) {
|
|
s.logger.Debug("Getting registrations by event ID", zap.Uint("event_id", eventID))
|
|
|
|
registrations, err := s.registrationRepo.FindByEventID(eventID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get registrations by event ID",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Error(err),
|
|
)
|
|
return nil, fmt.Errorf("failed to get registrations: %w", err)
|
|
}
|
|
|
|
s.logger.Debug("Registrations by event retrieved successfully",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Int("count", len(registrations)),
|
|
)
|
|
return registrations, nil
|
|
}
|
|
|
|
// GetRegistrationsByUserID возвращает все регистрации пользователя
|
|
func (s *eventRegistrationService) GetRegistrationsByUserID(userID uint) ([]models.EventRegistration, error) {
|
|
s.logger.Debug("Getting registrations by user ID", zap.Uint("user_id", userID))
|
|
|
|
registrations, err := s.registrationRepo.FindByUserID(userID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get registrations by user ID",
|
|
zap.Uint("user_id", userID),
|
|
zap.Error(err),
|
|
)
|
|
return nil, fmt.Errorf("failed to get user registrations: %w", err)
|
|
}
|
|
|
|
s.logger.Debug("User registrations retrieved successfully",
|
|
zap.Uint("user_id", userID),
|
|
zap.Int("count", len(registrations)),
|
|
)
|
|
return registrations, nil
|
|
}
|
|
|
|
// GetRegistrationByEventAndUser возвращает регистрацию по событию и пользователю
|
|
func (s *eventRegistrationService) GetRegistrationByEventAndUser(eventID, userID uint) (*models.EventRegistration, error) {
|
|
s.logger.Debug("Getting registration by event and user",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Uint("user_id", userID),
|
|
)
|
|
|
|
registration, err := s.registrationRepo.FindByEventAndUser(eventID, userID)
|
|
if err != nil {
|
|
s.logger.Debug("Registration not found for event and user",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Uint("user_id", userID),
|
|
zap.Error(err),
|
|
)
|
|
return nil, fmt.Errorf("registration not found: %w", err)
|
|
}
|
|
|
|
s.logger.Debug("Registration by event and user retrieved successfully",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Uint("user_id", userID),
|
|
)
|
|
return registration, nil
|
|
}
|
|
|
|
// UpdateRegistration обновляет регистрацию
|
|
func (s *eventRegistrationService) UpdateRegistration(registration *models.EventRegistration) error {
|
|
s.logger.Info("Updating registration",
|
|
zap.Uint("registration_id", registration.ID),
|
|
zap.Uint("user_id", registration.UserID),
|
|
zap.Uint("event_id", registration.EventID),
|
|
)
|
|
|
|
// Проверяем существование регистрации
|
|
existingRegistration, err := s.registrationRepo.FindByID(registration.ID)
|
|
if err != nil {
|
|
s.logger.Warn("Registration not found for update",
|
|
zap.Uint("registration_id", registration.ID),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("registration not found")
|
|
}
|
|
|
|
// Сохраняем неизменяемые поля
|
|
registration.CreatedAt = existingRegistration.CreatedAt
|
|
|
|
if err := s.registrationRepo.Update(registration); err != nil {
|
|
s.logger.Error("Failed to update registration",
|
|
zap.Uint("registration_id", registration.ID),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to update registration: %w", err)
|
|
}
|
|
|
|
s.logger.Info("Registration updated successfully",
|
|
zap.Uint("registration_id", registration.ID),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// CancelRegistration отменяет регистрацию
|
|
func (s *eventRegistrationService) CancelRegistration(id uint) error {
|
|
s.logger.Info("Canceling registration", zap.Uint("registration_id", id))
|
|
|
|
// Получаем регистрацию для получения event_id
|
|
registration, err := s.registrationRepo.FindByID(id)
|
|
if err != nil {
|
|
s.logger.Warn("Registration not found for cancellation",
|
|
zap.Uint("registration_id", id),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("registration not found")
|
|
}
|
|
|
|
if err := s.registrationRepo.Delete(id); err != nil {
|
|
s.logger.Error("Failed to cancel registration",
|
|
zap.Uint("registration_id", id),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to cancel registration: %w", err)
|
|
}
|
|
|
|
// Обновляем счетчик участников
|
|
if err := s.eventRepo.UpdateParticipantsCount(registration.EventID, registration.Event.ParticipantsCount-1); err != nil {
|
|
s.logger.Error("Failed to update participants count after cancellation",
|
|
zap.Uint("event_id", registration.EventID),
|
|
zap.Error(err),
|
|
)
|
|
// Не прерываем выполнение, только логируем ошибку
|
|
}
|
|
|
|
s.logger.Info("Registration canceled successfully",
|
|
zap.Uint("registration_id", id),
|
|
zap.Uint("event_id", registration.EventID),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// UpdateRegistrationStatus обновляет статус регистрации
|
|
func (s *eventRegistrationService) UpdateRegistrationStatus(registrationID uint, status string) error {
|
|
s.logger.Info("Updating registration status",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("status", status),
|
|
)
|
|
|
|
validStatuses := []string{"pending", "confirmed", "cancelled", "completed"}
|
|
if !contains(validStatuses, status) {
|
|
s.logger.Warn("Invalid registration status",
|
|
zap.String("status", status),
|
|
zap.Strings("valid_statuses", validStatuses),
|
|
)
|
|
return fmt.Errorf("invalid status: %s", status)
|
|
}
|
|
|
|
if err := s.registrationRepo.UpdateStatus(registrationID, status); err != nil {
|
|
s.logger.Error("Failed to update registration status",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("status", status),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to update registration status: %w", err)
|
|
}
|
|
|
|
s.logger.Info("Registration status updated successfully",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("status", status),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// UpdateResultTime обновляет результат забега
|
|
func (s *eventRegistrationService) UpdateResultTime(registrationID uint, resultTime string) error {
|
|
s.logger.Info("Updating result time",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("result_time", resultTime),
|
|
)
|
|
|
|
if err := s.registrationRepo.UpdateResultTime(registrationID, resultTime); err != nil {
|
|
s.logger.Error("Failed to update result time",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("result_time", resultTime),
|
|
zap.Error(err),
|
|
)
|
|
return fmt.Errorf("failed to update result time: %w", err)
|
|
}
|
|
|
|
s.logger.Info("Result time updated successfully",
|
|
zap.Uint("registration_id", registrationID),
|
|
zap.String("result_time", resultTime),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// CheckEventAvailability проверяет доступность мест на событии
|
|
func (s *eventRegistrationService) CheckEventAvailability(eventID uint) (bool, error) {
|
|
s.logger.Debug("Checking event availability", zap.Uint("event_id", eventID))
|
|
|
|
event, err := s.eventRepo.FindByID(eventID)
|
|
if err != nil {
|
|
return false, fmt.Errorf("event not found: %w", err)
|
|
}
|
|
|
|
// Если максимальное количество участников не установлено, считаем доступным
|
|
if event.MaxParticipants == 0 {
|
|
return true, nil
|
|
}
|
|
|
|
// Получаем текущее количество подтвержденных регистраций
|
|
currentCount, err := s.registrationRepo.CountByEventID(eventID)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to count registrations: %w", err)
|
|
}
|
|
|
|
available := int(currentCount) < event.MaxParticipants
|
|
|
|
s.logger.Debug("Event availability check completed",
|
|
zap.Uint("event_id", eventID),
|
|
zap.Int64("current_count", currentCount),
|
|
zap.Int("max_participants", event.MaxParticipants),
|
|
zap.Bool("available", available),
|
|
)
|
|
|
|
return available, nil
|
|
}
|
|
|
|
// contains проверяет наличие строки в слайсе
|
|
func contains(slice []string, item string) bool {
|
|
for _, s := range slice {
|
|
if s == item {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|