server/remote/challenge-sync-airbus/treat.go

214 lines
4.4 KiB
Go

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 i, t := range teams {
if team.Name == t.Name || team.ExternalId == t.Name {
w.TeamBindings[tid] = &teams[i]
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
}