Skip to content

Commit

Permalink
feat: valeria valuer builder (using api)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gornak40 committed Nov 22, 2023
1 parent 3549067 commit 493502e
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
go.work
ejik
config/config.json
valeria
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ linters:
- nlreturn
- goerr113
- exhaustruct
- godox
- varnamelen
- cyclop
11 changes: 2 additions & 9 deletions cmd/ejik/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"fmt"
"os"

"github.com/Gornak40/algolymp/config"
Expand All @@ -11,7 +10,7 @@ import (
)

func main() {
parser := argparse.NewParser("algolymp", "Algolymp contest manager")
parser := argparse.NewParser("ejik", "Ejudge contest config reloader")
cIDArg := parser.Int("i", "cid", &argparse.Options{
Required: true,
Help: "Ejudge contest ID",
Expand All @@ -20,17 +19,11 @@ func main() {
Required: false,
Help: "Show full output of check contest settings",
})
confDir, _ := os.UserHomeDir()
configArg := parser.String("c", "config", &argparse.Options{
Required: false,
Help: "JSON config path",
Default: fmt.Sprintf("%s/.config/algolymp/config.json", confDir),
})
if err := parser.Parse(os.Args); err != nil {
logrus.WithError(err).Fatal("bad arguments")
}

cfg := config.NewConfig(*configArg)
cfg := config.NewConfig()
ejClient := ejudge.NewEjudge(&cfg.Ejudge)

sid, err := ejClient.Login()
Expand Down
9 changes: 7 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ package config

import (
"encoding/json"
"fmt"
"os"

"github.com/Gornak40/algolymp/ejudge"
"github.com/Gornak40/algolymp/polygon"
"github.com/sirupsen/logrus"
)

type Config struct {
Ejudge ejudge.Config `json:"ejudge"`
Ejudge ejudge.Config `json:"ejudge"`
Polygon polygon.Config `json:"polygon"`
}

func NewConfig(path string) *Config {
func NewConfig() *Config {
confDir, _ := os.UserHomeDir()
path := fmt.Sprintf("%s/.config/algolymp/config.json", confDir)
data, err := os.ReadFile(path)
if err != nil {
logrus.WithError(err).Fatal("failed to read config")
Expand Down
167 changes: 167 additions & 0 deletions polygon/polygon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package polygon

import (
"crypto/sha512"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"

"github.com/sirupsen/logrus"
)

const (
sixSecretSymbols = "gorill"
)

type Config struct {
URL string `json:"url"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
}

type Polygon struct {
cfg *Config
}

func NewPolygon(cfg *Config) *Polygon {
return &Polygon{
cfg: cfg,
}
}

func (p *Polygon) makeQuery(method string, params url.Values) ([]byte, error) {
url, _ := url.JoinPath(p.cfg.URL, "api", method)
logrus.WithFields(logrus.Fields{"params": params.Encode()}).Info(method)

params["apiKey"] = []string{p.cfg.APIKey}
params["time"] = []string{fmt.Sprint(time.Now().Unix())}
sig := fmt.Sprintf("%s/%s?%s#%s", sixSecretSymbols, method, params.Encode(), p.cfg.APISecret)

b := sha512.Sum512([]byte(sig))
hsh := hex.EncodeToString(b[:])
params["apiSig"] = []string{sixSecretSymbols + hsh}

url = fmt.Sprintf("%s?%s", url, params.Encode())
resp, err := http.Get(url) //nolint:gosec,noctx // it's just get query, relax
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}

type TestAnswer struct {
Index int `json:"index"`
Group string `json:"group"`
Points float32 `json:"points"`
}

type GroupAnswer struct {
Name string `json:"name"`
PointsPolicy string `json:"pointsPolicy"`
FeedbackPolicy string `json:"feedbackPolicy"`
Dependencies []string `json:"dependencies"`
Tests int `json:"tests"`
}

type Answer struct {
Status string `json:"status"`
Comment string `json:"comment"`
Result json.RawMessage `json:"result"`
}

func (p *Polygon) getGroups(pID int) ([]GroupAnswer, error) {
data, err := p.makeQuery("problem.viewTestGroup", url.Values{
"problemId": []string{fmt.Sprint(pID)},
"testset": []string{"tests"},
})
if err != nil {
return nil, err
}
var ansG Answer
if err := json.Unmarshal(data, &ansG); err != nil {
return nil, err
}
if ansG.Status != "OK" {
return nil, errors.New(ansG.Comment)
}
var groups []GroupAnswer
_ = json.Unmarshal(ansG.Result, &groups)
return groups, nil
}

func (p *Polygon) getTests(pID int) ([]TestAnswer, error) {
data, err := p.makeQuery("problem.tests", url.Values{
"problemId": []string{fmt.Sprint(pID)},
"testset": []string{"tests"},
})
if err != nil {
return nil, err
}
var ansT Answer
if err := json.Unmarshal(data, &ansT); err != nil {
return nil, err
}
if ansT.Status != "OK" {
return nil, errors.New(ansT.Comment)
}
var tests []TestAnswer
_ = json.Unmarshal(ansT.Result, &tests)
return tests, nil
}

func (p *Polygon) GetValuer(pID int) error {
groups, err := p.getGroups(pID)
if err != nil {
return err
}

tests, err := p.getTests(pID)
if err != nil {
return err
}

score := map[string]int{}
count := map[string]int{}
first := map[string]int{}
last := map[string]int{}

for _, t := range tests {
score[t.Group] += int(t.Points) // TODO: ensure ejudge doesn't support float points
count[t.Group]++
if val, ok := first[t.Group]; !ok || val > t.Index {
first[t.Group] = t.Index
}
if val, ok := last[t.Group]; !ok || val < t.Index {
last[t.Group] = t.Index
}
}

res := []string{}
for _, g := range groups {
if g.PointsPolicy != "COMPLETE_GROUP" {
return errors.New("test_score not supported yet")
}
if last[g.Name]-first[g.Name]+1 != count[g.Name] {
return errors.New("bad tests order, fix in polygon required")
}
cur := fmt.Sprintf("group %s {\n\ttests %d-%d;\n\tscore %d;\n",
g.Name, first[g.Name], last[g.Name], score[g.Name])
if len(g.Dependencies) != 0 {
cur += fmt.Sprintf("\trequires %s;\n", strings.Join(g.Dependencies, ","))
}
cur += "}\n"
res = append(res, cur)
}

valuer := strings.Join(res, "\n")
logrus.Info(valuer)

return nil
}

0 comments on commit 493502e

Please sign in to comment.