package main import ( "encoding/json" "fmt" "log" "os" "path/filepath" "time" "srs.epita.fr/fic-server/libfic" ) var ( noValidateChallenge bool ) type Walker struct { LastSync map[string]*TSValue Exercices AirbusExercicesBindings Teams map[string]fic.ExportedTeam RevTeams map[string]string TeamBindings map[string]*AirbusTeam API AirbusAPI Coeff float64 } func (w *Walker) fetchTeams() error { teams, err := w.API.GetTeams() if err != nil { return err } w.RevTeams = map[string]string{} w.TeamBindings = map[string]*AirbusTeam{} for tid, team := range w.Teams { for _, t := range teams { if team.Name == t.Name || team.ExternalId == t.Name { w.TeamBindings[tid] = &t break } } if _, ok := w.TeamBindings[tid]; !ok { log.Printf("Team binding not found: %s - %s", tid, team.Name) } w.RevTeams[team.Name] = tid } return nil } func (w *Walker) treat(path string) error { teamid := filepath.Base(filepath.Dir(path)) if _, ok := w.TeamBindings[teamid]; ok { return w.TreatScoreGrid(path, w.TeamBindings[teamid]) } return nil } func (w *Walker) LoadScoreState(path string) (int64, error) { mypath := filepath.Join(filepath.Dir(path), "airbus.json") if _, err := os.Stat(mypath); os.IsNotExist(err) { fd, err := os.Create(mypath) if err != nil { return 0, err } defer fd.Close() fd.Write([]byte("0")) return 0, nil } fd, err := os.Open(mypath) if err != nil { return 0, err } defer fd.Close() var ret int64 jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return 0, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return ret, nil } func (w *Walker) LoadScoreGrid(path string) ([]fic.ScoreGridRow, error) { fd, err := os.Open(filepath.Join(filepath.Dir(path), "scores.json")) if err != nil { return nil, err } defer fd.Close() var ret []fic.ScoreGridRow jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return nil, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return ret, nil } func (w *Walker) WalkScoreSync(path string, d os.DirEntry, err error) error { if filepath.Base(path) == "scores.json" { return w.treat(path) } return nil } func (w *Walker) loadMyFile(path string) (*fic.MyTeam, error) { fd, err := os.Open(path) if err != nil { return nil, err } defer fd.Close() var ret fic.MyTeam jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return nil, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return &ret, nil } func (w *Walker) WalkScore(path string, d os.DirEntry, err error) error { if filepath.Base(path) == "scores.json" { go w.treat(path) } return nil } func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { // Read score grid fdscores, err := os.Open(path) if err != nil { return err } defer fdscores.Close() teamscores, err := fic.ReadScoreGrid(fdscores) if err != nil { return err } // Found all new entries maxts := &TSValue{ Time: time.Time{}, } if ts, ok := w.LastSync[airbusTeam.Name]; ok { maxts = ts } for _, row := range teamscores { if row.Time.After(maxts.Time) { maxts.Time = row.Time } if ts, ok := w.LastSync[airbusTeam.Name]; !ok || row.Time.After(ts.Time) { if !noValidateChallenge && row.Reason == "Validation" { err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice]) } else { err = w.API.AwardUser(airbusTeam, int64(row.Points*row.Coeff*w.Coeff), row.Reason) } if err != nil { return err } maxts.Score += int64(row.Points * row.Coeff * w.Coeff) } } w.LastSync[airbusTeam.Name] = maxts return nil } func (w *Walker) BalanceScores() error { for team, ts := range w.LastSync { team_id, ok := w.RevTeams[team] if !ok { continue } myteam, err := w.loadMyFile(filepath.Join(TeamsDir, team_id, "my.json")) if err != nil { return fmt.Errorf("Unable to open %s/my.json: %w", team_id, err) } airbusTeam := w.TeamBindings[fmt.Sprintf("%d", myteam.Id)] if ts.Score != myteam.Points*int64(w.Coeff) { err := w.API.AwardUser(airbusTeam, myteam.Points*int64(w.Coeff)-ts.Score, "Équilibrage") if err != nil { return fmt.Errorf("Unable to open %s/my.json: %w", team, err) } w.LastSync[airbusTeam.Name].Score = myteam.Points * int64(w.Coeff) w.LastSync[airbusTeam.Name].Time = time.Now() } } return nil }