package handlers import ( "context" "fmt" "net/http" "strconv" "git.haelnorr.com/h/golib/hws" "git.haelnorr.com/h/oslstats/internal/db" "git.haelnorr.com/h/oslstats/internal/notify" "git.haelnorr.com/h/oslstats/internal/respond" "git.haelnorr.com/h/oslstats/internal/validation" "git.haelnorr.com/h/oslstats/internal/view/seasonsview" "github.com/pkg/errors" "github.com/uptrace/bun" ) func GenerateFixtures( s *hws.Server, conn *db.DB, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { getter, ok := validation.ParseFormOrNotify(s, w, r) if !ok { return } seasonShortName := getter.String("season_short_name").TrimSpace().Required().Value leagueShortName := getter.String("league_short_name").TrimSpace().Required().Value round := getter.Int("round").Required().Value if !getter.ValidateAndNotify(s, w, r) { return } var season *db.Season var league *db.League var fixtures []*db.Fixture if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) { _, err := db.NewRound(ctx, tx, seasonShortName, leagueShortName, round, db.NewAudit(r, nil)) if err != nil { if db.IsBadRequest(err) { respond.BadRequest(w, errors.Wrap(err, "db.NewRound")) return false, nil } return false, errors.Wrap(err, "db.NewRound") } season, league, fixtures, err = db.GetFixtures(ctx, tx, seasonShortName, leagueShortName) if err != nil { return false, errors.Wrap(err, "db.GetFixtures") } return true, nil }); !ok { return } renderSafely(seasonsview.SeasonLeagueManageFixtures(season, league, fixtures), s, r, w) }) } func UpdateFixtures( s *hws.Server, conn *db.DB, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { getter, ok := validation.ParseFormOrNotify(s, w, r) if !ok { return } seasonShortName := getter.String("season_short_name").TrimSpace().Required().Value leagueShortName := getter.String("league_short_name").TrimSpace().Required().Value allocations := getter.GetMaps("allocations") if !getter.ValidateAndNotify(s, w, r) { w.WriteHeader(http.StatusBadRequest) return } updates, err := mapUpdates(allocations) if err != nil { respond.BadRequest(w, errors.Wrap(err, "strconv.Atoi")) return } var fixtures []*db.Fixture if !conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) { var err error _, _, fixtures, err = db.GetFixtures(ctx, tx, seasonShortName, leagueShortName) if err != nil { if db.IsBadRequest(err) { respond.BadRequest(w, errors.Wrap(err, "db.NewRound")) return false, nil } return false, errors.Wrap(err, "db.GetFixtures") } var valid bool fixtures, valid = updateFixtures(fixtures, updates) fmt.Println(len(fixtures)) if !valid { notify.Warn(s, w, r, "Invalid game weeks", "A game week is missing or has no games", nil) return false, nil } err = db.UpdateFixtureGameWeeks(ctx, tx, fixtures, db.NewAudit(r, nil)) if err != nil { if db.IsBadRequest(err) { respond.BadRequest(w, errors.Wrap(err, "db.UpdateFixtureGameWeeks")) } return false, errors.Wrap(err, "db.UpdateFixtureGameWeeks") } return true, nil }) { return } notify.Success(s, w, r, "Fixtures Updated", "Fixtures successfully updated", nil) }) } func DeleteFixture( s *hws.Server, conn *db.DB, ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fixtureIDstr := r.PathValue("fixture_id") fixtureID, err := strconv.Atoi(fixtureIDstr) if err != nil { respond.BadRequest(w, errors.Wrap(err, "strconv.Atoi")) return } if !conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) { err := db.DeleteFixture(ctx, tx, fixtureID, db.NewAudit(r, nil)) if err != nil { if db.IsBadRequest(err) { respond.NotFound(w, errors.Wrap(err, "db.DeleteFixture")) return false, nil } return false, errors.Wrap(err, "db.DeleteFixture") } return true, nil }) { return } }) } func mapUpdates(allocations []map[string]string) (map[int]int, error) { updates := map[int]int{} for _, v := range allocations { id, err := strconv.Atoi(v["id"]) if err != nil { return nil, errors.Wrap(err, "strconv.Atoi") } gameWeek, err := strconv.Atoi(v["game_week"]) if err != nil { return nil, errors.Wrap(err, "strconv.Atoi") } updates[id] = gameWeek } return updates, nil } func updateFixtures(fixtures []*db.Fixture, updates map[int]int) ([]*db.Fixture, bool) { updated := []*db.Fixture{} gameWeeks := map[int]int{} for _, fixture := range fixtures { if gameWeek, exists := updates[fixture.ID]; exists { var newValue *int var oldValue int if fixture.GameWeek != nil { oldValue = *fixture.GameWeek } else { oldValue = 0 } if gameWeek == 0 { newValue = nil } else { newValue = &gameWeek } if gameWeek != oldValue { fixture.GameWeek = newValue updated = append(updated, fixture) } // fuck i hate pointers sometimes } if fixture.GameWeek != nil { gameWeeks[*fixture.GameWeek]++ } } for i := range len(gameWeeks) { count, exists := gameWeeks[i+1] if !exists || count < 1 { return nil, false } } return updated, true }