refactor: twhelp - migrate to /v2 API endpoints
ci/woodpecker/pr/govulncheck Pipeline was successful Details
ci/woodpecker/pr/test Pipeline was successful Details

This commit is contained in:
Dawid Wysokiński 2024-04-30 10:35:24 +02:00
parent 3b60163b01
commit 3f9bd1335a
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
37 changed files with 611 additions and 1208 deletions

View File

@ -29,6 +29,11 @@ install-goose:
@echo "Installing github.com/pressly/goose..."
@(test -f $(GOOSE_PATH) && echo "github.com/pressly/goose is already installed. Skipping...") || (wget -q -O $(GOOSE_PATH) https://github.com/pressly/goose/releases/download/v3.20.0/goose_$(GOOS)_$(OSARCH) && chmod u+x $(GOOSE_PATH))
.PHONY: install-oapi-codegen
install-oapi-codegen:
@echo "Installing github.com/deepmap/oapi-codegen..."
@go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0
.PHONY: install-tools
install-tools: install-golangci-lint install-counterfeiter install-goose
@ -37,7 +42,7 @@ install-tools: install-golangci-lint install-counterfeiter install-goose
install: install-tools install-git-hooks
.PHONY: generate
generate: install-counterfeiter
generate: install-counterfeiter install-oapi-codegen
go generate ./...
.PHONY: create-sql-migration

View File

@ -16,7 +16,7 @@ type twhelpClientConfig struct {
URL *url.URL `envconfig:"URL" required:"true"`
Timeout time.Duration `envconfig:"TIMEOUT" default:"10s"`
RateLimiterEnabled bool `envconfig:"RATE_LIMITER_ENABLED" default:"false"`
RateLimiterMaxRequestsPerSecond float64 `envconfig:"RATE_LIMITER_MAX_REQUESTS_PER_SECOND" default:"10"`
RateLimiterMaxRequestsPerSecond float64 `envconfig:"RATE_LIMITER_MAX_REQUESTS_PER_SECOND" default:"50"`
RateLimiterRequestBurst int `envconfig:"RATE_LIMITER_REQUEST_BURST" default:"5"`
}
@ -27,6 +27,7 @@ func NewTWHelpService(version string) (*adapter.TWHelpHTTP, error) {
}
opts := []twhelp.ClientOption{
twhelp.WithBaseURL(cfg.URL.String()),
twhelp.WithHTTPClient(&http.Client{
Timeout: cfg.Timeout,
}),
@ -37,5 +38,10 @@ func NewTWHelpService(version string) (*adapter.TWHelpHTTP, error) {
opts = append(opts, twhelp.WithRateLimiter(rate.NewLimiter(rate.Limit(cfg.RateLimiterMaxRequestsPerSecond), cfg.RateLimiterRequestBurst)))
}
return adapter.NewTWHelpHTTP(twhelp.NewClient(cfg.URL, opts...)), nil
client, err := twhelp.NewClientWithResponses("", opts...)
if err != nil {
return nil, err
}
return adapter.NewTWHelpHTTP(client), nil
}

2
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/kelseyhightower/envconfig v1.4.0
github.com/nicksnyder/go-i18n/v2 v2.4.0
github.com/oapi-codegen/runtime v1.1.1
github.com/ory/dockertest/v3 v3.10.0
github.com/pressly/goose/v3 v3.20.0
github.com/redis/go-redis/v9 v9.5.1
@ -29,6 +30,7 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/continuity v0.4.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect

24
go.sum
View File

@ -2,13 +2,16 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@ -60,6 +63,7 @@ github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@ -78,12 +82,12 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nicksnyder/go-i18n/v2 v2.2.2 h1:Iv/FL6pvYmDqybEZkr4TrOv8jSHezwpE77K68kcaft8=
github.com/nicksnyder/go-i18n/v2 v2.2.2/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
@ -110,6 +114,7 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -142,7 +147,6 @@ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@ -153,12 +157,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -166,30 +168,22 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@ -198,7 +192,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -208,7 +201,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -71,7 +71,7 @@ func (g *GroupBunRepository) Update(ctx context.Context, id string, params domai
return g.Get(ctx, id)
}
func (g *GroupBunRepository) AddMonitor(ctx context.Context, id string, tribeID int64) (domain.GroupWithMonitors, error) {
func (g *GroupBunRepository) AddMonitor(ctx context.Context, id string, tribeID int) (domain.GroupWithMonitors, error) {
parsedID, err := uuid.Parse(id)
if err != nil {
return domain.GroupWithMonitors{}, domain.GroupDoesNotExistError{ID: id}
@ -287,7 +287,7 @@ func (l listGroupsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
return q
}
func mapAddMonitorError(err error, groupID string, tribeID int64) error {
func mapAddMonitorError(err error, groupID string, tribeID int) error {
var pgError pgdriver.Error
if !errors.As(err, &pgError) {
return err

View File

@ -158,7 +158,7 @@ func TestGroupBunRepository_AddMonitor(t *testing.T) {
t.Run("OK", func(t *testing.T) {
t.Parallel()
var tribeID int64 = 91283718
var tribeID int = 91283718
updatedGroup, err := repo.AddMonitor(context.Background(), group.ID, tribeID)
assert.NoError(t, err)

View File

@ -13,7 +13,7 @@ type Monitor struct {
ID uuid.UUID `bun:"id,pk,nullzero"`
GroupID uuid.UUID `bun:"group_id"`
TribeID int64 `bun:"tribe_id,nullzero"`
TribeID int `bun:"tribe_id,nullzero"`
CreatedAt time.Time `bun:"created_at,nullzero"`
}

View File

@ -3,6 +3,8 @@ package adapter
import (
"context"
"errors"
"slices"
"strings"
"time"
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
@ -10,57 +12,57 @@ import (
)
type TWHelpHTTP struct {
client *twhelp.Client
client *twhelp.ClientWithResponses
}
func NewTWHelpHTTP(client *twhelp.Client) *TWHelpHTTP {
func NewTWHelpHTTP(client *twhelp.ClientWithResponses) *TWHelpHTTP {
return &TWHelpHTTP{client: client}
}
func (t *TWHelpHTTP) ListVersions(ctx context.Context) ([]domain.TWVersion, error) {
versions, err := t.client.ListVersions(ctx)
resp, err := t.client.ListVersionsWithResponse(ctx, nil)
if err != nil {
return nil, err
}
if resp.JSONDefault != nil {
return nil, t.convertErrors(resp.JSONDefault.Errors)
}
res := make([]domain.TWVersion, 0, len(versions))
for _, v := range versions {
res := make([]domain.TWVersion, 0, len(resp.JSON200.Data))
for _, v := range resp.JSON200.Data {
res = append(res, t.convertVersionToDomain(v))
}
return res, nil
}
func (t *TWHelpHTTP) ListOpenServers(ctx context.Context, version string, offset, limit int32) ([]domain.TWServer, error) {
return t.listServers(ctx, version, twhelp.ListServersQueryParams{
Limit: limit,
Offset: offset,
Open: twhelp.NullBool{
Bool: true,
Valid: true,
},
func (t *TWHelpHTTP) ListOpenServers(ctx context.Context, versionCode string, limit int) ([]domain.TWServer, error) {
open := true
return t.listServers(ctx, versionCode, &twhelp.ListServersParams{
Limit: &limit,
Open: &open,
})
}
func (t *TWHelpHTTP) ListClosedServers(ctx context.Context, version string, offset, limit int32) ([]domain.TWServer, error) {
return t.listServers(ctx, version, twhelp.ListServersQueryParams{
Limit: limit,
Offset: offset,
Open: twhelp.NullBool{
Bool: false,
Valid: true,
},
func (t *TWHelpHTTP) ListClosedServers(ctx context.Context, versionCode string, limit int) ([]domain.TWServer, error) {
open := false
return t.listServers(ctx, versionCode, &twhelp.ListServersParams{
Limit: &limit,
Open: &open,
})
}
func (t *TWHelpHTTP) listServers(ctx context.Context, version string, params twhelp.ListServersQueryParams) ([]domain.TWServer, error) {
servers, err := t.client.ListServers(ctx, version, params)
func (t *TWHelpHTTP) listServers(ctx context.Context, versionCode string, params *twhelp.ListServersParams) ([]domain.TWServer, error) {
resp, err := t.client.ListServersWithResponse(ctx, versionCode, params)
if err != nil {
return nil, err
}
if resp.JSONDefault != nil {
return nil, t.convertErrors(resp.JSONDefault.Errors)
}
res := make([]domain.TWServer, 0, len(servers))
for _, s := range servers {
res := make([]domain.TWServer, 0, len(resp.JSON200.Data))
for _, s := range resp.JSON200.Data {
res = append(res, t.convertServerToDomain(s))
}
@ -72,60 +74,78 @@ func (t *TWHelpHTTP) GetOpenServer(ctx context.Context, versionCode, serverKey s
if err != nil {
return domain.TWServer{}, err
}
if !server.Open {
return domain.TWServer{}, domain.TWServerNotFoundError{
VersionCode: versionCode,
Key: serverKey,
}
}
return server, nil
}
func (t *TWHelpHTTP) GetServer(ctx context.Context, versionCode, serverKey string) (domain.TWServer, error) {
server, err := t.client.GetServer(ctx, versionCode, serverKey)
resp, err := t.client.GetServerWithResponse(ctx, versionCode, serverKey)
if err != nil {
var apiErr twhelp.APIError
if !errors.As(err, &apiErr) || apiErr.Code != twhelp.ErrorCodeEntityNotFound {
return domain.TWServer{}, err
}
return domain.TWServer{}, domain.TWServerNotFoundError{
VersionCode: versionCode,
Key: serverKey,
}
return domain.TWServer{}, err
}
return t.convertServerToDomain(server), nil
if resp.JSONDefault != nil {
if slices.ContainsFunc(resp.JSONDefault.Errors, func(err twhelp.Error) bool {
return err.Code == twhelp.ErrorCodeServerNotFound
}) {
return domain.TWServer{}, domain.TWServerNotFoundError{
VersionCode: versionCode,
Key: serverKey,
}
}
return domain.TWServer{}, t.convertErrors(resp.JSONDefault.Errors)
}
return t.convertServerToDomain(resp.JSON200.Data), nil
}
func (t *TWHelpHTTP) GetTribeByID(ctx context.Context, versionCode, serverKey string, id int64) (domain.Tribe, error) {
tribe, err := t.client.GetTribeByID(ctx, versionCode, serverKey, id)
func (t *TWHelpHTTP) GetTribeByID(ctx context.Context, versionCode, serverKey string, id int) (domain.Tribe, error) {
resp, err := t.client.GetTribeWithResponse(ctx, versionCode, serverKey, id)
if err != nil {
var apiErr twhelp.APIError
if !errors.As(err, &apiErr) || apiErr.Code != twhelp.ErrorCodeEntityNotFound {
return domain.Tribe{}, err
}
return domain.Tribe{}, domain.TribeIDNotFoundError{
VersionCode: versionCode,
ServerKey: serverKey,
ID: id,
}
return domain.Tribe{}, err
}
return t.convertTribeToDomain(tribe), nil
if resp.JSONDefault != nil {
if slices.ContainsFunc(resp.JSONDefault.Errors, func(err twhelp.Error) bool {
return err.Code == twhelp.ErrorCodeTribeNotFound
}) {
return domain.Tribe{}, domain.TribeIDNotFoundError{
VersionCode: versionCode,
ServerKey: serverKey,
ID: id,
}
}
return domain.Tribe{}, t.convertErrors(resp.JSONDefault.Errors)
}
return t.convertTribeToDomain(resp.JSON200.Data), nil
}
func (t *TWHelpHTTP) GetExistingTribeByTag(ctx context.Context, versionCode, serverKey, tribeTag string) (domain.Tribe, error) {
tribes, err := t.client.ListTribes(ctx, versionCode, serverKey, twhelp.ListTribesQueryParams{
Limit: 1,
Tags: []string{tribeTag},
Deleted: twhelp.NullBool{
Valid: true,
Bool: false,
},
deleted := false
tags := []string{tribeTag}
limit := 1
resp, err := t.client.ListTribesWithResponse(ctx, versionCode, serverKey, &twhelp.ListTribesParams{
Deleted: &deleted,
Tag: &tags,
Limit: &limit,
})
if err != nil {
return domain.Tribe{}, err
}
if resp.JSONDefault != nil {
return domain.Tribe{}, t.convertErrors(resp.JSONDefault.Errors)
}
if len(tribes) == 0 {
if len(resp.JSON200.Data) == 0 {
return domain.Tribe{}, domain.TribeTagNotFoundError{
VersionCode: versionCode,
ServerKey: serverKey,
@ -133,30 +153,23 @@ func (t *TWHelpHTTP) GetExistingTribeByTag(ctx context.Context, versionCode, ser
}
}
return t.convertTribeToDomain(tribes[0]), nil
return t.convertTribeToDomain(resp.JSON200.Data[0]), nil
}
func (t *TWHelpHTTP) ListTribesByTag(
ctx context.Context,
versionCode, serverKey string,
tribeTags []string,
offset, limit int32,
) ([]domain.Tribe, error) {
tribes, err := t.client.ListTribes(ctx, versionCode, serverKey, twhelp.ListTribesQueryParams{
Limit: limit,
Offset: offset,
Tags: tribeTags,
Deleted: twhelp.NullBool{
Valid: true,
Bool: false,
},
func (t *TWHelpHTTP) ListTribesByTag(ctx context.Context, versionCode, serverKey string, tribeTags []string, limit int) ([]domain.Tribe, error) {
resp, err := t.client.ListTribesWithResponse(ctx, versionCode, serverKey, &twhelp.ListTribesParams{
Tag: &tribeTags,
Limit: &limit,
})
if err != nil {
return nil, err
}
if resp.JSONDefault != nil {
return nil, t.convertErrors(resp.JSONDefault.Errors)
}
res := make([]domain.Tribe, 0, len(tribes))
for _, tr := range tribes {
res := make([]domain.Tribe, 0, len(resp.JSON200.Data))
for _, tr := range resp.JSON200.Data {
res = append(res, t.convertTribeToDomain(tr))
}
@ -167,19 +180,21 @@ func (t *TWHelpHTTP) ListVillagesByCoords(
ctx context.Context,
versionCode, serverKey string,
coords []string,
offset, limit int32,
limit int,
) ([]domain.Village, error) {
villages, err := t.client.ListVillages(ctx, versionCode, serverKey, twhelp.ListVillagesQueryParams{
Limit: limit,
Offset: offset,
Coords: coords,
resp, err := t.client.ListVillagesWithResponse(ctx, versionCode, serverKey, &twhelp.ListVillagesParams{
Limit: &limit,
Coords: &coords,
})
if err != nil {
return nil, err
}
if resp.JSONDefault != nil {
return nil, t.convertErrors(resp.JSONDefault.Errors)
}
res := make([]domain.Village, 0, len(villages))
for _, v := range villages {
res := make([]domain.Village, 0, len(resp.JSON200.Data))
for _, v := range resp.JSON200.Data {
res = append(res, t.convertVillageToDomain(v))
}
@ -190,22 +205,26 @@ func (t *TWHelpHTTP) ListEnnoblementsSince(
ctx context.Context,
versionCode, serverKey string,
since time.Time,
offset, limit int32,
limit int,
) ([]domain.Ennoblement, error) {
ennoblements, err := t.client.ListEnnoblements(ctx, versionCode, serverKey, twhelp.ListEnnoblementsQueryParams{
Limit: limit,
Offset: offset,
Since: since,
Sort: []twhelp.EnnoblementSort{
twhelp.EnnoblementSortCreatedAtASC,
},
sort := []string{
string(twhelp.ListEnnoblementsParamsSortCreatedAtASC),
}
resp, err := t.client.ListEnnoblementsWithResponse(ctx, versionCode, serverKey, &twhelp.ListEnnoblementsParams{
Limit: &limit,
Sort: &sort,
Since: &since,
})
if err != nil {
return nil, err
}
if resp.JSONDefault != nil {
return nil, t.convertErrors(resp.JSONDefault.Errors)
}
res := make([]domain.Ennoblement, 0, len(ennoblements))
for _, e := range ennoblements {
res := make([]domain.Ennoblement, 0, len(resp.JSON200.Data))
for _, e := range resp.JSON200.Data {
res = append(res, t.convertEnnoblementToDomain(e))
}
@ -217,45 +236,71 @@ func (t *TWHelpHTTP) convertVersionToDomain(v twhelp.Version) domain.TWVersion {
}
func (t *TWHelpHTTP) convertServerToDomain(s twhelp.Server) domain.TWServer {
return domain.TWServer(s)
return domain.TWServer{
Key: s.Key,
URL: s.Url,
Open: s.Open,
}
}
func (t *TWHelpHTTP) convertTribeToDomain(tr twhelp.Tribe) domain.Tribe {
return domain.Tribe(tr)
var deletedAt time.Time
if tr.DeletedAt != nil {
deletedAt = *tr.DeletedAt
}
return domain.Tribe{
ID: tr.Id,
Tag: tr.Tag,
Name: tr.Name,
ProfileURL: tr.ProfileUrl,
DeletedAt: deletedAt,
}
}
func (t *TWHelpHTTP) convertTribeMetaToDomain(tr twhelp.TribeMeta) domain.TribeMeta {
return domain.TribeMeta(tr)
return domain.TribeMeta{
ID: tr.Id,
Name: tr.Name,
Tag: tr.Tag,
ProfileURL: tr.ProfileUrl,
}
}
func (t *TWHelpHTTP) convertNullTribeMetaToDomain(tr twhelp.NullTribeMeta) domain.NullTribeMeta {
return domain.NullTribeMeta{
Tribe: t.convertTribeMetaToDomain(tr.Tribe),
Valid: tr.Valid,
func (t *TWHelpHTTP) convertNullTribeMetaToDomain(tr *twhelp.NullTribeMeta) domain.NullTribeMeta {
res := domain.NullTribeMeta{
Valid: tr != nil,
}
if tr != nil {
res.Tribe = t.convertTribeMetaToDomain(*tr)
}
return res
}
func (t *TWHelpHTTP) convertPlayerMetaToDomain(p twhelp.PlayerMeta) domain.PlayerMeta {
return domain.PlayerMeta{
ID: p.ID,
ID: p.Id,
Name: p.Name,
ProfileURL: p.ProfileURL,
ProfileURL: p.ProfileUrl,
Tribe: t.convertNullTribeMetaToDomain(p.Tribe),
}
}
func (t *TWHelpHTTP) convertNullPlayerMetaToDomain(p twhelp.NullPlayerMeta) domain.NullPlayerMeta {
return domain.NullPlayerMeta{
Player: t.convertPlayerMetaToDomain(p.Player),
Valid: p.Valid,
func (t *TWHelpHTTP) convertNullPlayerMetaToDomain(p *twhelp.NullPlayerMeta) domain.NullPlayerMeta {
res := domain.NullPlayerMeta{
Valid: p != nil,
}
if p != nil {
res.Player = t.convertPlayerMetaToDomain(*p)
}
return res
}
func (t *TWHelpHTTP) convertVillageToDomain(v twhelp.Village) domain.Village {
return domain.Village{
ID: v.ID,
ID: v.Id,
FullName: v.FullName,
ProfileURL: v.ProfileURL,
ProfileURL: v.ProfileUrl,
Points: v.Points,
X: v.X,
Y: v.Y,
@ -265,18 +310,43 @@ func (t *TWHelpHTTP) convertVillageToDomain(v twhelp.Village) domain.Village {
func (t *TWHelpHTTP) convertVillageMetaToDomain(v twhelp.VillageMeta) domain.VillageMeta {
return domain.VillageMeta{
ID: v.ID,
ID: v.Id,
FullName: v.FullName,
ProfileURL: v.ProfileURL,
ProfileURL: v.ProfileUrl,
Player: t.convertNullPlayerMetaToDomain(v.Player),
}
}
func (t *TWHelpHTTP) convertEnnoblementToDomain(e twhelp.Ennoblement) domain.Ennoblement {
return domain.Ennoblement{
ID: e.ID,
ID: e.Id,
Village: t.convertVillageMetaToDomain(e.Village),
NewOwner: t.convertNullPlayerMetaToDomain(e.NewOwner),
NewOwner: t.convertPlayerMetaToDomain(e.NewOwner),
CreatedAt: e.CreatedAt,
}
}
func (t *TWHelpHTTP) convertErrors(errs []twhelp.Error) error {
if len(errs) == 0 {
return nil
}
sep := "\n"
n := len(sep) * (len(errs) - 1)
for _, err := range errs {
n += len(err.Message)
}
var b strings.Builder
b.Grow(n)
for i, err := range errs {
if i > 0 {
b.WriteString(sep)
}
b.WriteString(err.Message)
}
return errors.New(b.String())
}

View File

@ -26,8 +26,8 @@ type translateVillageCoordsParamsRedis struct {
VersionCode string
ServerKey string
Coords []string
PerPage int32
MaxPage int32
PerPage int
MaxPage int
SHA256 string
}

View File

@ -34,12 +34,8 @@ type ChoiceService interface {
}
type VillageService interface {
TranslateCoords(
ctx context.Context,
params domain.TranslateVillageCoordsParams,
page int32,
) (domain.TranslateVillageCoordsResult, error)
TranslateCoordsFromHash(ctx context.Context, paramsSHA256Hash string, page int32) (domain.TranslateVillageCoordsResult, error)
TranslateCoords(ctx context.Context, params domain.TranslateVillageCoordsParams, page int) (domain.TranslateVillageCoordsResult, error)
TranslateCoordsFromHash(ctx context.Context, paramsSHA256Hash string, page int) (domain.TranslateVillageCoordsResult, error)
}
type Bot struct {

View File

@ -358,20 +358,20 @@ const (
coordsTranslationButtonIDSeparator = "-"
)
func (c *coordsCommand) buildButtonID(page int32, hash string) string {
func (c *coordsCommand) buildButtonID(page int, hash string) string {
return fmt.Sprintf("%s%s%d%s%s", coordsTranslationButtonIDPrefix, coordsTranslationButtonIDSeparator, page, coordsTranslationButtonIDSeparator, hash)
}
func (c *coordsCommand) parseButtonID(id string) (int32, string, error) {
func (c *coordsCommand) parseButtonID(id string) (int, string, error) {
chunks := strings.Split(id, coordsTranslationButtonIDSeparator)
if len(chunks) != 3 || chunks[0] != coordsTranslationButtonIDPrefix {
return 0, "", fmt.Errorf("couldn't parse '%s': incorrect format", id)
}
page, err := strconv.ParseInt(chunks[1], 10, 32)
page, err := strconv.Atoi(id)
if err != nil {
return 0, "", fmt.Errorf("couldn't parse '%s': %w", id, err)
}
return int32(page), chunks[2], nil
return page, chunks[2], nil
}

View File

@ -38,18 +38,33 @@ func buildLangMessageID(languageTag string) string {
return "lang." + languageTag
}
func buildPlayerMarkdown(p domain.NullPlayerMeta) string {
if !p.Valid {
return "-"
}
func buildPlayerMarkdown(p any) (string, error) {
switch player := p.(type) {
case domain.PlayerMeta:
tag := player.Tribe.Tribe.Tag
if tag == "" {
tag = "-"
}
tag := p.Player.Tribe.Tribe.Tag
if tag == "" {
tag = "-"
}
return buildLink(player.Name, player.ProfileURL) +
" [" +
buildLink(tag, player.Tribe.Tribe.ProfileURL) +
"]", nil
case domain.NullPlayerMeta:
if !player.Valid {
return "-", nil
}
return buildLink(p.Player.Name, p.Player.ProfileURL) +
" [" +
buildLink(tag, p.Player.Tribe.Tribe.ProfileURL) +
"]"
tag := player.Player.Tribe.Tribe.Tag
if tag == "" {
tag = "-"
}
return buildLink(player.Player.Name, player.Player.ProfileURL) +
" [" +
buildLink(tag, player.Player.Tribe.Tribe.ProfileURL) +
"]", nil
default:
return "", fmt.Errorf("can't build player markdown for type: %T", p)
}
}

View File

@ -3,9 +3,9 @@ package domain
import "time"
type Ennoblement struct {
ID int64
ID int
Village VillageMeta
NewOwner NullPlayerMeta
NewOwner PlayerMeta
CreatedAt time.Time
}
@ -14,5 +14,5 @@ func (e Ennoblement) IsBarbarian() bool {
}
func (e Ennoblement) IsSelfConquer() bool {
return e.NewOwner.Player.ID == e.Village.Player.Player.ID
return e.NewOwner.ID == e.Village.Player.Player.ID
}

View File

@ -35,17 +35,14 @@ func TestNewEnnoblementNotifications(t *testing.T) {
},
ennoblements: []domain.Ennoblement{
{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -63,31 +60,25 @@ func TestNewEnnoblementNotifications(t *testing.T) {
},
},
{ // Barbarians == false
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
},
{ // Internals == false
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -105,17 +96,14 @@ func TestNewEnnoblementNotifications(t *testing.T) {
},
},
{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 153,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 153,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{

View File

@ -11,20 +11,14 @@ func TestEnnoblement_IsBarbarian(t *testing.T) {
t.Parallel()
assert.True(t, domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 123,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 123,
},
}.IsBarbarian())
assert.False(t, domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 123,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 123,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -41,11 +35,8 @@ func TestEnnoblement_IsSelfConquer(t *testing.T) {
t.Parallel()
assert.True(t, domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 123,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 123,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -58,20 +49,14 @@ func TestEnnoblement_IsSelfConquer(t *testing.T) {
}.IsSelfConquer())
assert.False(t, domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 123,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 123,
},
}.IsSelfConquer())
assert.False(t, domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 123,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 123,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{

View File

@ -48,7 +48,7 @@ func (g GroupWithMonitors) IsGain(e Ennoblement) bool {
var n bool
for _, m := range g.Monitors {
if m.TribeID == e.NewOwner.Player.Tribe.Tribe.ID {
if m.TribeID == e.NewOwner.Tribe.Tribe.ID {
n = true
break
}
@ -61,7 +61,7 @@ func (g GroupWithMonitors) IsInternal(e Ennoblement) bool {
var n, o bool
for _, m := range g.Monitors {
if m.TribeID == e.NewOwner.Player.Tribe.Tribe.ID {
if m.TribeID == e.NewOwner.Tribe.Tribe.ID {
n = true
}

View File

@ -25,17 +25,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -63,17 +60,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -105,17 +99,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
}))
@ -132,17 +123,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
}))
@ -160,17 +148,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -201,17 +186,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeGain(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -246,17 +228,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeLoss(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeLoss(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -284,17 +263,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeLoss(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeLoss(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -325,17 +301,14 @@ func TestGroupWithMonitors_CanSendEnnoblementNotificationTypeLoss(t *testing.T)
},
},
}.CanSendEnnoblementNotificationTypeLoss(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -367,17 +340,14 @@ func TestGroupWithMonitors_IsGain(t *testing.T) {
},
},
}.IsGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
}))
@ -391,17 +361,14 @@ func TestGroupWithMonitors_IsGain(t *testing.T) {
},
},
}.IsGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -429,16 +396,13 @@ func TestGroupWithMonitors_IsGain(t *testing.T) {
},
},
}.IsGain(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
}))
@ -493,17 +457,14 @@ func TestGroupWithMonitors_IsLoss(t *testing.T) {
},
},
}.IsLoss(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -572,17 +533,14 @@ func TestGroupWithMonitors_IsInternal(t *testing.T) {
},
},
}.IsInternal(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -610,17 +568,14 @@ func TestGroupWithMonitors_IsInternal(t *testing.T) {
},
},
}.IsInternal(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
Village: domain.VillageMeta{
Player: domain.NullPlayerMeta{
@ -648,17 +603,14 @@ func TestGroupWithMonitors_IsInternal(t *testing.T) {
},
},
}.IsInternal(domain.Ennoblement{
NewOwner: domain.NullPlayerMeta{
Player: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
NewOwner: domain.PlayerMeta{
ID: 125,
Tribe: domain.NullTribeMeta{
Tribe: domain.TribeMeta{
ID: 150,
},
Valid: true,
},
Valid: true,
},
}))

View File

@ -7,7 +7,7 @@ import (
type Monitor struct {
ID string
TribeID int64
TribeID int
GroupID string
CreatedAt time.Time
}
@ -18,7 +18,7 @@ type MonitorWithTribe struct {
}
type MonitorAlreadyExistsError struct {
TribeID int64
TribeID int
GroupID string
}

View File

@ -1,7 +1,7 @@
package domain
type PlayerMeta struct {
ID int64
ID int
Name string
ProfileURL string
Tribe NullTribeMeta

View File

@ -6,7 +6,7 @@ import (
)
type Tribe struct {
ID int64
ID int
Tag string
Name string
ProfileURL string
@ -14,7 +14,7 @@ type Tribe struct {
}
type TribeMeta struct {
ID int64
ID int
Name string
Tag string
ProfileURL string
@ -52,7 +52,7 @@ func (e TribeTagNotFoundError) Params() map[string]any {
type TribeIDNotFoundError struct {
VersionCode string
ServerKey string
ID int64
ID int
}
var _ TranslatableError = TribeIDNotFoundError{}

View File

@ -10,12 +10,12 @@ import (
)
type Village struct {
ID int64
ID int
FullName string
ProfileURL string
Points int64
X int64
Y int64
Points int
X int
Y int
Player NullPlayerMeta
}
@ -24,7 +24,7 @@ func (v Village) Coords() string {
}
type VillageMeta struct {
ID int64
ID int
FullName string
ProfileURL string
Player NullPlayerMeta
@ -76,8 +76,8 @@ type TranslateVillageCoordsParams struct {
versionCode string
serverKey string
coords []string
perPage int32
maxPage int32
perPage int
maxPage int
sha256 string
}
@ -88,7 +88,7 @@ const (
translateVillageCoordsMinPerPage = 1
)
func NewTranslateVillageCoordsParams(versionCode, serverKey, coordsStr string, perPage int32) (TranslateVillageCoordsParams, error) {
func NewTranslateVillageCoordsParams(versionCode, serverKey, coordsStr string, perPage int) (TranslateVillageCoordsParams, error) {
if versionCode == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "VersionCode"}
}
@ -125,7 +125,7 @@ func NewTranslateVillageCoordsParams(versionCode, serverKey, coordsStr string, p
serverKey: serverKey,
coords: coords,
perPage: perPage,
maxPage: int32(math.Ceil(float64(len(coords)) / float64(perPage))),
maxPage: int(math.Ceil(float64(len(coords)) / float64(perPage))),
sha256: hex.EncodeToString(sum256[:]),
}, nil
}
@ -138,8 +138,8 @@ func UnmarshalTranslateVillageCoordsParamsFromDatabase(
versionCode string,
serverKey string,
coords []string,
perPage int32,
maxPage int32,
perPage int,
maxPage int,
sha256Hash string,
) (TranslateVillageCoordsParams, error) {
if versionCode == "" {
@ -190,11 +190,11 @@ func (t TranslateVillageCoordsParams) Coords() []string {
return t.coords
}
func (t TranslateVillageCoordsParams) PerPage() int32 {
func (t TranslateVillageCoordsParams) PerPage() int {
return t.perPage
}
func (t TranslateVillageCoordsParams) MaxPage() int32 {
func (t TranslateVillageCoordsParams) MaxPage() int {
return t.maxPage
}
@ -202,13 +202,13 @@ func (t TranslateVillageCoordsParams) SHA256() string {
return t.sha256
}
func (t TranslateVillageCoordsParams) IsPageInRange(page int32) error {
func (t TranslateVillageCoordsParams) IsPageInRange(page int) error {
if page < 1 {
return GreaterEqualThanError{Field: "page", Threshold: 1}
}
if page > t.maxPage {
return LessEqualThanError{Field: "page", Threshold: int(t.maxPage)}
return LessEqualThanError{Field: "page", Threshold: t.maxPage}
}
return nil
@ -219,8 +219,8 @@ type TranslateVillageCoordsResult struct {
NotFound []string
HasNext bool
HasPrev bool
Page int32
MaxPage int32
Page int
MaxPage int
ParamsSHA256 string
}

View File

@ -22,8 +22,8 @@ func TestNewTranslateVillageCoordsParams(t *testing.T) {
serverKey string
coordsStr string
coords []string
perPage int32
maxPage int32
perPage int
maxPage int
err error
}{
{

View File

@ -15,7 +15,7 @@ import (
type GroupRepository interface {
Create(ctx context.Context, params domain.CreateGroupParams) (domain.GroupWithMonitors, error)
Update(ctx context.Context, id string, params domain.UpdateGroupParams) (domain.GroupWithMonitors, error)
AddMonitor(ctx context.Context, id string, tribeID int64) (domain.GroupWithMonitors, error)
AddMonitor(ctx context.Context, id string, tribeID int) (domain.GroupWithMonitors, error)
DeleteMonitors(ctx context.Context, id string, monitorID ...string) (domain.GroupWithMonitors, error)
List(ctx context.Context, params domain.ListGroupsParams) ([]domain.GroupWithMonitors, error)
Get(ctx context.Context, id string) (domain.GroupWithMonitors, error)
@ -110,7 +110,7 @@ func (g *Group) RemoveTribe(ctx context.Context, id, serverID, tribeTag string)
return domain.GroupWithMonitors{}, err
}
tribes, err := g.twhelpSvc.ListTribesByTag(ctx, groupBeforeUpdate.VersionCode, groupBeforeUpdate.ServerKey, []string{tribeTag}, 0, listTribesLimit)
tribes, err := g.twhelpSvc.ListTribesByTag(ctx, groupBeforeUpdate.VersionCode, groupBeforeUpdate.ServerKey, []string{tribeTag}, listTribesLimit)
if err != nil {
return domain.GroupWithMonitors{}, fmt.Errorf("TWHelpClient.ListTribes: %w", err)
}
@ -372,7 +372,7 @@ func (g *Group) listEnnoblements(ctx context.Context, groups []domain.GroupWithM
go func(group domain.GroupWithMonitors, since time.Time) {
defer wg.Done()
ennoblements, err := g.twhelpSvc.ListEnnoblementsSince(ctx, group.VersionCode, group.ServerKey, since, 0, listEnnoblementsLimit)
ennoblements, err := g.twhelpSvc.ListEnnoblementsSince(ctx, group.VersionCode, group.ServerKey, since, listEnnoblementsLimit)
if err != nil {
g.logger.Warn(
"couldn't list ennoblements",
@ -461,7 +461,7 @@ func (g *Group) deleteAllWithClosedTWServers(ctx context.Context) error {
}
for _, v := range versions {
servers, err := g.twhelpSvc.ListClosedServers(ctx, v.Code, 0, listServersLimit)
servers, err := g.twhelpSvc.ListClosedServers(ctx, v.Code, listServersLimit)
if err != nil {
g.logger.Warn("couldn't list closed servers", zap.Error(err), zap.String("versionCode", v.Code))
continue

View File

@ -111,7 +111,7 @@ func TestGroup_AddTribe(t *testing.T) {
},
}
repo.GetReturns(group, nil)
repo.AddMonitorCalls(func(ctx context.Context, id string, tribeID int64) (domain.GroupWithMonitors, error) {
repo.AddMonitorCalls(func(ctx context.Context, id string, tribeID int) (domain.GroupWithMonitors, error) {
group.Monitors = append(group.Monitors, domain.Monitor{
ID: uuid.NewString(),
GroupID: id,
@ -907,7 +907,7 @@ func TestGroup_GetWithTribes(t *testing.T) {
repo.GetReturns(group, nil)
twhelpSvc := &mock.FakeTWHelpService{}
twhelpSvc.GetTribeByIDCalls(func(ctx context.Context, versionCode string, serverKey string, id int64) (domain.Tribe, error) {
twhelpSvc.GetTribeByIDCalls(func(ctx context.Context, versionCode string, serverKey string, id int) (domain.Tribe, error) {
return domain.Tribe{
ID: id,
Tag: fmt.Sprintf("*%d*", id),
@ -1007,7 +1007,7 @@ func TestGroup_GetWithTribes(t *testing.T) {
twhelpSvc := &mock.FakeTWHelpService{}
expectedErr := errors.New("err")
twhelpSvc.GetTribeByIDCalls(func(ctx context.Context, versionCode string, serverKey string, id int64) (domain.Tribe, error) {
twhelpSvc.GetTribeByIDCalls(func(ctx context.Context, versionCode string, serverKey string, id int) (domain.Tribe, error) {
if id == 115 {
return domain.Tribe{}, expectedErr
}
@ -1367,132 +1367,93 @@ func TestGroup_Execute(t *testing.T) {
ennoblements := map[string][]domain.Ennoblement{
"pl:pl181": {
{
ID: 1,
Village: villages["pl:pl181"][0],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][0],
Valid: true,
},
ID: 1,
Village: villages["pl:pl181"][0],
NewOwner: players["pl:pl181"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 2, // self conquer, should be skipped
Village: villages["pl:pl181"][1],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][0],
Valid: true,
},
ID: 2, // self conquer, should be skipped
Village: villages["pl:pl181"][1],
NewOwner: players["pl:pl181"][0],
CreatedAt: time.Now().Add(-4 * time.Minute),
},
{
ID: 3, // internal, should be skipped (internals disabled)
Village: villages["pl:pl181"][2],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][0],
Valid: true,
},
ID: 3, // internal, should be skipped (internals disabled)
Village: villages["pl:pl181"][2],
NewOwner: players["pl:pl181"][0],
CreatedAt: time.Now().Add(-3 * time.Minute),
},
{
ID: 4, // barbarian, shouldn't be skipped (barbarians enabled)
Village: villages["pl:pl181"][3],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][0],
Valid: true,
},
ID: 4, // barbarian, shouldn't be skipped (barbarians enabled)
Village: villages["pl:pl181"][3],
NewOwner: players["pl:pl181"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 5, // disabled notifications about gains, should be skipped
Village: villages["pl:pl181"][4],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][1],
Valid: true,
},
ID: 5, // disabled notifications about gains, should be skipped
Village: villages["pl:pl181"][4],
NewOwner: players["pl:pl181"][1],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 6, // disabled notifications about losses, should be skipped
Village: villages["pl:pl181"][4],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl181"][3],
Valid: true,
},
ID: 6, // disabled notifications about losses, should be skipped
Village: villages["pl:pl181"][4],
NewOwner: players["pl:pl181"][3],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
},
"en:en130": {
{
ID: 100, // no monitor for these tribes, should be skipped
Village: villages["en:en130"][0],
NewOwner: domain.NullPlayerMeta{
Player: players["en:en130"][0],
Valid: true,
},
ID: 100, // no monitor for these tribes, should be skipped
Village: villages["en:en130"][0],
NewOwner: players["en:en130"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 101, // no monitor for these tribes, should be skipped
Village: villages["en:en130"][1],
NewOwner: domain.NullPlayerMeta{
Player: players["en:en130"][2],
Valid: true,
},
ID: 101, // no monitor for these tribes, should be skipped
Village: villages["en:en130"][1],
NewOwner: players["en:en130"][2],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 102,
Village: villages["en:en130"][2],
NewOwner: domain.NullPlayerMeta{
Player: players["en:en130"][1],
Valid: true,
},
ID: 102,
Village: villages["en:en130"][2],
NewOwner: players["en:en130"][1],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
},
"pl:pl180": {
{
ID: 200, // api error, should be skipped
Village: villages["pl:pl180"][0],
NewOwner: domain.NullPlayerMeta{
Player: players["pl:pl180"][0],
Valid: true,
},
ID: 200, // api error, should be skipped
Village: villages["pl:pl180"][0],
NewOwner: players["pl:pl180"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
},
"de:de200": {
{
ID: 300, // barbarian, should be skipped (barbarians disabled)
Village: villages["de:de200"][0],
NewOwner: domain.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
ID: 300, // barbarian, should be skipped (barbarians disabled)
Village: villages["de:de200"][0],
NewOwner: players["de:de200"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 301, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][1],
NewOwner: domain.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
ID: 301, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][1],
NewOwner: players["de:de200"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 302, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][2],
NewOwner: domain.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
ID: 302, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][2],
NewOwner: players["de:de200"][0],
CreatedAt: time.Now().Add(-5 * time.Minute),
},
},
}
twhelpSvc.ListEnnoblementsSinceCalls(
func(ctx context.Context, version string, server string, _ time.Time, _ int32, _ int32) ([]domain.Ennoblement, error) {
func(ctx context.Context, version string, server string, _ time.Time, _ int) ([]domain.Ennoblement, error) {
if version == "pl" && server == "pl180" {
return nil, errors.New("random error")
}
@ -1672,7 +1633,7 @@ func TestGroup_CleanUp(t *testing.T) {
},
},
}
twhelpSvc.ListClosedServersCalls(func(ctx context.Context, version string, _, _ int32) ([]domain.TWServer, error) {
twhelpSvc.ListClosedServersCalls(func(ctx context.Context, version string, _ int) ([]domain.TWServer, error) {
return serversByVersion[version], nil
})

View File

@ -12,13 +12,13 @@ import (
//counterfeiter:generate -o internal/mock/twhelp_service.gen.go . TWHelpService
type TWHelpService interface {
ListVersions(ctx context.Context) ([]domain.TWVersion, error)
ListOpenServers(ctx context.Context, version string, offset, limit int32) ([]domain.TWServer, error)
ListClosedServers(ctx context.Context, version string, offset, limit int32) ([]domain.TWServer, error)
ListOpenServers(ctx context.Context, version string, limit int) ([]domain.TWServer, error)
ListClosedServers(ctx context.Context, version string, limit int) ([]domain.TWServer, error)
GetOpenServer(ctx context.Context, versionCode, serverKey string) (domain.TWServer, error)
GetServer(ctx context.Context, versionCode, serverKey string) (domain.TWServer, error)
GetTribeByID(ctx context.Context, versionCode, serverKey string, id int64) (domain.Tribe, error)
GetTribeByID(ctx context.Context, versionCode, serverKey string, id int) (domain.Tribe, error)
GetExistingTribeByTag(ctx context.Context, versionCode, serverKey, tribeTag string) (domain.Tribe, error)
ListTribesByTag(ctx context.Context, versionCode, serverKey string, tribeTags []string, offset, limit int32) ([]domain.Tribe, error)
ListVillagesByCoords(ctx context.Context, versionCode, serverKey string, coords []string, offset, limit int32) ([]domain.Village, error)
ListEnnoblementsSince(ctx context.Context, versionCode, serverKey string, since time.Time, offset, limit int32) ([]domain.Ennoblement, error)
ListTribesByTag(ctx context.Context, versionCode, serverKey string, tribeTags []string, limit int) ([]domain.Tribe, error)
ListVillagesByCoords(ctx context.Context, versionCode, serverKey string, coords []string, limit int) ([]domain.Village, error)
ListEnnoblementsSince(ctx context.Context, versionCode, serverKey string, since time.Time, limit int) ([]domain.Ennoblement, error)
}

View File

@ -24,7 +24,7 @@ func NewVillage(repo VillageRepository, twhelpSvc TWHelpService) *Village {
func (v *Village) TranslateCoords(
ctx context.Context,
params domain.TranslateVillageCoordsParams,
page int32,
page int,
) (domain.TranslateVillageCoordsResult, error) {
if err := params.IsPageInRange(page); err != nil {
return domain.TranslateVillageCoordsResult{}, err
@ -40,13 +40,13 @@ func (v *Village) TranslateCoords(
low := params.PerPage() * (page - 1)
high := params.PerPage() * page
if coordsLen := int32(len(params.Coords())); coordsLen < high {
if coordsLen := len(params.Coords()); coordsLen < high {
high = coordsLen
}
coords := params.Coords()[low:high]
villages, err := v.twhelpSvc.ListVillagesByCoords(ctx, params.VersionCode(), params.ServerKey(), coords, 0, high-low)
villages, err := v.twhelpSvc.ListVillagesByCoords(ctx, params.VersionCode(), params.ServerKey(), coords, high-low)
if err != nil {
return domain.TranslateVillageCoordsResult{}, err
}
@ -78,7 +78,7 @@ func (v *Village) TranslateCoords(
}, nil
}
func (v *Village) TranslateCoordsFromHash(ctx context.Context, paramsSHA256Hash string, page int32) (domain.TranslateVillageCoordsResult, error) {
func (v *Village) TranslateCoordsFromHash(ctx context.Context, paramsSHA256Hash string, page int) (domain.TranslateVillageCoordsResult, error) {
params, err := v.repo.GetTranslateCoordsParams(ctx, paramsSHA256Hash)
if err != nil {
return domain.TranslateVillageCoordsResult{}, err

View File

@ -57,7 +57,7 @@ func TestVillage_TranslateCoords(t *testing.T) {
require.NoError(t, err)
tests := []struct {
page int32
page int
hasNext bool
hasPrev bool
villages []domain.Village
@ -105,8 +105,7 @@ func TestVillage_TranslateCoords(t *testing.T) {
versionCode string,
serverKey string,
coords []string,
offset int32,
perPage int32,
perPage int,
) ([]domain.Village, error) {
if versionCode != params.VersionCode() || serverKey != params.ServerKey() {
return nil, nil

1
internal/twhelp/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.gen.go

View File

@ -1,291 +0,0 @@
package twhelp
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"time"
"golang.org/x/time/rate"
)
const (
defaultUserAgent = "TWHelpDCBot/development"
defaultTimeout = 10 * time.Second
endpointListVersions = "/api/v1/versions"
endpointListServers = "/api/v1/versions/%s/servers"
endpointGetServer = "/api/v1/versions/%s/servers/%s"
endpointListTribes = "/api/v1/versions/%s/servers/%s/tribes"
endpointGetTribeByID = "/api/v1/versions/%s/servers/%s/tribes/%d"
endpointListEnnoblements = "/api/v1/versions/%s/servers/%s/ennoblements"
endpointListVillages = "/api/v1/versions/%s/servers/%s/villages"
)
type Client struct {
userAgent string
client *http.Client
baseURL *url.URL
rateLimiter *rate.Limiter
}
type ClientOption func(c *Client)
func WithHTTPClient(hc *http.Client) ClientOption {
return func(c *Client) {
c.client = hc
}
}
func WithUserAgent(ua string) ClientOption {
return func(c *Client) {
c.userAgent = ua
}
}
func WithRateLimiter(rl *rate.Limiter) ClientOption {
return func(c *Client) {
c.rateLimiter = rl
}
}
func NewClient(baseURL *url.URL, opts ...ClientOption) *Client {
c := &Client{
baseURL: baseURL,
userAgent: defaultUserAgent,
client: &http.Client{
Timeout: defaultTimeout,
},
}
for _, opt := range opts {
opt(c)
}
return c
}
func (c *Client) ListVersions(ctx context.Context) ([]Version, error) {
var resp listVersionsResp
if err := c.getJSON(ctx, endpointListVersions, &resp); err != nil {
return nil, err
}
return resp.Data, nil
}
type ListServersQueryParams struct {
Limit int32
Offset int32
Open NullBool
}
func (c *Client) ListServers(
ctx context.Context,
version string,
params ListServersQueryParams,
) ([]Server, error) {
q := url.Values{}
if params.Limit > 0 {
q.Set("limit", strconv.FormatInt(int64(params.Limit), 10))
}
if params.Offset > 0 {
q.Set("offset", strconv.FormatInt(int64(params.Offset), 10))
}
if params.Open.Valid {
q.Set("open", strconv.FormatBool(params.Open.Bool))
}
var resp listServersResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointListServers, version)+"?"+q.Encode(), &resp); err != nil {
return nil, err
}
return resp.Data, nil
}
func (c *Client) GetServer(ctx context.Context, version, server string) (Server, error) {
var resp getServerResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetServer, version, server), &resp); err != nil {
return Server{}, err
}
return resp.Data, nil
}
type ListTribesQueryParams struct {
Limit int32
Offset int32
Tags []string
Deleted NullBool
}
func (c *Client) ListTribes(
ctx context.Context,
version, server string,
params ListTribesQueryParams,
) ([]Tribe, error) {
q := url.Values{}
if params.Limit > 0 {
q.Set("limit", strconv.FormatInt(int64(params.Limit), 10))
}
if params.Offset > 0 {
q.Set("offset", strconv.FormatInt(int64(params.Offset), 10))
}
if params.Deleted.Valid {
q.Set("deleted", strconv.FormatBool(params.Deleted.Bool))
}
if params.Tags != nil {
for _, t := range params.Tags {
q.Add("tag", t)
}
}
var resp listTribesResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointListTribes, version, server)+"?"+q.Encode(), &resp); err != nil {
return nil, err
}
return resp.Data, nil
}
func (c *Client) GetTribeByID(ctx context.Context, version, server string, id int64) (Tribe, error) {
var resp getTribeResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetTribeByID, version, server, id), &resp); err != nil {
return Tribe{}, err
}
return resp.Data, nil
}
type EnnoblementSort string
const (
EnnoblementSortCreatedAtASC EnnoblementSort = "createdAt:ASC"
)
func (s EnnoblementSort) String() string {
return string(s)
}
type ListEnnoblementsQueryParams struct {
Limit int32
Offset int32
Since time.Time
Sort []EnnoblementSort
}
func (c *Client) ListEnnoblements(
ctx context.Context,
version, server string,
params ListEnnoblementsQueryParams,
) ([]Ennoblement, error) {
q := url.Values{}
if params.Limit > 0 {
q.Set("limit", strconv.FormatInt(int64(params.Limit), 10))
}
if params.Offset > 0 {
q.Set("offset", strconv.FormatInt(int64(params.Offset), 10))
}
if !params.Since.IsZero() {
q.Set("since", params.Since.Format(time.RFC3339))
}
for _, s := range params.Sort {
q.Add("sort", s.String())
}
var resp listEnnoblementsResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointListEnnoblements, version, server)+"?"+q.Encode(), &resp); err != nil {
return nil, err
}
return resp.Data, nil
}
type ListVillagesQueryParams struct {
Limit int32
Offset int32
Coords []string
}
func (c *Client) ListVillages(
ctx context.Context,
version, server string,
params ListVillagesQueryParams,
) ([]Village, error) {
q := url.Values{}
if params.Limit > 0 {
q.Set("limit", strconv.FormatInt(int64(params.Limit), 10))
}
if params.Offset > 0 {
q.Set("offset", strconv.FormatInt(int64(params.Offset), 10))
}
for _, co := range params.Coords {
q.Add("coords", co)
}
var resp listVillagesResp
if err := c.getJSON(ctx, fmt.Sprintf(endpointListVillages, version, server)+"?"+q.Encode(), &resp); err != nil {
return nil, err
}
return resp.Data, nil
}
func (c *Client) getJSON(ctx context.Context, urlStr string, v any) error {
u, err := c.baseURL.Parse(urlStr)
if err != nil {
return fmt.Errorf("c.baseURL.Parse: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil {
return fmt.Errorf("http.NewRequestWithContext: %w", err)
}
// headers
req.Header.Set("User-Agent", c.userAgent)
// rate limiter
if c.rateLimiter != nil {
if err = c.rateLimiter.Wait(ctx); err != nil {
return err
}
}
resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("client.Do: %w", err)
}
defer func() {
_ = resp.Body.Close()
}()
if resp.StatusCode != http.StatusOK {
var errResp errorResp
if err = json.NewDecoder(resp.Body).Decode(&errResp); err != nil {
_, _ = io.Copy(io.Discard, resp.Body)
return fmt.Errorf("got non-ok HTTP status: %d", resp.StatusCode)
}
return errResp.Error
}
if err = json.NewDecoder(resp.Body).Decode(v); err != nil {
return fmt.Errorf("couldn't decode resp body: %w", err)
}
return nil
}

View File

@ -0,0 +1,5 @@
package: twhelp
generate:
models: true
client: true
output: twhelp.gen.go

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,123 @@
// ClientWithResponses builds on ClientInterface to offer response payloads
type ClientWithResponses struct {
ClientInterface
}
// NewClientWithResponses creates a new ClientWithResponses, which wraps
// Client with return type handling
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
client, err := NewClient(server, opts...)
if err != nil {
return nil, err
}
return &ClientWithResponses{client}, nil
}
{{$clientTypeName := opts.OutputOptions.ClientTypeName -}}
// WithBaseURL overrides the baseURL.
func WithBaseURL(baseURL string) ClientOption {
return func(c *{{ $clientTypeName }}) error {
newBaseURL, err := url.Parse(baseURL)
if err != nil {
return err
}
c.Server = newBaseURL.String()
return nil
}
}
// ClientWithResponsesInterface is the interface specification for the client with responses above.
type ClientWithResponsesInterface interface {
{{range . -}}
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$opid := .OperationId -}}
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with any body{{end}}
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}Container, error)
{{range .Bodies}}
{{if .IsSupportedByClient -}}
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}Container, error)
{{end -}}
{{end}}{{/* range .Bodies */}}
{{end}}{{/* range . $opid := .OperationId */}}
}
{{range .}}{{$opid := .OperationId}}{{$op := .}}
type {{genResponseTypeName $opid | ucFirst}}Container struct {
Body []byte
HTTPResponse *http.Response
{{- range getResponseTypeDefinitions .}}
{{.TypeName}} *{{.Schema.TypeDecl}}
{{- end}}
}
// Status returns HTTPResponse.Status
func (r {{genResponseTypeName $opid | ucFirst}}Container) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r {{genResponseTypeName $opid | ucFirst}}Container) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
{{end}}
{{range .}}
{{$opid := .OperationId -}}
{{/* Generate client methods (with responses)*/}}
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with arbitrary body{{end}} returning *{{genResponseTypeName $opid}}Container
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}Container, error){
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}}, reqEditors...)
if err != nil {
return nil, err
}
return Parse{{genResponseTypeName $opid | ucFirst}}Container(rsp)
}
{{$hasParams := .RequiresParamObject -}}
{{$pathParams := .PathParams -}}
{{$bodyRequired := .BodyRequired -}}
{{range .Bodies}}
{{if .IsSupportedByClient -}}
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}Container, error) {
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body, reqEditors...)
if err != nil {
return nil, err
}
return Parse{{genResponseTypeName $opid | ucFirst}}Container(rsp)
}
{{end}}
{{end}}
{{end}}{{/* operations */}}
{{/* Generate parse functions for responses*/}}
{{range .}}{{$opid := .OperationId}}
// Parse{{genResponseTypeName $opid | ucFirst}} parses an HTTP response from a {{$opid}}WithResponse call
func Parse{{genResponseTypeName $opid | ucFirst}}Container(rsp *http.Response) (*{{genResponseTypeName $opid}}Container, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &{{genResponseTypeName $opid | ucFirst}}Container{
Body: bodyBytes,
HTTPResponse: rsp,
}
{{genResponseUnmarshal .}}
return response, nil
}
{{end}}{{/* range . $opid := .OperationId */}}

View File

@ -1,181 +1,29 @@
package twhelp
import (
"encoding/json"
"time"
"context"
"net/http"
"golang.org/x/time/rate"
)
type NullBool struct {
Bool bool
Valid bool // Valid is true if Bool is not NULL
}
//go:generate oapi-codegen -templates templates/ --config=config.yml openapi3.json
type ErrorCode string
const (
ErrorCodeInternalServerError ErrorCode = "internal-server-error"
ErrorCodeEntityNotFound ErrorCode = "entity-not-found"
ErrorCodeValidationError ErrorCode = "validation-error"
ErrorCodeRouteNotFound ErrorCode = "route-not-found"
ErrorCodeMethodNotAllowed ErrorCode = "method-not-allowed"
)
func (c ErrorCode) String() string {
return string(c)
}
type APIError struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
}
func (e APIError) Error() string {
return e.Message + " (code=" + e.Code.String() + ")"
}
type errorResp struct {
Error APIError `json:"error"`
}
type Version struct {
Code string `json:"code"`
Host string `json:"host"`
Name string `json:"name"`
Timezone string `json:"timezone"`
}
type listVersionsResp struct {
Data []Version `json:"data"`
}
type Server struct {
Key string `json:"key"`
URL string `json:"url"`
Open bool `json:"open"`
}
type getServerResp struct {
Data Server `json:"data"`
}
type listServersResp struct {
Data []Server `json:"data"`
}
type Tribe struct {
ID int64 `json:"id"`
Tag string `json:"tag"`
Name string `json:"name"`
ProfileURL string `json:"profileUrl"`
DeletedAt time.Time `json:"deletedAt"`
}
type listTribesResp struct {
Data []Tribe `json:"data"`
}
type getTribeResp struct {
Data Tribe `json:"data"`
}
type TribeMeta struct {
ID int64 `json:"id"`
Name string `json:"name"`
Tag string `json:"tag"`
ProfileURL string `json:"profileUrl"`
}
type NullTribeMeta struct {
Tribe TribeMeta
Valid bool
}
func (t NullTribeMeta) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
return json.Marshal(t.Tribe)
}
func (t *NullTribeMeta) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
func WithUserAgent(userAgent string) ClientOption {
return func(client *Client) error {
client.RequestEditors = append(client.RequestEditors, func(_ context.Context, req *http.Request) error {
req.Header.Set("User-Agent", userAgent)
return nil
})
return nil
}
if err := json.Unmarshal(data, &t.Tribe); err != nil {
return err
}
t.Valid = true
return nil
}
type PlayerMeta struct {
ID int64 `json:"id"`
Name string `json:"name"`
ProfileURL string `json:"profileUrl"`
Tribe NullTribeMeta `json:"tribe"`
}
type NullPlayerMeta struct {
Player PlayerMeta
Valid bool
}
func (p NullPlayerMeta) MarshalJSON() ([]byte, error) {
if !p.Valid {
return []byte("null"), nil
}
return json.Marshal(p.Player)
}
func (p *NullPlayerMeta) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
func WithRateLimiter(rl *rate.Limiter) ClientOption {
return func(client *Client) error {
client.RequestEditors = append(client.RequestEditors, func(ctx context.Context, _ *http.Request) error {
return rl.Wait(ctx)
})
return nil
}
if err := json.Unmarshal(data, &p.Player); err != nil {
return err
}
p.Valid = true
return nil
}
type Village struct {
ID int64 `json:"id"`
FullName string `json:"fullName"`
ProfileURL string `json:"profileUrl"`
Points int64 `json:"points"`
X int64 `json:"x"`
Y int64 `json:"y"`
Player NullPlayerMeta `json:"player"`
}
type listVillagesResp struct {
Data []Village `json:"data"`
}
type VillageMeta struct {
ID int64 `json:"id"`
FullName string `json:"fullName"`
ProfileURL string `json:"profileUrl"`
Player NullPlayerMeta `json:"player"`
}
type Ennoblement struct {
ID int64 `json:"id"`
Village VillageMeta `json:"village"`
NewOwner NullPlayerMeta `json:"newOwner"`
CreatedAt time.Time `json:"createdAt"`
}
type listEnnoblementsResp struct {
Data []Ennoblement `json:"data"`
}

View File

@ -1,258 +0,0 @@
package twhelp_test
import (
"encoding/json"
"testing"
"gitea.dwysokinski.me/twhelp/dcbot/internal/twhelp"
"github.com/stretchr/testify/assert"
)
func TestNullTribeMeta_MarshalJSON(t *testing.T) {
t.Parallel()
tests := []struct {
name string
tribe twhelp.NullTribeMeta
expectedJSON string
}{
{
name: "OK: null 1",
tribe: twhelp.NullTribeMeta{
Tribe: twhelp.TribeMeta{},
Valid: false,
},
expectedJSON: "null",
},
{
name: "OK: null 2",
tribe: twhelp.NullTribeMeta{
Tribe: twhelp.TribeMeta{ID: 1234},
Valid: false,
},
expectedJSON: "null",
},
{
name: "OK: valid struct",
tribe: twhelp.NullTribeMeta{
Tribe: twhelp.TribeMeta{
ID: 997,
Name: "name 997",
Tag: "tag 997",
ProfileURL: "profile-997",
},
Valid: true,
},
expectedJSON: `{"id":997,"name":"name 997","tag":"tag 997","profileUrl":"profile-997"}`,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
b, err := json.Marshal(tt.tribe)
assert.NoError(t, err)
assert.JSONEq(t, tt.expectedJSON, string(b))
})
}
}
func TestNullTribeMeta_UnmarshalJSON(t *testing.T) {
t.Parallel()
tests := []struct {
name string
json string
expectedTribe twhelp.NullTribeMeta
expectedJSONSyntaxError bool
}{
{
name: "OK: null",
json: "null",
expectedTribe: twhelp.NullTribeMeta{
Tribe: twhelp.TribeMeta{},
Valid: false,
},
},
{
name: "OK: valid struct",
//nolint:lll
json: `{"id":997,"name":"name 997","tag":"tag 997","profileUrl":"profile-997"}`,
expectedTribe: twhelp.NullTribeMeta{
Tribe: twhelp.TribeMeta{
ID: 997,
Name: "name 997",
Tag: "tag 997",
ProfileURL: "profile-997",
},
Valid: true,
},
},
{
name: "ERR: invalid tribe 1",
json: "2022-07-30T14:13:12.0000005Z",
expectedTribe: twhelp.NullTribeMeta{},
expectedJSONSyntaxError: true,
},
{
name: "ERR: invalid tribe 2",
json: "hello world",
expectedTribe: twhelp.NullTribeMeta{},
expectedJSONSyntaxError: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var target twhelp.NullTribeMeta
err := json.Unmarshal([]byte(tt.json), &target)
if tt.expectedJSONSyntaxError {
var syntaxError *json.SyntaxError
assert.ErrorAs(t, err, &syntaxError)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.expectedTribe, target)
})
}
}
func TestNullPlayerMeta_MarshalJSON(t *testing.T) {
t.Parallel()
tests := []struct {
name string
player twhelp.NullPlayerMeta
expectedJSON string
}{
{
name: "OK: null 1",
player: twhelp.NullPlayerMeta{
Player: twhelp.PlayerMeta{},
Valid: false,
},
expectedJSON: "null",
},
{
name: "OK: null 2",
player: twhelp.NullPlayerMeta{
Player: twhelp.PlayerMeta{ID: 1234},
Valid: false,
},
expectedJSON: "null",
},
{
name: "OK: valid struct",
player: twhelp.NullPlayerMeta{
Player: twhelp.PlayerMeta{
ID: 997,
Name: "name 997",
ProfileURL: "profile-997",
Tribe: twhelp.NullTribeMeta{
Valid: true,
Tribe: twhelp.TribeMeta{
ID: 1234,
Name: "name 997",
ProfileURL: "profile-997",
Tag: "tag 997",
},
},
},
Valid: true,
},
//nolint:lll
expectedJSON: `{"id":997,"name":"name 997","profileUrl":"profile-997","tribe":{"id":1234,"name":"name 997","profileUrl":"profile-997","tag":"tag 997"}}`,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
b, err := json.Marshal(tt.player)
assert.NoError(t, err)
assert.JSONEq(t, tt.expectedJSON, string(b))
})
}
}
func TestNullPlayerMeta_UnmarshalJSON(t *testing.T) {
t.Parallel()
tests := []struct {
name string
json string
expectedPlayer twhelp.NullPlayerMeta
expectedJSONSyntaxError bool
}{
{
name: "OK: null",
json: "null",
expectedPlayer: twhelp.NullPlayerMeta{
Player: twhelp.PlayerMeta{},
Valid: false,
},
},
{
name: "OK: valid struct",
//nolint:lll
json: `{"id":997,"name":"name 997","profileUrl":"profile-997","tribe":{"id":1234,"name":"name 997","profileUrl":"profile-997","tag":"tag 997"}}`,
expectedPlayer: twhelp.NullPlayerMeta{
Player: twhelp.PlayerMeta{
ID: 997,
Name: "name 997",
ProfileURL: "profile-997",
Tribe: twhelp.NullTribeMeta{
Valid: true,
Tribe: twhelp.TribeMeta{
ID: 1234,
Name: "name 997",
ProfileURL: "profile-997",
Tag: "tag 997",
},
},
},
Valid: true,
},
},
{
name: "ERR: invalid tribe 1",
json: "2022-07-30T14:13:12.0000005Z",
expectedPlayer: twhelp.NullPlayerMeta{},
expectedJSONSyntaxError: true,
},
{
name: "ERR: invalid tribe 2",
json: "hello world",
expectedPlayer: twhelp.NullPlayerMeta{},
expectedJSONSyntaxError: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var target twhelp.NullPlayerMeta
err := json.Unmarshal([]byte(tt.json), &target)
if tt.expectedJSONSyntaxError {
var syntaxError *json.SyntaxError
assert.ErrorAs(t, err, &syntaxError)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.expectedPlayer, target)
})
}
}

View File

@ -31,7 +31,7 @@ spec:
name: twhelp-dcbot-secret
key: token
- name: TWHELP_URL
value: "https://tribalwarshelp.com"
value: "https://twhelp.app/api"
- name: TWHELP_RATE_LIMITER_ENABLED
value: "true"
- name: TWHELP_RATE_LIMITER_MAX_REQUESTS_PER_SECOND

View File

@ -31,7 +31,7 @@ spec:
name: twhelp-dcbot-secret
key: token
- name: TWHELP_URL
value: "http://twhelp-api-service:9234"
value: "http://twhelp-api-service:9234/api"
- name: BOT_MAX_GROUPS_PER_SERVER
value: "5"
- name: BOT_MAX_MONITORS_PER_GROUP

View File

@ -4,6 +4,9 @@ build:
tagPolicy:
customTemplate:
template: latest
local:
useBuildkit: true
useDockerCLI: true
artifacts:
- image: dcbot
hooks: