Files
tp/serv_nginx/api_bb/internal/service/event_registration_service.go
T
valitovgaziz 6422d85727 modified: serv_nginx/api_bb/internal/database/migrate.go
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
2025-10-19 10:54:45 +05:00

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
}