feat: add a new endpoint - GET /api/v1/versions/:code/servers/:key/players/:id (#62)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: twhelp/core#62
This commit is contained in:
parent
4c82b503e9
commit
262c8ae4c7
|
@ -36,6 +36,7 @@ linters:
|
|||
- grouper
|
||||
- errname
|
||||
- exhaustive
|
||||
- tagliatelle
|
||||
|
||||
linters-settings:
|
||||
tagliatelle:
|
||||
|
|
|
@ -95,11 +95,13 @@ func newServer(cfg serverConfig) (*http.Server, error) {
|
|||
versionRepo := bundb.NewVersion(cfg.db)
|
||||
serverRepo := bundb.NewServer(cfg.db)
|
||||
tribeRepo := bundb.NewTribe(cfg.db)
|
||||
playerRepo := bundb.NewPlayer(cfg.db)
|
||||
|
||||
// services
|
||||
versionSvc := service.NewVersion(versionRepo)
|
||||
serverSvc := service.NewServer(serverRepo, client)
|
||||
tribeSvc := service.NewTribe(tribeRepo, client)
|
||||
playerSvc := service.NewPlayer(playerRepo, client)
|
||||
|
||||
// router
|
||||
r := chi.NewRouter()
|
||||
|
@ -109,6 +111,7 @@ func newServer(cfg serverConfig) (*http.Server, error) {
|
|||
VersionService: versionSvc,
|
||||
ServerService: serverSvc,
|
||||
TribeService: tribeSvc,
|
||||
PlayerService: playerSvc,
|
||||
CORS: rest.CORSConfig{
|
||||
Enabled: apiCfg.CORSEnabled,
|
||||
AllowedOrigins: nil,
|
||||
|
|
|
@ -17,6 +17,7 @@ type Player struct {
|
|||
Points int64 `bun:"points,default:0"`
|
||||
Rank int64 `bun:"rank,default:0"`
|
||||
TribeID int64 `bun:"tribe_id,nullzero"`
|
||||
Tribe Tribe `bun:"tribe,rel:belongs-to,join:tribe_id=id,join:server_key=server_key"`
|
||||
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
|
||||
DeletedAt time.Time `bun:"deleted_at,nullzero"`
|
||||
|
||||
|
@ -38,6 +39,13 @@ func NewPlayer(p domain.CreatePlayerParams) Player {
|
|||
}
|
||||
|
||||
func (p Player) ToDomain() domain.Player {
|
||||
var tribe domain.NullTribe
|
||||
if p.Tribe.ID > 0 {
|
||||
tribe = domain.NullTribe{
|
||||
Valid: true,
|
||||
Tribe: p.Tribe.ToDomain(),
|
||||
}
|
||||
}
|
||||
return domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated(p.OpponentsDefeated),
|
||||
|
@ -49,6 +57,7 @@ func (p Player) ToDomain() domain.Player {
|
|||
TribeID: p.TribeID,
|
||||
},
|
||||
ServerKey: p.ServerKey,
|
||||
Tribe: tribe,
|
||||
CreatedAt: p.CreatedAt,
|
||||
DeletedAt: p.DeletedAt,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ func TestNewPlayer(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
deletedAt := time.Now().Add(-100 * time.Hour)
|
||||
params := domain.CreatePlayerParams{
|
||||
playerParams := domain.CreatePlayerParams{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 1,
|
||||
|
@ -34,12 +34,30 @@ func TestNewPlayer(t *testing.T) {
|
|||
},
|
||||
ServerKey: "pl151",
|
||||
}
|
||||
tribeParams := domain.CreateTribeParams{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
ID: playerParams.TribeID,
|
||||
},
|
||||
ServerKey: playerParams.ServerKey,
|
||||
}
|
||||
|
||||
result := model.NewPlayer(playerParams)
|
||||
|
||||
result := model.NewPlayer(params)
|
||||
result.DeletedAt = deletedAt
|
||||
player := result.ToDomain()
|
||||
assert.Equal(t, params.BasePlayer, player.BasePlayer)
|
||||
assert.Equal(t, params.ServerKey, player.ServerKey)
|
||||
assert.Equal(t, playerParams.BasePlayer, player.BasePlayer)
|
||||
assert.Equal(t, playerParams.ServerKey, player.ServerKey)
|
||||
assert.WithinDuration(t, time.Now(), player.CreatedAt, 10*time.Millisecond)
|
||||
assert.Zero(t, player.Tribe)
|
||||
assert.Equal(t, deletedAt, player.DeletedAt)
|
||||
|
||||
result.Tribe = model.NewTribe(tribeParams)
|
||||
result.DeletedAt = time.Time{}
|
||||
player = result.ToDomain()
|
||||
assert.Equal(t, playerParams.BasePlayer, player.BasePlayer)
|
||||
assert.Equal(t, playerParams.ServerKey, player.ServerKey)
|
||||
assert.WithinDuration(t, time.Now(), player.CreatedAt, 10*time.Millisecond)
|
||||
assert.Equal(t, tribeParams.BaseTribe, player.Tribe.Tribe.BaseTribe)
|
||||
assert.True(t, player.Tribe.Valid)
|
||||
assert.Zero(t, player.DeletedAt)
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ func (p *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlay
|
|||
}
|
||||
|
||||
players := make([]model.Player, 0, len(params))
|
||||
for _, p := range params {
|
||||
players = append(players, model.NewPlayer(p))
|
||||
for _, param := range params {
|
||||
players = append(players, model.NewPlayer(param))
|
||||
}
|
||||
if _, err := p.db.NewInsert().
|
||||
Model(&players).
|
||||
|
@ -89,6 +89,7 @@ func (p *Player) List(ctx context.Context, params domain.ListPlayersParams) ([]d
|
|||
for _, player := range players {
|
||||
result = append(result, player.ToDomain())
|
||||
}
|
||||
|
||||
return result, int64(count), nil
|
||||
}
|
||||
|
||||
|
@ -98,20 +99,24 @@ type listPlayersParamsApplier struct {
|
|||
|
||||
func (l listPlayersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
if l.params.IDs != nil {
|
||||
q = q.Where("id IN (?)", bun.In(l.params.IDs))
|
||||
q = q.Where("player.id IN (?)", bun.In(l.params.IDs))
|
||||
}
|
||||
|
||||
if l.params.ServerKeys != nil {
|
||||
q = q.Where("server_key IN (?)", bun.In(l.params.ServerKeys))
|
||||
q = q.Where("player.server_key IN (?)", bun.In(l.params.ServerKeys))
|
||||
}
|
||||
|
||||
if l.params.Deleted.Valid {
|
||||
if l.params.Deleted.Bool {
|
||||
q = q.Where("deleted_at IS NOT NULL")
|
||||
q = q.Where("player.deleted_at IS NOT NULL")
|
||||
} else {
|
||||
q = q.Where("deleted_at IS NULL")
|
||||
q = q.Where("player.deleted_at IS NULL")
|
||||
}
|
||||
}
|
||||
|
||||
return q
|
||||
if l.params.IncludeTribe {
|
||||
q = q.Relation("Tribe")
|
||||
}
|
||||
|
||||
return paginationApplier{l.params.Pagination}.apply(q)
|
||||
}
|
||||
|
|
|
@ -203,6 +203,7 @@ func TestPlayer_List(t *testing.T) {
|
|||
|
||||
type expectedPlayer struct {
|
||||
id int64
|
||||
tribeID int64
|
||||
serverKey string
|
||||
}
|
||||
|
||||
|
@ -263,34 +264,84 @@ func TestPlayer_List(t *testing.T) {
|
|||
expectedCount: 1,
|
||||
},
|
||||
{
|
||||
name: "IDs=[8625053,622676],ServerKeys=[en113],Count=true",
|
||||
params: domain.ListPlayersParams{IDs: []int64{8625053, 622676}, ServerKeys: []string{"en113"}, Count: true},
|
||||
name: "IDs=[6180190,8419570,699736927],Limit=1,ServerKeys=[pl169],Count=true",
|
||||
params: domain.ListPlayersParams{
|
||||
IDs: []int64{6180190, 8419570, 699736927},
|
||||
ServerKeys: []string{"pl169"},
|
||||
Pagination: domain.Pagination{
|
||||
Limit: 1,
|
||||
},
|
||||
Count: true,
|
||||
},
|
||||
expectedPlayers: []expectedPlayer{
|
||||
{
|
||||
id: 6180190,
|
||||
serverKey: "pl169",
|
||||
},
|
||||
},
|
||||
expectedCount: 3,
|
||||
},
|
||||
{
|
||||
name: "IDs=[6180190,8419570,699736927],Offset=1,ServerKeys=[pl169],Count=true",
|
||||
params: domain.ListPlayersParams{
|
||||
IDs: []int64{6180190, 8419570, 699736927},
|
||||
ServerKeys: []string{"pl169"},
|
||||
Pagination: domain.Pagination{
|
||||
Offset: 1,
|
||||
},
|
||||
Count: true,
|
||||
},
|
||||
expectedPlayers: []expectedPlayer{
|
||||
{
|
||||
id: 8419570,
|
||||
serverKey: "pl169",
|
||||
},
|
||||
{
|
||||
id: 699736927,
|
||||
serverKey: "pl169",
|
||||
},
|
||||
},
|
||||
expectedCount: 3,
|
||||
},
|
||||
{
|
||||
name: "IDs=[8625053,622676],IncludeTribe=true,ServerKeys=[en113],Count=true",
|
||||
params: domain.ListPlayersParams{
|
||||
IDs: []int64{8625053, 622676},
|
||||
ServerKeys: []string{"en113"},
|
||||
IncludeTribe: true,
|
||||
Count: true,
|
||||
},
|
||||
expectedPlayers: []expectedPlayer{
|
||||
{
|
||||
id: 8625053,
|
||||
tribeID: 122,
|
||||
serverKey: "en113",
|
||||
},
|
||||
{
|
||||
id: 622676,
|
||||
tribeID: 122,
|
||||
serverKey: "en113",
|
||||
},
|
||||
},
|
||||
expectedCount: 2,
|
||||
},
|
||||
{
|
||||
name: "Deleted=true,ServerKeys=[en113],Count=true",
|
||||
name: "Deleted=true,IncludeTribe=true,ServerKeys=[en113],Count=true",
|
||||
params: domain.ListPlayersParams{
|
||||
Deleted: domain.NullBool{Bool: true, Valid: true},
|
||||
ServerKeys: []string{"en113"},
|
||||
Count: true,
|
||||
Deleted: domain.NullBool{Bool: true, Valid: true},
|
||||
ServerKeys: []string{"en113"},
|
||||
IncludeTribe: true,
|
||||
Count: true,
|
||||
},
|
||||
expectedPlayers: []expectedPlayer{
|
||||
{
|
||||
id: 1111,
|
||||
tribeID: 0,
|
||||
serverKey: "en113",
|
||||
},
|
||||
{
|
||||
id: 1112,
|
||||
tribeID: 0,
|
||||
serverKey: "en113",
|
||||
},
|
||||
},
|
||||
|
@ -311,12 +362,29 @@ func TestPlayer_List(t *testing.T) {
|
|||
for _, expPlayer := range tt.expectedPlayers {
|
||||
found := false
|
||||
for _, player := range res {
|
||||
if player.ID == expPlayer.id && player.ServerKey == expPlayer.serverKey {
|
||||
found = true
|
||||
break
|
||||
if player.ID != expPlayer.id {
|
||||
continue
|
||||
}
|
||||
|
||||
if player.ServerKey != expPlayer.serverKey {
|
||||
continue
|
||||
}
|
||||
|
||||
if player.Tribe.Tribe.ID != expPlayer.tribeID {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
break
|
||||
}
|
||||
assert.True(t, found, "player (id=%d,serverkey=%s) not found", expPlayer.id, expPlayer.serverKey)
|
||||
assert.True(
|
||||
t,
|
||||
found,
|
||||
"player (id=%d,tribeID=%d,serverkey=%s) not found",
|
||||
expPlayer.id,
|
||||
expPlayer.tribeID,
|
||||
expPlayer.serverKey,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BasePlayer struct {
|
||||
OpponentsDefeated
|
||||
|
@ -17,6 +20,7 @@ type Player struct {
|
|||
BasePlayer
|
||||
|
||||
ServerKey string
|
||||
Tribe NullTribe // only available when ListPlayersParams.IncludeTribe == true
|
||||
CreatedAt time.Time
|
||||
DeletedAt time.Time
|
||||
}
|
||||
|
@ -28,8 +32,26 @@ type CreatePlayerParams struct {
|
|||
}
|
||||
|
||||
type ListPlayersParams struct {
|
||||
IDs []int64
|
||||
ServerKeys []string
|
||||
Deleted NullBool
|
||||
Count bool
|
||||
IDs []int64
|
||||
ServerKeys []string
|
||||
Deleted NullBool
|
||||
IncludeTribe bool
|
||||
Pagination Pagination
|
||||
Count bool
|
||||
}
|
||||
|
||||
type PlayerNotFoundError struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (e PlayerNotFoundError) Error() string {
|
||||
return fmt.Sprintf("player (id=%d) not found", e.ID)
|
||||
}
|
||||
|
||||
func (e PlayerNotFoundError) UserError() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
func (e PlayerNotFoundError) Code() ErrorCode {
|
||||
return ErrorCodeEntityNotFound
|
||||
}
|
||||
|
|
20
internal/domain/player_test.go
Normal file
20
internal/domain/player_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package domain_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPlayerNotFoundError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := domain.PlayerNotFoundError{
|
||||
ID: 1234,
|
||||
}
|
||||
var _ domain.UserError = err
|
||||
assert.Equal(t, "player (id=1234) not found", err.Error())
|
||||
assert.Equal(t, err.Error(), err.UserError())
|
||||
assert.Equal(t, domain.ErrorCodeEntityNotFound, err.Code())
|
||||
}
|
|
@ -27,6 +27,11 @@ type Tribe struct {
|
|||
DeletedAt time.Time
|
||||
}
|
||||
|
||||
type NullTribe struct {
|
||||
Valid bool
|
||||
Tribe Tribe
|
||||
}
|
||||
|
||||
type CreateTribeParams struct {
|
||||
BaseTribe
|
||||
|
||||
|
|
1
internal/rest/.swaggo
Normal file
1
internal/rest/.swaggo
Normal file
|
@ -0,0 +1 @@
|
|||
replace gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model.NullTribe gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model.Tribe
|
67
internal/rest/internal/model/player.go
Normal file
67
internal/rest/internal/model/player.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
NumVillages int64 `json:"numVillages"`
|
||||
Points int64 `json:"points"`
|
||||
Rank int64 `json:"rank"`
|
||||
Tribe NullTribe `json:"tribe" extensions:"x-nullable"`
|
||||
RankAtt int64 `json:"rankAtt"`
|
||||
ScoreAtt int64 `json:"scoreAtt"`
|
||||
RankDef int64 `json:"rankDef"`
|
||||
ScoreDef int64 `json:"scoreDef"`
|
||||
RankSup int64 `json:"rankSup"`
|
||||
ScoreSup int64 `json:"scoreSup"`
|
||||
RankTotal int64 `json:"rankTotal"`
|
||||
ScoreTotal int64 `json:"scoreTotal"`
|
||||
CreatedAt time.Time `json:"createdAt" format:"date-time"`
|
||||
DeletedAt NullTime `json:"deletedAt" swaggertype:"string" format:"date-time" extensions:"x-nullable"`
|
||||
} // @name Player
|
||||
|
||||
func NewPlayer(p domain.Player) Player {
|
||||
var t NullTribe
|
||||
if p.Tribe.Valid {
|
||||
t = NullTribe{
|
||||
Valid: true,
|
||||
Tribe: NewTribe(p.Tribe.Tribe),
|
||||
}
|
||||
}
|
||||
return Player{
|
||||
ID: p.ID,
|
||||
Name: p.Name,
|
||||
NumVillages: p.NumVillages,
|
||||
Points: p.Points,
|
||||
Rank: p.Rank,
|
||||
Tribe: t,
|
||||
RankAtt: p.RankAtt,
|
||||
ScoreAtt: p.ScoreAtt,
|
||||
RankDef: p.RankDef,
|
||||
ScoreDef: p.ScoreDef,
|
||||
RankSup: p.RankSup,
|
||||
ScoreSup: p.ScoreSup,
|
||||
RankTotal: p.RankTotal,
|
||||
ScoreTotal: p.ScoreTotal,
|
||||
CreatedAt: p.CreatedAt,
|
||||
DeletedAt: NullTime{
|
||||
Time: p.DeletedAt,
|
||||
Valid: !p.DeletedAt.IsZero(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type GetPlayerResp struct {
|
||||
Data Player `json:"data"`
|
||||
} // @name GetPlayerResp
|
||||
|
||||
func NewGetPlayerResp(v domain.Player) GetPlayerResp {
|
||||
return GetPlayerResp{
|
||||
Data: NewPlayer(v),
|
||||
}
|
||||
}
|
135
internal/rest/internal/model/player_test.go
Normal file
135
internal/rest/internal/model/player_test.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewPlayer(t *testing.T) {
|
||||
playerWithoutTribe := domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
Rank: 2,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
assertPlayer(t, playerWithoutTribe, model.NewPlayer(playerWithoutTribe))
|
||||
|
||||
playerWithTribe := domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
Rank: 2,
|
||||
TribeID: 1234,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
Tribe: domain.NullTribe{
|
||||
Valid: true,
|
||||
Tribe: domain.Tribe{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 1234,
|
||||
Name: "name 997",
|
||||
Tag: "tag 997",
|
||||
NumMembers: 6,
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
AllPoints: 3,
|
||||
Rank: 2,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
Dominance: 12.5,
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
},
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
assertPlayer(t, playerWithTribe, model.NewPlayer(playerWithTribe))
|
||||
}
|
||||
|
||||
func TestNewGetPlayerResp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
player := domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
Rank: 2,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
assertPlayer(t, player, model.NewGetPlayerResp(player).Data)
|
||||
}
|
||||
|
||||
func assertPlayer(tb testing.TB, dt domain.Player, rt model.Player) {
|
||||
tb.Helper()
|
||||
|
||||
assert.Equal(tb, dt.ID, rt.ID)
|
||||
assert.Equal(tb, dt.Name, rt.Name)
|
||||
assert.Equal(tb, dt.NumVillages, rt.NumVillages)
|
||||
assert.Equal(tb, dt.Points, rt.Points)
|
||||
assert.Equal(tb, dt.Rank, rt.Rank)
|
||||
assert.Equal(tb, dt.RankAtt, rt.RankAtt)
|
||||
assert.Equal(tb, dt.ScoreAtt, rt.ScoreAtt)
|
||||
assert.Equal(tb, dt.RankDef, rt.RankDef)
|
||||
assert.Equal(tb, dt.ScoreDef, rt.ScoreDef)
|
||||
assert.Equal(tb, dt.RankSup, rt.RankSup)
|
||||
assert.Equal(tb, dt.ScoreSup, rt.ScoreSup)
|
||||
assert.Equal(tb, dt.RankTotal, rt.RankTotal)
|
||||
assert.Equal(tb, dt.ScoreTotal, rt.ScoreTotal)
|
||||
assert.Equal(tb, dt.CreatedAt, rt.CreatedAt)
|
||||
assertNullTribe(tb, dt.Tribe, rt.Tribe)
|
||||
assertNullTime(tb, dt.DeletedAt, rt.DeletedAt)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
|
@ -51,6 +52,34 @@ func NewTribe(t domain.Tribe) Tribe {
|
|||
}
|
||||
}
|
||||
|
||||
type NullTribe struct {
|
||||
Tribe Tribe
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t NullTribe) MarshalJSON() ([]byte, error) {
|
||||
if !t.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
return json.Marshal(t.Tribe)
|
||||
}
|
||||
|
||||
func (t *NullTribe) UnmarshalJSON(data []byte) error {
|
||||
// Ignore null, like in the main JSON package.
|
||||
if string(data) == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &t.Tribe); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Valid = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListTribesResp struct {
|
||||
Data []Tribe `json:"data"`
|
||||
} // @name ListTribesResp
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -42,6 +43,147 @@ func TestNewTribe(t *testing.T) {
|
|||
assertTribe(t, tribe, model.NewTribe(tribe))
|
||||
}
|
||||
|
||||
func TestNullTribe_MarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tribe model.NullTribe
|
||||
expectedJSON string
|
||||
}{
|
||||
{
|
||||
name: "OK: null 1",
|
||||
tribe: model.NullTribe{
|
||||
Tribe: model.Tribe{},
|
||||
Valid: false,
|
||||
},
|
||||
expectedJSON: "null",
|
||||
},
|
||||
{
|
||||
name: "OK: null 2",
|
||||
tribe: model.NullTribe{
|
||||
Tribe: model.Tribe{ID: 1234},
|
||||
Valid: false,
|
||||
},
|
||||
expectedJSON: "null",
|
||||
},
|
||||
{
|
||||
name: "OK: valid struct",
|
||||
tribe: model.NullTribe{
|
||||
Tribe: model.Tribe{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
Tag: "tag 997",
|
||||
NumMembers: 6,
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
AllPoints: 3,
|
||||
Rank: 2,
|
||||
Dominance: 12.5,
|
||||
CreatedAt: time.Date(2022, time.July, 30, 14, 13, 12, 0, time.UTC),
|
||||
},
|
||||
Valid: true,
|
||||
},
|
||||
//nolint:lll
|
||||
expectedJSON: `{"id":997,"name":"name 997","tag":"tag 997","numMembers":6,"numVillages":5,"points":4,"allPoints":3,"rank":2,"dominance":12.5,"rankAtt":8,"scoreAtt":7,"rankDef":6,"scoreDef":5,"rankTotal":2,"scoreTotal":1,"createdAt":"2022-07-30T14:13:12Z","deletedAt":null}`,
|
||||
},
|
||||
}
|
||||
|
||||
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 TestNullTribe_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
json string
|
||||
expectedTribe model.NullTribe
|
||||
expectedJSONSyntaxError bool
|
||||
}{
|
||||
{
|
||||
name: "OK: null",
|
||||
json: "null",
|
||||
expectedTribe: model.NullTribe{
|
||||
Tribe: model.Tribe{},
|
||||
Valid: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: valid struct",
|
||||
//nolint:lll
|
||||
json: `{"id":997,"name":"name 997","tag":"tag 997","numMembers":6,"numVillages":5,"points":4,"allPoints":3,"rank":2,"dominance":12.5,"rankAtt":8,"scoreAtt":7,"rankDef":6,"scoreDef":5,"rankTotal":2,"scoreTotal":1,"createdAt":"2022-07-30T14:13:12Z","deletedAt":null}`,
|
||||
expectedTribe: model.NullTribe{
|
||||
Tribe: model.Tribe{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
Tag: "tag 997",
|
||||
NumMembers: 6,
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
AllPoints: 3,
|
||||
Rank: 2,
|
||||
Dominance: 12.5,
|
||||
CreatedAt: time.Date(2022, time.July, 30, 14, 13, 12, 0, time.UTC),
|
||||
},
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: invalid tribe 1",
|
||||
json: "2022-07-30T14:13:12.0000005Z",
|
||||
expectedTribe: model.NullTribe{},
|
||||
expectedJSONSyntaxError: true,
|
||||
},
|
||||
{
|
||||
name: "ERR: invalid tribe 2",
|
||||
json: "hello world",
|
||||
expectedTribe: model.NullTribe{},
|
||||
expectedJSONSyntaxError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var target model.NullTribe
|
||||
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 TestNewListTribesResp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -157,3 +299,16 @@ func assertTribe(tb testing.TB, dt domain.Tribe, rt model.Tribe) {
|
|||
assert.Equal(tb, dt.CreatedAt, rt.CreatedAt)
|
||||
assertNullTime(tb, dt.DeletedAt, rt.DeletedAt)
|
||||
}
|
||||
|
||||
func assertNullTribe(tb testing.TB, dt domain.NullTribe, rt model.NullTribe) {
|
||||
tb.Helper()
|
||||
|
||||
if !dt.Valid {
|
||||
assert.False(tb, rt.Valid)
|
||||
assert.Zero(tb, rt.Tribe)
|
||||
return
|
||||
}
|
||||
|
||||
assert.True(tb, rt.Valid)
|
||||
assertTribe(tb, dt.Tribe, rt.Tribe)
|
||||
}
|
||||
|
|
52
internal/rest/player.go
Normal file
52
internal/rest/player.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model"
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
)
|
||||
|
||||
//counterfeiter:generate -o internal/mock/player_service.gen.go . PlayerService
|
||||
type PlayerService interface {
|
||||
GetByServerKeyAndID(ctx context.Context, serverKey string, id int64, includeTribe bool) (domain.Player, error)
|
||||
}
|
||||
|
||||
type player struct {
|
||||
svc PlayerService
|
||||
}
|
||||
|
||||
// @ID getPlayer
|
||||
// @Summary Get a player
|
||||
// @Description Get a player
|
||||
// @Tags versions,servers,players
|
||||
// @Produce json
|
||||
// @Success 200 {object} model.GetPlayerResp
|
||||
// @Failure 400 {object} model.ErrorResp
|
||||
// @Failure 404 {object} model.ErrorResp
|
||||
// @Failure 500 {object} model.ErrorResp
|
||||
// @Param versionCode path string true "Version code"
|
||||
// @Param serverKey path string true "Server key"
|
||||
// @Param playerId path integer true "Player ID"
|
||||
// @Router /versions/{versionCode}/servers/{serverKey}/players/{playerId} [get]
|
||||
func (p *player) getByID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
routeCtx := chi.RouteContext(ctx)
|
||||
|
||||
playerID, err := urlParamInt64(routeCtx, "playerId")
|
||||
if err != nil {
|
||||
renderErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
pl, err := p.svc.GetByServerKeyAndID(ctx, routeCtx.URLParam("serverKey"), playerID, true)
|
||||
if err != nil {
|
||||
renderErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
renderJSON(w, http.StatusOK, model.NewGetPlayerResp(pl))
|
||||
}
|
247
internal/rest/player_test.go
Normal file
247
internal/rest/player_test.go
Normal file
|
@ -0,0 +1,247 @@
|
|||
package rest_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/rest"
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/rest/internal/mock"
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model"
|
||||
)
|
||||
|
||||
func TestPlayer_getByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Now()
|
||||
version := domain.Version{
|
||||
Code: "pl",
|
||||
Name: "Poland",
|
||||
Host: "plemiona.pl",
|
||||
Timezone: "Europe/Warsaw",
|
||||
}
|
||||
server := domain.Server{
|
||||
Key: "pl151",
|
||||
URL: "https://pl151.plemiona.pl",
|
||||
Open: true,
|
||||
Special: false,
|
||||
VersionCode: "pl",
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService)
|
||||
versionCode string
|
||||
serverKey string
|
||||
id string
|
||||
expectedStatus int
|
||||
target any
|
||||
expectedResponse any
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
playerSvc.GetByServerKeyAndIDReturns(domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
Rank: 2,
|
||||
TribeID: 1234,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
Tribe: domain.NullTribe{
|
||||
Valid: true,
|
||||
Tribe: domain.Tribe{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
},
|
||||
ID: 1234,
|
||||
Name: "name 997",
|
||||
Tag: "tag 997",
|
||||
NumMembers: 6,
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
AllPoints: 3,
|
||||
Rank: 2,
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
Dominance: 12.5,
|
||||
CreatedAt: now,
|
||||
},
|
||||
},
|
||||
CreatedAt: now,
|
||||
}, nil)
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: "pl151",
|
||||
id: "997",
|
||||
expectedStatus: http.StatusOK,
|
||||
target: &model.GetPlayerResp{},
|
||||
expectedResponse: &model.GetPlayerResp{
|
||||
Data: model.Player{
|
||||
ID: 997,
|
||||
Name: "name 997",
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
Rank: 2,
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankSup: 4,
|
||||
ScoreSup: 3,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
CreatedAt: now,
|
||||
Tribe: model.NullTribe{
|
||||
Tribe: model.Tribe{
|
||||
ID: 1234,
|
||||
Name: "name 997",
|
||||
Tag: "tag 997",
|
||||
NumMembers: 6,
|
||||
NumVillages: 5,
|
||||
Points: 4,
|
||||
AllPoints: 3,
|
||||
Rank: 2,
|
||||
Dominance: 12.5,
|
||||
RankAtt: 8,
|
||||
ScoreAtt: 7,
|
||||
RankDef: 6,
|
||||
ScoreDef: 5,
|
||||
RankTotal: 2,
|
||||
ScoreTotal: 1,
|
||||
CreatedAt: now,
|
||||
},
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: player id is not a valid int64",
|
||||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: "pl1512",
|
||||
id: "true",
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: domain.ErrorCodeValidationError.String(),
|
||||
Message: "playerId: strconv.ParseInt: parsing \"true\": invalid syntax",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: version not found",
|
||||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService) {
|
||||
versionSvc.GetByCodeReturns(domain.Version{}, domain.VersionNotFoundError{VerCode: version.Code + "2"})
|
||||
},
|
||||
versionCode: version.Code + "2",
|
||||
serverKey: "pl151",
|
||||
id: "1234",
|
||||
expectedStatus: http.StatusNotFound,
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||
Message: fmt.Sprintf("version (code=%s) not found", version.Code+"2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: server not found",
|
||||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(domain.Server{}, domain.ServerNotFoundError{Key: "pl1512"})
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: "pl1512",
|
||||
id: "1234",
|
||||
expectedStatus: http.StatusNotFound,
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||
Message: "server (key=pl1512) not found",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: player not found",
|
||||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
playerSvc.GetByServerKeyAndIDReturns(domain.Player{}, domain.PlayerNotFoundError{ID: 12345551})
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: server.Key,
|
||||
id: "12345551",
|
||||
expectedStatus: http.StatusNotFound,
|
||||
target: &model.ErrorResp{},
|
||||
expectedResponse: &model.ErrorResp{
|
||||
Error: model.APIError{
|
||||
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||
Message: "player (id=12345551) not found",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
versionSvc := &mock.FakeVersionService{}
|
||||
serverSvc := &mock.FakeServerService{}
|
||||
playerSvc := &mock.FakePlayerService{}
|
||||
tt.setup(versionSvc, serverSvc, playerSvc)
|
||||
|
||||
router := rest.NewRouter(rest.RouterConfig{
|
||||
VersionService: versionSvc,
|
||||
ServerService: serverSvc,
|
||||
PlayerService: playerSvc,
|
||||
})
|
||||
|
||||
target := fmt.Sprintf(
|
||||
"/v1/versions/%s/servers/%s/players/%s",
|
||||
tt.versionCode,
|
||||
tt.serverKey,
|
||||
tt.id,
|
||||
)
|
||||
log.Println(target)
|
||||
resp := doRequest(router, http.MethodGet, target, nil)
|
||||
defer resp.Body.Close()
|
||||
assertJSONResponse(t, resp, tt.expectedStatus, tt.expectedResponse, tt.target)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ type RouterConfig struct {
|
|||
VersionService VersionService
|
||||
ServerService ServerService
|
||||
TribeService TribeService
|
||||
PlayerService PlayerService
|
||||
CORS CORSConfig
|
||||
Swagger bool
|
||||
}
|
||||
|
@ -47,6 +48,9 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
|
|||
tribeHandler := &tribe{
|
||||
svc: cfg.TribeService,
|
||||
}
|
||||
playerHandler := &player{
|
||||
svc: cfg.PlayerService,
|
||||
}
|
||||
|
||||
router := chi.NewRouter()
|
||||
|
||||
|
@ -77,12 +81,19 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
|
|||
r.Get("/", serverHandler.list)
|
||||
r.Route("/{serverKey}", func(r chi.Router) {
|
||||
r.Get("/", serverHandler.getByKey)
|
||||
r.With(verifyServerKey(cfg.ServerService)).
|
||||
|
||||
verifyServerKeyMiddleware := verifyServerKey(cfg.ServerService)
|
||||
|
||||
r.With(verifyServerKeyMiddleware).
|
||||
Route("/tribes", func(r chi.Router) {
|
||||
r.Get("/", tribeHandler.list)
|
||||
r.Get("/{tribeId}", tribeHandler.getByID)
|
||||
r.Get("/tag/{tribeTag}", tribeHandler.getByTag)
|
||||
})
|
||||
r.With(verifyServerKeyMiddleware).
|
||||
Route("/players", func(r chi.Router) {
|
||||
r.Get("/{playerId}", playerHandler.getByID)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -18,8 +18,8 @@ const (
|
|||
//counterfeiter:generate -o internal/mock/tribe_service.gen.go . TribeService
|
||||
type TribeService interface {
|
||||
List(ctx context.Context, params domain.ListTribesParams) ([]domain.Tribe, int64, error)
|
||||
GetTribeByServerKeyAndID(ctx context.Context, serverKey string, id int64) (domain.Tribe, error)
|
||||
GetTribeByServerKeyAndTag(ctx context.Context, serverKey string, tag string) (domain.Tribe, error)
|
||||
GetByServerKeyAndID(ctx context.Context, serverKey string, id int64) (domain.Tribe, error)
|
||||
GetByServerKeyAndTag(ctx context.Context, serverKey string, tag string) (domain.Tribe, error)
|
||||
}
|
||||
|
||||
type tribe struct {
|
||||
|
@ -103,7 +103,7 @@ func (t *tribe) getByID(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
trb, err := t.svc.GetTribeByServerKeyAndID(ctx, routeCtx.URLParam("serverKey"), tribeID)
|
||||
trb, err := t.svc.GetByServerKeyAndID(ctx, routeCtx.URLParam("serverKey"), tribeID)
|
||||
if err != nil {
|
||||
renderErr(w, err)
|
||||
return
|
||||
|
@ -128,7 +128,7 @@ func (t *tribe) getByTag(w http.ResponseWriter, r *http.Request) {
|
|||
ctx := r.Context()
|
||||
routeCtx := chi.RouteContext(ctx)
|
||||
|
||||
trb, err := t.svc.GetTribeByServerKeyAndTag(
|
||||
trb, err := t.svc.GetByServerKeyAndTag(
|
||||
ctx,
|
||||
routeCtx.URLParam("serverKey"),
|
||||
routeCtx.URLParam("tribeTag"),
|
||||
|
|
|
@ -645,7 +645,7 @@ func TestTribe_getByID(t *testing.T) {
|
|||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, tribeSvc *mock.FakeTribeService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
tribeSvc.GetTribeByServerKeyAndIDReturns(domain.Tribe{
|
||||
tribeSvc.GetByServerKeyAndIDReturns(domain.Tribe{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
|
@ -755,7 +755,7 @@ func TestTribe_getByID(t *testing.T) {
|
|||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, tribeSvc *mock.FakeTribeService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
tribeSvc.GetTribeByServerKeyAndIDReturns(domain.Tribe{}, domain.TribeNotFoundError{ID: 12345551})
|
||||
tribeSvc.GetByServerKeyAndIDReturns(domain.Tribe{}, domain.TribeNotFoundError{ID: 12345551})
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: server.Key,
|
||||
|
@ -833,7 +833,7 @@ func TestTribe_getByTag(t *testing.T) {
|
|||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, tribeSvc *mock.FakeTribeService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
tribeSvc.GetTribeByServerKeyAndTagReturns(domain.Tribe{
|
||||
tribeSvc.GetByServerKeyAndTagReturns(domain.Tribe{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
OpponentsDefeated: domain.OpponentsDefeated{
|
||||
RankAtt: 8,
|
||||
|
@ -925,7 +925,7 @@ func TestTribe_getByTag(t *testing.T) {
|
|||
setup: func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, tribeSvc *mock.FakeTribeService) {
|
||||
versionSvc.GetByCodeReturns(version, nil)
|
||||
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||
tribeSvc.GetTribeByServerKeyAndTagReturns(domain.Tribe{}, domain.TribeNotFoundError{Tag: "*CSA*"})
|
||||
tribeSvc.GetByServerKeyAndTagReturns(domain.Tribe{}, domain.TribeNotFoundError{Tag: "*CSA*"})
|
||||
},
|
||||
versionCode: version.Code,
|
||||
serverKey: server.Key,
|
||||
|
|
|
@ -76,3 +76,23 @@ func (p *Player) Refresh(ctx context.Context, key, url string) (int64, error) {
|
|||
|
||||
return int64(len(players)), nil
|
||||
}
|
||||
|
||||
func (p *Player) GetByServerKeyAndID(ctx context.Context, serverKey string, id int64, includeTribe bool) (domain.Player, error) {
|
||||
players, _, err := p.repo.List(ctx, domain.ListPlayersParams{
|
||||
IDs: []int64{id},
|
||||
ServerKeys: []string{serverKey},
|
||||
IncludeTribe: includeTribe,
|
||||
Pagination: domain.Pagination{
|
||||
Limit: 1,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Player{}, fmt.Errorf("PlayerRepository.List: %w", err)
|
||||
}
|
||||
if len(players) == 0 {
|
||||
return domain.Player{}, domain.PlayerNotFoundError{
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
return players[0], nil
|
||||
}
|
||||
|
|
|
@ -113,3 +113,59 @@ func TestPlayer_Refresh(t *testing.T) {
|
|||
|
||||
require.Equal(t, 1, repo.ListCallCount())
|
||||
}
|
||||
|
||||
func TestPlayer_GetByServerKeyAndID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
player := domain.Player{
|
||||
BasePlayer: domain.BasePlayer{
|
||||
ID: 123,
|
||||
TribeID: 123,
|
||||
},
|
||||
Tribe: domain.NullTribe{
|
||||
Valid: true,
|
||||
Tribe: domain.Tribe{
|
||||
BaseTribe: domain.BaseTribe{
|
||||
ID: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
ServerKey: "pl151",
|
||||
}
|
||||
repo := &mock.FakePlayerRepository{}
|
||||
repo.ListReturns([]domain.Player{player}, 0, nil)
|
||||
client := &mock.FakePlayersGetter{}
|
||||
|
||||
res, err := service.NewPlayer(repo, client).
|
||||
GetByServerKeyAndID(context.Background(), player.ServerKey, player.ID, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, player, res)
|
||||
require.Equal(t, 1, repo.ListCallCount())
|
||||
_, params := repo.ListArgsForCall(0)
|
||||
assert.Equal(t, domain.ListPlayersParams{
|
||||
IDs: []int64{player.ID},
|
||||
ServerKeys: []string{player.ServerKey},
|
||||
IncludeTribe: true,
|
||||
Pagination: domain.Pagination{
|
||||
Limit: 1,
|
||||
},
|
||||
}, params)
|
||||
|
||||
})
|
||||
|
||||
t.Run("ERR: player not found", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
repo := &mock.FakePlayerRepository{}
|
||||
client := &mock.FakePlayersGetter{}
|
||||
|
||||
var id int64 = 123
|
||||
res, err := service.NewPlayer(repo, client).
|
||||
GetByServerKeyAndID(context.Background(), "pl151", id, false)
|
||||
assert.ErrorIs(t, err, domain.PlayerNotFoundError{ID: id})
|
||||
assert.Zero(t, res)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ func (t *Tribe) List(ctx context.Context, params domain.ListTribesParams) ([]dom
|
|||
return servers, count, nil
|
||||
}
|
||||
|
||||
func (t *Tribe) GetTribeByServerKeyAndID(ctx context.Context, serverKey string, id int64) (domain.Tribe, error) {
|
||||
func (t *Tribe) GetByServerKeyAndID(ctx context.Context, serverKey string, id int64) (domain.Tribe, error) {
|
||||
tribes, _, err := t.repo.List(ctx, domain.ListTribesParams{
|
||||
IDs: []int64{id},
|
||||
ServerKeys: []string{serverKey},
|
||||
|
@ -143,7 +143,7 @@ func (t *Tribe) GetTribeByServerKeyAndID(ctx context.Context, serverKey string,
|
|||
return tribes[0], nil
|
||||
}
|
||||
|
||||
func (t *Tribe) GetTribeByServerKeyAndTag(ctx context.Context, serverKey string, tag string) (domain.Tribe, error) {
|
||||
func (t *Tribe) GetByServerKeyAndTag(ctx context.Context, serverKey string, tag string) (domain.Tribe, error) {
|
||||
tribes, _, err := t.repo.List(ctx, domain.ListTribesParams{
|
||||
Tags: []string{tag},
|
||||
ServerKeys: []string{serverKey},
|
||||
|
|
|
@ -305,7 +305,7 @@ func TestTribe_List(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestTribe_GetTribeByServerKeyAndID(t *testing.T) {
|
||||
func TestTribe_GetByServerKeyAndID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
|
@ -322,7 +322,7 @@ func TestTribe_GetTribeByServerKeyAndID(t *testing.T) {
|
|||
client := &mock.FakeTribesGetter{}
|
||||
|
||||
res, err := service.NewTribe(repo, client).
|
||||
GetTribeByServerKeyAndID(context.Background(), tribe.ServerKey, tribe.ID)
|
||||
GetByServerKeyAndID(context.Background(), tribe.ServerKey, tribe.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tribe, res)
|
||||
require.Equal(t, 1, repo.ListCallCount())
|
||||
|
@ -345,13 +345,13 @@ func TestTribe_GetTribeByServerKeyAndID(t *testing.T) {
|
|||
|
||||
var id int64 = 123
|
||||
res, err := service.NewTribe(repo, client).
|
||||
GetTribeByServerKeyAndID(context.Background(), "pl151", id)
|
||||
GetByServerKeyAndID(context.Background(), "pl151", id)
|
||||
assert.ErrorIs(t, err, domain.TribeNotFoundError{ID: id})
|
||||
assert.Zero(t, res)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTribe_GetTribeByServerKeyAndTag(t *testing.T) {
|
||||
func TestTribe_GetByServerKeyAndTag(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
|
@ -369,7 +369,7 @@ func TestTribe_GetTribeByServerKeyAndTag(t *testing.T) {
|
|||
client := &mock.FakeTribesGetter{}
|
||||
|
||||
res, err := service.NewTribe(repo, client).
|
||||
GetTribeByServerKeyAndTag(context.Background(), tribe.ServerKey, tribe.Tag)
|
||||
GetByServerKeyAndTag(context.Background(), tribe.ServerKey, tribe.Tag)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tribe, res)
|
||||
require.Equal(t, 1, repo.ListCallCount())
|
||||
|
@ -392,7 +392,7 @@ func TestTribe_GetTribeByServerKeyAndTag(t *testing.T) {
|
|||
|
||||
tag := "taggg"
|
||||
res, err := service.NewTribe(repo, client).
|
||||
GetTribeByServerKeyAndTag(context.Background(), "pl151", tag)
|
||||
GetByServerKeyAndTag(context.Background(), "pl151", tag)
|
||||
assert.ErrorIs(t, err, domain.TribeNotFoundError{Tag: tag})
|
||||
assert.Zero(t, res)
|
||||
})
|
||||
|
|
Reference in New Issue
Block a user