Skip to content

Commit

Permalink
feat: ripper runs status changer (#20)
Browse files Browse the repository at this point in the history
* feat: ripper runs status changer

* fix: rejudge for rejudge, not empty; less verdicts
  • Loading branch information
Gornak40 authored Feb 22, 2024
1 parent 8792ef3 commit 30e96ad
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 48 deletions.
32 changes: 0 additions & 32 deletions .github/workflows/auto-tag.yml

This file was deleted.

1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ linters:
- depguard
- wsl
- wrapcheck
- goerr113
- exhaustruct
- godox

Expand Down
53 changes: 48 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,23 @@
| [boban](#boban) | filter runs | 🦍 | ||
| [casper](#casper) | change visibility | 🦍 | ||
| [ejik](#ejik) | commit + check + reload | 🦍 | ||
| [ripper](#ripper) | change runs status | 🦍 | ||
| [scalp](#scalp) | incremental scoring | | 🦍 ||
| [valeria](#valeria) | valuer.cfg + tex scoring | | 🦍 ||
| 👻 | change runs status | 🦍 | | 🧑‍💻 |
| 👻 | list/commit problems | | 🦍 | 🧑‍💻 |
| 👻 | regexp problem upload | | 🦍 | 🤔 |
| 👻 | download/upload package | | 🦍 | 🤔 |
| 👻 | import polygon problem | 🦍 | 🦍 | 🤔 |
| 👻 | autogen static problem | 🦍 | | 🤔 |

### Icons

- ✅ Done
- 🧑‍💻 In progress
- 🤔 To do
- 👻 Name placeholder
- 🦍 Engines usage

## Build
```bash
sudo apt install go
Expand Down Expand Up @@ -57,7 +65,7 @@ Put your config file in `~/.config/algolymp/config.json`.
2. Commit changes;
3. *(Optional)* Open contest xml config for editing.

Useful before running `polygon-to-ejudge`.
Useful before running [polygon-to-ejudge](https://github.com/grphil/polygon-to-ejudge).

### Flags
- `-i` - new contest id (required)
Expand Down Expand Up @@ -85,7 +93,7 @@ blanka -i 51013 -t 51000 -e

### Abount

Filter and print Ejudge runs IDs in specified contest.
Filter and print Ejudge runs ids.

### Flags
- `-i` - contest id (required)
Expand Down Expand Up @@ -115,7 +123,7 @@ boban -i 50014 -c 10000 2> /dev/null | wc -l
- Make contest visible;
- Make contest invisible.

Useful with bash `for` loop after the end of the year.
Useful with bash `for` loop at the end of the year.

### Flags
- `-i` - contest id (required)
Expand Down Expand Up @@ -145,7 +153,9 @@ for i in {41014..41023}; do casper -i $i; done
2. Check contest settings;
3. Reload config files.

Useful after running `polygon-to-ejudge`.
Useful after running [polygon-to-ejudge](https://github.com/grphil/polygon-to-ejudge).

Feel free to use it after every change

### Flags
- `-i` - contest id (required)
Expand All @@ -165,6 +175,39 @@ ejik -i 40507

![ejik logo](https://algolymp.ru/static/img/ejik.png)

## ripper
*Change Ejudge runs status.*

### About

Change runs status. Designed to work with [boban](#boban) or with raw ids from `stdin`.

**Be careful** using it, double check the [parameters](https://ejudge.ru/wiki/index.php/%D0%92%D0%B5%D1%80%D0%B4%D0%B8%D0%BA%D1%82%D1%8B_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F).

`RJ` is reject, not rejudge. Use `rejudge` status for rejudge.

### Flags
- `-i` - contest id (required)
- `-s` - new status (required, `DQ|IG|OK|PR|RJ|SM|SV|rejudge`)

### Config
- `ejudge.url`
- `ejudge.login`
- `ejudge.password`

### Examples

```bash
ripper --help
ripper -i 51023 -s RJ # read from stdin
cat banlist.txt | ripper -i 47110 -s DQ # ban submits with list
boban -i 52010 -f "prob == 'D' && score >= 50" -c 10000 | ripper -i 52010 -s rejudge # rejudge incorrect group
boban -i 50014 -f "login == 'barmaley' && status == OK" | ripper -i 50014 -s SM # torture a participant
boban -i 48001 -f "status == PR" -c 2000 | ripper -i 48001 -s OK # smart code-review
```

![ripper logo](https://algolymp.ru/static/img/ripper.png)

## scalp
*Set incremental problem scoring using Polygon API.*

Expand Down
1 change: 0 additions & 1 deletion cmd/boban/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ func main() {
for _, run := range runs {
fmt.Println(run) //nolint:forbidigo // Basic functionality.
}
logrus.WithField("runs", len(runs)).Info("filter result")

if err := ejClient.Logout(sid); err != nil {
logrus.WithError(err).Fatal("logout failed")
Expand Down
67 changes: 67 additions & 0 deletions cmd/ripper/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"errors"
"fmt"
"io"
"os"
"sort"

"github.com/Gornak40/algolymp/config"
"github.com/Gornak40/algolymp/ejudge"
"github.com/akamensky/argparse"
"github.com/sirupsen/logrus"
)

func main() {
verdicts := make([]string, 0, len(ejudge.Verdicts))
for v := range ejudge.Verdicts {
verdicts = append(verdicts, v)
}
sort.Strings(verdicts)

parser := argparse.NewParser("ripper", "Change Ejudge runs status (stdin input).")
cID := parser.Int("i", "cid", &argparse.Options{
Required: true,
Help: "Ejudge contest ID",
})
status := parser.Selector("s", "status", verdicts, &argparse.Options{
Required: true,
Help: "New runs status",
})
if err := parser.Parse(os.Args); err != nil {
logrus.WithError(err).Fatal("bad arguments")
}

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

sid, err := ejClient.Login()
if err != nil {
logrus.WithError(err).Fatal("login failed")
}

csid, err := ejClient.MasterLogin(sid, *cID)
if err != nil {
logrus.WithError(err).Fatal("master login failed")
}

logrus.Info("waiting for run ids input...")
for {
var runID int
_, err := fmt.Scanf("%d", &runID)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
logrus.WithError(err).Fatal("invalid run id")
}
if err := ejClient.ChangeRunStatus(csid, runID, *status); err != nil {
logrus.WithError(err).Fatal("failed change run status")
}
}

if err := ejClient.Logout(sid); err != nil {
logrus.WithError(err).Fatal("logout failed")
}
}
58 changes: 50 additions & 8 deletions ejudge/ejudge.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,24 @@ import (
const BadSID = "0000000000000000"

var (
ErrParseMasterSID = fmt.Errorf("can't parse master SID")
ErrParseMasterSID = errors.New("can't parse master SID")
ErrBadStatusCode = errors.New("bad status code")
ErrBadFilter = errors.New("bad filter expression")
ErrUnknownVerdict = errors.New("unknown verdict")
)

//nolint:gochecknoglobals,gomnd // ejudge constants
var Verdicts = map[string]int{
"OK": 0,
"IG": 9,
"DQ": 10,
"SV": 14,
"PR": 16,
"RJ": 17,
"SM": 23,
"rejudge": 99,
}

type Config struct {
URL string `json:"url"`
Login string `json:"login"`
Expand Down Expand Up @@ -55,7 +70,7 @@ func (ej *Ejudge) postRequest(method string, params url.Values) (*http.Request,
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("bad status code %d", resp.StatusCode)
return nil, nil, fmt.Errorf("%w: %d", ErrBadStatusCode, resp.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
Expand Down Expand Up @@ -97,7 +112,8 @@ func (ej *Ejudge) Logout(sid string) error {
}

func (ej *Ejudge) Lock(sid string, cid int) error {
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).Info("lock contest for editing")
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).
Info("lock contest for editing")
_, _, err := ej.postRequest("serve-control", url.Values{
"contest_id": {strconv.Itoa(cid)},
"SID": {sid},
Expand All @@ -122,8 +138,29 @@ func (ej *Ejudge) Commit(sid string) error {
return nil
}

func (ej *Ejudge) ChangeRunStatus(csid string, runID int, status string) error {
idx, ok := Verdicts[status]
if !ok {
return fmt.Errorf("%w: %s", ErrUnknownVerdict, status)
}
_, _, err := ej.postRequest("new-master", url.Values{
"SID": {csid},
"action": {"67"},
"run_id": {strconv.Itoa(runID)},
"status": {strconv.Itoa(idx)},
})
if err != nil {
return err
}
logrus.WithFields(logrus.Fields{"CSID": csid, "run": runID, "status": idx}).
Info("success set status")

return nil
}

func (ej *Ejudge) CheckContest(sid string, cid int, verbose bool) error {
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).Info("check contest settings, wait please")
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).
Info("check contest settings, wait please")
_, doc, err := ej.postRequest("serve-control", url.Values{
"contest_id": {strconv.Itoa(cid)},
"SID": {sid},
Expand All @@ -136,7 +173,8 @@ func (ej *Ejudge) CheckContest(sid string, cid int, verbose bool) error {
logrus.Info(doc.Find("font").Text())
}
status := doc.Find("h2").First().Text()
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).Infof("ejudge answer %q", status)
logrus.WithFields(logrus.Fields{"CID": cid, "SID": sid}).
Infof("ejudge answer %q", status)

return nil
}
Expand All @@ -154,7 +192,8 @@ func (ej *Ejudge) MasterLogin(sid string, cid int) (string, error) {
if csid == "" {
return "", ErrParseMasterSID
}
logrus.WithFields(logrus.Fields{"CID": cid, "CSID": csid, "SID": sid}).Info("success master login")
logrus.WithFields(logrus.Fields{"CID": cid, "CSID": csid, "SID": sid}).
Info("success master login")

return csid, nil
}
Expand All @@ -172,7 +211,7 @@ func (ej *Ejudge) FilterRuns(csid string, filter string, count int) ([]int, erro
}
ejErr := doc.Find("#container > pre")
if ejErr.Text() != "" {
return nil, errors.New(ejErr.Text())
return nil, fmt.Errorf("%w: %s", ErrBadFilter, ejErr.Text())
}
res := doc.Find("#container > table:nth-child(18) > tbody > tr > td:nth-child(1)")
digits := regexp.MustCompile("[^0-9]+")
Expand All @@ -187,6 +226,8 @@ func (ej *Ejudge) FilterRuns(csid string, filter string, count int) ([]int, erro
}
runs = append(runs, run)
}
logrus.WithFields(logrus.Fields{"CSID": csid, "count": len(runs)}).
Info("success filter runs")

return runs, nil
}
Expand Down Expand Up @@ -221,7 +262,8 @@ func (ej *Ejudge) CreateContest(sid string, cid int, tid int) error {
if status == "" {
status = "OK"
}
logrus.WithFields(logrus.Fields{"CID": cid, "TID": tid, "SID": sid}).Infof("ejudge answer %q", status)
logrus.WithFields(logrus.Fields{"CID": cid, "TID": tid, "SID": sid}).
Infof("ejudge answer %q", status)

return nil
}
Expand Down
Binary file added logos/ripper.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion polygon/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const (
defaultTestset = "tests"
)

var (
ErrBadPolygonStatus = errors.New("bad polygon status")
)

type Config struct {
URL string `json:"url"`
APIKey string `json:"apiKey"`
Expand Down Expand Up @@ -59,7 +63,7 @@ func (p *Polygon) makeQuery(method string, link string) (*Answer, error) {
return nil, err
}
if ans.Status != "OK" {
return nil, errors.New(ans.Comment)
return nil, fmt.Errorf("%w: %s", ErrBadPolygonStatus, ans.Comment)
}

return &ans, nil
Expand Down

0 comments on commit 30e96ad

Please sign in to comment.