package app import ( "context" "crypto/subtle" "encoding/json" "errors" "io" "net/http" "strconv" "time" "evening_detective_server/internal/repos/teams_repo" "evening_detective_server/internal/services/game_service" ) // TeamRegistrationHandler принимает webhook Яндекс Форм отдельно от пользовательского JWT. func TeamRegistrationHandler(token string, register func(context.Context, int, string, game_service.Registration) (int, error)) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "no-store") fail := func(code int, message string) { w.WriteHeader(code) _ = json.NewEncoder(w).Encode(map[string]string{"error": message}) } if token == "" { fail(http.StatusServiceUnavailable, "Интеграция регистрации не настроена") return } if subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), []byte("Bearer "+token)) != 1 { fail(http.StatusUnauthorized, "Неверный токен интеграции") return } gameID, err := strconv.ParseInt(r.PathValue("id"), 10, 32) deliveryID := r.Header.Get("X-Delivery-Id") if err != nil || gameID <= 0 || deliveryID == "" || len(deliveryID) > 255 { fail(http.StatusBadRequest, "Требуются ID игры и заголовок X-Delivery-Id (до 255 байт)") return } decoder := json.NewDecoder(http.MaxBytesReader(w, r.Body, 16<<10)) decoder.DisallowUnknownFields() var registration game_service.Registration if err := decoder.Decode(®istration); err != nil { fail(http.StatusBadRequest, "Некорректный JSON регистрации") return } if err := decoder.Decode(new(any)); err != io.EOF { fail(http.StatusBadRequest, "Ожидается один JSON-объект") return } ctx, cancel := context.WithTimeout(r.Context(), 4*time.Second) defer cancel() id, err := register(ctx, int(gameID), deliveryID, registration) switch { case errors.Is(err, game_service.ErrInvalidRegistration): fail(http.StatusBadRequest, err.Error()) case errors.Is(err, teams_repo.ErrRegistrationClosed): fail(http.StatusConflict, err.Error()) case err != nil: fail(http.StatusInternalServerError, "Не удалось зарегистрировать команду") default: _ = json.NewEncoder(w).Encode(map[string]int{"id": id}) } }) }