Skip to content

Commit

Permalink
chore: add more dump modes to shoga (#50)
Browse files Browse the repository at this point in the history
* chore: add more dump modes to shoga

* chore: mode required

* fix: throw error from walktable

* chore: dump regs

* chore: dump ips

* docs: minor

* chore: witherror
  • Loading branch information
Gornak40 authored Nov 17, 2024
1 parent 40a924a commit 15778ba
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 42 deletions.
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Extended release notes can be found at [chat](https://t.me/algolymp).
| [pepel](#pepel) | generate hasher solution | | ||
| [ripper](#ripper) | change runs status | 🦍 | ||
| [scalp](#scalp) | incremental scoring | | 🦍 ||
| [shoga](#shoga) | dump registered users | 🦍 | ||
| [shoga](#shoga) | dump contest tables | 🦍 | ||
| [valeria](#valeria) | valuer.cfg + tex scoring | | 🦍 ||
| [vydra](#vydra) | upload package | | 🦍 | 🧪 |
| [wooda](#wooda) | glob problem files upload | | 🦍 ||
Expand Down Expand Up @@ -477,16 +477,26 @@ scalp -i 330328 -s
![scalp logo](https://algolymp.ru/static/img/scalp.png)

## shoga
*Dump Ejudge contest users.*
*Dump Ejudge contest tables.*

### About

Print Ejudges users who registered in the specified contest (CSV format).
Print Ejudges contest tables (CSV format). Various modes are supported.

You can use some custom CSV toolkits, like [xsv](https://github.com/BurntSushi/xsv.git) or [qsv](https://github.com/jqnatividad/qsv.git) to process the output. But I prefer to use vanilla [awk](https://www.opennet.ru/man.shtml?topic=awk).
**Tip:** You can use some custom CSV toolkits, like [xsv](https://github.com/BurntSushi/xsv.git) or [qsv](https://github.com/jqnatividad/qsv.git) to process the output. But I prefer to use vanilla [awk](https://manpages.org/awk) or [cut](https://manpages.org/cut).

#### Supported modes

- `usr` - registered users
- `run` - contest runs
- `stn` - contest standings
- `prb` - contest problems
- `reg` - registration passwords
- `ips` - user IPs

### Flags
- `-i` - contest id (required)
- `-m` - dump mode (required, `usr|run|stn|prb|reg|ips`)

### Config
- `ejudge.url`
Expand All @@ -496,8 +506,16 @@ You can use some custom CSV toolkits, like [xsv](https://github.com/BurntSushi/x
### Examples
```bash
shoga --help
shoga -i 55000
shoga -i 59000 | awk '{split($0,a,";"); print a[2]}'
shoga -i 59000 -m usr # registered users
shoga -i 59000 -m usr | awk '{split($0,a,";"); print a[2]}' # just registered logins
shoga -i 60705 -m usr | cut -d ';' -f 2 | tail -n +2 | sort # just registered logins
shoga -i 55000 -m run # contest runs
shoga -i 436 -m stn # full standings
shoga -i 436 -m stn | cut -d ";" -f 1,2,9,10 | head -n -3 # 6 problems acm contest standings
shoga -i 48005 -m prb # contest problems
shoga -i 51000 -m reg # registration passwords
shoga -i 51000 -m reg | grep myav | cut -d ';' -f 3,6 # specified password
shoga -i 434 -m ips # user IPs
```

![shoga logo](https://algolymp.ru/static/img/shoga.png)
Expand Down Expand Up @@ -556,7 +574,7 @@ This tool uses `problem.xml` for uploading all package content.

Useful for migration between `polygon.lksh.ru` and `polygon.codeforces.com`.

Designed designed as an alternative to [polygon-cli](https://github.com/kunyavskiy/polygon-cli).
Designed as an alternative to [polygon-cli](https://github.com/kunyavskiy/polygon-cli).

**Ensure that the problem you are uploading the package into is empty.**

Expand Down
41 changes: 36 additions & 5 deletions cmd/shoga/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main

import (
"fmt"
"io"
"os"

"github.com/Gornak40/algolymp/config"
Expand All @@ -10,12 +10,26 @@ import (
"github.com/sirupsen/logrus"
)

const (
modeUsers = "usr"
modeRuns = "run"
modeStandings = "stn"
modeProblems = "prb"
modePasswords = "reg"
modeIPs = "ips"
)

func main() {
parser := argparse.NewParser("shoga", "Dump Ejudge contest users.")
parser := argparse.NewParser("shoga", "Dump Ejudge contest tables.")
cID := parser.Int("i", "cid", &argparse.Options{
Required: true,
Help: "Ejudge contest ID",
})
av := []string{modeUsers, modeRuns, modeStandings, modeProblems, modePasswords, modeIPs}
mode := parser.Selector("m", "mode", av, &argparse.Options{
Required: true,
Help: "Dump mode",
})
if err := parser.Parse(os.Args); err != nil {
logrus.WithError(err).Fatal("bad arguments")
}
Expand All @@ -33,11 +47,28 @@ func main() {
logrus.WithError(err).Fatal("master login failed")
}

list, err := ejClient.DumpUsers(csid)
var call func(csid string) (io.Reader, error)
switch *mode {
case modeUsers:
call = ejClient.DumpUsers
case modeRuns:
call = ejClient.DumpRuns
case modeStandings:
call = ejClient.DumpStandings
case modeProblems:
call = ejClient.DumpProbStats
case modePasswords:
call = ejClient.DumpRegPasswords
case modeIPs:
call = ejClient.DumpIPs
}
r, err := call(csid)
if err != nil {
logrus.WithError(err).Fatal("dump users failed")
logrus.WithError(err).WithField("mode", *mode).Fatal("dump failed")
}
if _, err := io.Copy(os.Stdout, r); err != nil {
logrus.WithError(err).Fatal("write dumped content failed")
}
fmt.Println(list) //nolint:forbidigo // Basic functionality.

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

import (
"bytes"
"encoding/csv"
"io"
"net/url"
"strings"

"github.com/PuerkitoBio/goquery"
"github.com/sirupsen/logrus"
)

const (
defBufSize = 1024
)

func (ej *Ejudge) DumpUsers(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump contest users")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"132"},
})
if err != nil {
return nil, err
}

return strings.NewReader(doc.Text()), nil // TODO: fix trimspace
}

func (ej *Ejudge) DumpRuns(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump contest runs")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"152"},
})
if err != nil {
return nil, err
}

return strings.NewReader(doc.Text()), nil
}

func (ej *Ejudge) DumpStandings(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump contest standings")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"94"},
})
if err != nil {
return nil, err
}
th := doc.Find("table.standings > tbody > tr")

return walkTable(th)
}

func (ej *Ejudge) DumpProbStats(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump problem stats")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"309"},
})
if err != nil {
return nil, err
}
th := doc.Find("table.b1 > tbody > tr")

return walkTable(th)
}

func (ej *Ejudge) DumpRegPasswords(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump registration passwords")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"120"},
})
if err != nil {
return nil, err
}
th := doc.Find("table.b1 > tbody > tr")

return walkTable(th)
}

func (ej *Ejudge) DumpIPs(csid string) (io.Reader, error) {
logrus.WithFields(logrus.Fields{
"CSID": csid,
}).Info("dump user IPs")
_, doc, err := ej.postRequest(newMaster, url.Values{
"SID": {csid},
"action": {"235"},
})
if err != nil {
return nil, err
}
th := doc.Find("table.b1 > tbody > tr")

return walkTable(th)
}

func walkTable(table *goquery.Selection) (io.Reader, error) {
bf := bytes.NewBuffer(make([]byte, 0, defBufSize))
w := csv.NewWriter(bf)
w.Comma = ';'

var err error
table.EachWithBreak(func(_ int, row *goquery.Selection) bool {
cols := row.Find("th, td")
rec := make([]string, 0, cols.Length())
cols.Each(func(_ int, s *goquery.Selection) {
rec = append(rec, s.Text())
})
if err = w.Write(rec); err != nil {
return false
}

return true
})
w.Flush()

return strings.NewReader(bf.String()), err
}
Loading

0 comments on commit 15778ba

Please sign in to comment.