feat: new rest endpoint - /versions/{code}/servers/{key}/tribes/{id}/members
All checks were successful
continuous-integration/drone/pr Build is passing
All checks were successful
continuous-integration/drone/pr Build is passing
This commit is contained in:
parent
5379e75d79
commit
ee0cbd2cf4
|
@ -109,3 +109,6 @@ issues:
|
||||||
- linters:
|
- linters:
|
||||||
- lll
|
- lll
|
||||||
source: "^// @Param"
|
source: "^// @Param"
|
||||||
|
- path: internal/domain/(server_config|unit_info|opponents_defeated|building_info).go # TODO: https://github.com/dominikh/go-tools/issues/1360 needs to be released
|
||||||
|
linters:
|
||||||
|
- unused
|
||||||
|
|
|
@ -6,6 +6,6 @@ repos:
|
||||||
stages: [commit-msg]
|
stages: [commit-msg]
|
||||||
additional_dependencies: ['@commitlint/config-conventional']
|
additional_dependencies: ['@commitlint/config-conventional']
|
||||||
- repo: https://github.com/golangci/golangci-lint
|
- repo: https://github.com/golangci/golangci-lint
|
||||||
rev: v1.51.0
|
rev: v1.51.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: golangci-lint
|
- id: golangci-lint
|
||||||
|
|
|
@ -162,6 +162,10 @@ func (l listPlayersParamsApplier) applyFilters(q *bun.SelectQuery) *bun.SelectQu
|
||||||
q = q.Where("player.server_key IN (?)", bun.In(l.params.ServerKeys))
|
q = q.Where("player.server_key IN (?)", bun.In(l.params.ServerKeys))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if l.params.TribeID > 0 {
|
||||||
|
q = q.Where("player.tribe_id = ?", l.params.TribeID)
|
||||||
|
}
|
||||||
|
|
||||||
if l.params.Deleted.Valid {
|
if l.params.Deleted.Valid {
|
||||||
if l.params.Deleted.Bool {
|
if l.params.Deleted.Bool {
|
||||||
q = q.Where("player.deleted_at IS NOT NULL")
|
q = q.Where("player.deleted_at IS NOT NULL")
|
||||||
|
|
|
@ -212,6 +212,7 @@ func TestPlayer_List_ListCountWithRelations(t *testing.T) {
|
||||||
fixture := loadFixtures(t, db)
|
fixture := loadFixtures(t, db)
|
||||||
repo := bundb.NewPlayer(db)
|
repo := bundb.NewPlayer(db)
|
||||||
players := fixture.players(t)
|
players := fixture.players(t)
|
||||||
|
tribeCSA := fixture.tribe(t, "pl169-csa")
|
||||||
|
|
||||||
type expectedPlayer struct {
|
type expectedPlayer struct {
|
||||||
id int64
|
id int64
|
||||||
|
@ -222,6 +223,7 @@ func TestPlayer_List_ListCountWithRelations(t *testing.T) {
|
||||||
//nolint:prealloc
|
//nolint:prealloc
|
||||||
var playersIT70 []expectedPlayer
|
var playersIT70 []expectedPlayer
|
||||||
var playersPL []expectedPlayer
|
var playersPL []expectedPlayer
|
||||||
|
var playersPL169CSA []expectedPlayer
|
||||||
var playersExceptPL169 []expectedPlayer
|
var playersExceptPL169 []expectedPlayer
|
||||||
for _, p := range players {
|
for _, p := range players {
|
||||||
allPlayers = append(allPlayers, expectedPlayer{
|
allPlayers = append(allPlayers, expectedPlayer{
|
||||||
|
@ -236,6 +238,13 @@ func TestPlayer_List_ListCountWithRelations(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.ServerKey == "pl169" && p.TribeID == tribeCSA.ID {
|
||||||
|
playersPL169CSA = append(playersPL169CSA, expectedPlayer{
|
||||||
|
id: p.ID,
|
||||||
|
serverKey: p.ServerKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if fixture.server(t, p.ServerKey).VersionCode == "pl" {
|
if fixture.server(t, p.ServerKey).VersionCode == "pl" {
|
||||||
playersPL = append(playersPL, expectedPlayer{
|
playersPL = append(playersPL, expectedPlayer{
|
||||||
id: p.ID,
|
id: p.ID,
|
||||||
|
@ -572,6 +581,16 @@ func TestPlayer_List_ListCountWithRelations(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectedCount: 2,
|
expectedCount: 2,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ServerKey=[pl169],TribeID=28,Sort=[{By=ID,Direction=ASC}]",
|
||||||
|
params: domain.ListPlayersParams{
|
||||||
|
ServerKeys: []string{"pl169"},
|
||||||
|
TribeID: tribeCSA.ID,
|
||||||
|
Sort: []domain.PlayerSort{{By: domain.PlayerSortByID, Direction: domain.SortDirectionASC}},
|
||||||
|
},
|
||||||
|
expectedPlayers: playersPL169CSA,
|
||||||
|
expectedCount: int64(len(playersPL169CSA)),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "VersionCodes=[pl],Sort=[{By=ID,Direction=ASC}]",
|
name: "VersionCodes=[pl],Sort=[{By=ID,Direction=ASC}]",
|
||||||
params: domain.ListPlayersParams{
|
params: domain.ListPlayersParams{
|
||||||
|
|
|
@ -137,6 +137,7 @@ type ListPlayersParams struct {
|
||||||
ServerKeysNIN []string
|
ServerKeysNIN []string
|
||||||
VersionCodes []string
|
VersionCodes []string
|
||||||
Deleted NullBool
|
Deleted NullBool
|
||||||
|
TribeID int64
|
||||||
Pagination Pagination
|
Pagination Pagination
|
||||||
Sort []PlayerSort
|
Sort []PlayerSort
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,56 @@ func (p *player) listOtherServers(w http.ResponseWriter, r *http.Request) {
|
||||||
renderJSON(w, http.StatusOK, model.NewListPlayerOtherServersResp(players))
|
renderJSON(w, http.StatusOK, model.NewListPlayerOtherServersResp(players))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ID listTribeMembers
|
||||||
|
// @Summary List tribe members
|
||||||
|
// @Description List all tribe members
|
||||||
|
// @Tags versions,servers,players,tribes
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} model.ListPlayersResp
|
||||||
|
// @Success 400 {object} model.ErrorResp
|
||||||
|
// @Success 404 {object} model.ErrorResp
|
||||||
|
// @Failure 500 {object} model.ErrorResp
|
||||||
|
// @Header 200 {integer} X-Total-Count "Total number of records"
|
||||||
|
// @Param versionCode path string true "Version code"
|
||||||
|
// @Param serverKey path string true "Server key"
|
||||||
|
// @Param tribeId path integer true "Tribe ID"
|
||||||
|
// @Param offset query int false "specifies where to start a page" minimum(0) default(0)
|
||||||
|
// @Param limit query int false "page size" minimum(1) maximum(200) default(200)
|
||||||
|
// @Param sort query []string false "format: field:direction, default: [id:asc]" Enums(id:asc,id:desc,scoreAtt:asc,scoreAtt:desc,scoreDef:asc,scoreDef:desc,scoreSup:asc,scoreSup:desc,scoreTotal:asc,scoreTotal:desc,points:asc,points:desc,deletedAt:asc,deletedAt:desc)
|
||||||
|
// @Router /versions/{versionCode}/servers/{serverKey}/tribes/{tribeId}/members [get]
|
||||||
|
func (p *player) listTribeMembers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var err error
|
||||||
|
ctx := r.Context()
|
||||||
|
srv, _ := serverFromContext(ctx)
|
||||||
|
trb, _ := tribeFromContext(ctx)
|
||||||
|
params := domain.ListPlayersParams{
|
||||||
|
ServerKeys: []string{srv.Key},
|
||||||
|
TribeID: trb.ID,
|
||||||
|
}
|
||||||
|
query := queryParams[domain.PlayerSort]{r.URL.Query()}
|
||||||
|
|
||||||
|
params.Pagination, err = query.pagination(playerDefaultOffset, playerDefaultLimit)
|
||||||
|
if err != nil {
|
||||||
|
renderErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Sort, err = query.sort(domain.NewPlayerSort)
|
||||||
|
if err != nil {
|
||||||
|
renderErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
players, count, err := p.svc.ListCountWithRelations(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
renderErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setTotalCountHeader(w.Header(), count)
|
||||||
|
renderJSON(w, http.StatusOK, model.NewListPlayersResp(players))
|
||||||
|
}
|
||||||
|
|
||||||
func playerMiddleware(svc PlayerService) func(http.Handler) http.Handler {
|
func playerMiddleware(svc PlayerService) func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -905,7 +905,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
setup func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService)
|
setup func(versionSvc *mock.FakeVersionService, serverSvc *mock.FakeServerService, playerSvc *mock.FakePlayerService)
|
||||||
versionCode string
|
versionCode string
|
||||||
serverKey string
|
serverKey string
|
||||||
id string
|
playerID string
|
||||||
queryParams url.Values
|
queryParams url.Values
|
||||||
expectedStatus int
|
expectedStatus int
|
||||||
target any
|
target any
|
||||||
|
@ -1017,7 +1017,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
expectedStatus: http.StatusOK,
|
expectedStatus: http.StatusOK,
|
||||||
target: &model.ListPlayerOtherServersResp{},
|
target: &model.ListPlayerOtherServersResp{},
|
||||||
expectedResponse: &model.ListPlayerOtherServersResp{
|
expectedResponse: &model.ListPlayerOtherServersResp{
|
||||||
|
@ -1161,7 +1161,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
queryParams: url.Values{
|
queryParams: url.Values{
|
||||||
"limit": []string{"1"},
|
"limit": []string{"1"},
|
||||||
"offset": []string{"1"},
|
"offset": []string{"1"},
|
||||||
|
@ -1221,7 +1221,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
queryParams: url.Values{
|
queryParams: url.Values{
|
||||||
"limit": []string{"asd"},
|
"limit": []string{"asd"},
|
||||||
},
|
},
|
||||||
|
@ -1244,7 +1244,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
queryParams: url.Values{
|
queryParams: url.Values{
|
||||||
"offset": []string{"asd"},
|
"offset": []string{"asd"},
|
||||||
},
|
},
|
||||||
|
@ -1265,7 +1265,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code + "2",
|
versionCode: version.Code + "2",
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
expectedStatus: http.StatusNotFound,
|
expectedStatus: http.StatusNotFound,
|
||||||
target: &model.ErrorResp{},
|
target: &model.ErrorResp{},
|
||||||
expectedResponse: &model.ErrorResp{
|
expectedResponse: &model.ErrorResp{
|
||||||
|
@ -1284,7 +1284,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key + "2",
|
serverKey: serverPL151.Key + "2",
|
||||||
id: playerIdStr,
|
playerID: playerIdStr,
|
||||||
expectedStatus: http.StatusNotFound,
|
expectedStatus: http.StatusNotFound,
|
||||||
target: &model.ErrorResp{},
|
target: &model.ErrorResp{},
|
||||||
expectedResponse: &model.ErrorResp{
|
expectedResponse: &model.ErrorResp{
|
||||||
|
@ -1304,7 +1304,7 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
},
|
},
|
||||||
versionCode: version.Code,
|
versionCode: version.Code,
|
||||||
serverKey: serverPL151.Key,
|
serverKey: serverPL151.Key,
|
||||||
id: "12345551",
|
playerID: "12345551",
|
||||||
expectedStatus: http.StatusNotFound,
|
expectedStatus: http.StatusNotFound,
|
||||||
target: &model.ErrorResp{},
|
target: &model.ErrorResp{},
|
||||||
expectedResponse: &model.ErrorResp{
|
expectedResponse: &model.ErrorResp{
|
||||||
|
@ -1337,7 +1337,636 @@ func TestPlayer_listOtherServers(t *testing.T) {
|
||||||
"/v1/versions/%s/servers/%s/players/%s/other-servers?%s",
|
"/v1/versions/%s/servers/%s/players/%s/other-servers?%s",
|
||||||
tt.versionCode,
|
tt.versionCode,
|
||||||
tt.serverKey,
|
tt.serverKey,
|
||||||
tt.id,
|
tt.playerID,
|
||||||
|
tt.queryParams.Encode(),
|
||||||
|
)
|
||||||
|
resp := doRequest(router, http.MethodGet, target, nil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
assertTotalCount(t, resp.Header, tt.expectedTotalCount)
|
||||||
|
assertJSONResponse(t, resp, tt.expectedStatus, tt.expectedResponse, tt.target)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlayer_listTribeMembers(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",
|
||||||
|
}
|
||||||
|
tribe := domain.Tribe{
|
||||||
|
ID: 124,
|
||||||
|
Name: "tribe 124",
|
||||||
|
Tag: "tag 124",
|
||||||
|
ProfileURL: "tribe-124",
|
||||||
|
}
|
||||||
|
tribeID := strconv.FormatInt(tribe.ID, 10)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setup func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
)
|
||||||
|
versionCode string
|
||||||
|
serverKey string
|
||||||
|
tribeID string
|
||||||
|
queryParams url.Values
|
||||||
|
expectedStatus int
|
||||||
|
target any
|
||||||
|
expectedResponse any
|
||||||
|
expectedTotalCount string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK: without params",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
playerSvc.ListCountWithRelationsCalls(func(
|
||||||
|
_ context.Context,
|
||||||
|
params domain.ListPlayersParams,
|
||||||
|
) ([]domain.PlayerWithRelations, int64, error) {
|
||||||
|
expectedParams := domain.ListPlayersParams{
|
||||||
|
ServerKeys: []string{server.Key},
|
||||||
|
TribeID: tribe.ID,
|
||||||
|
Pagination: domain.Pagination{
|
||||||
|
Limit: 200,
|
||||||
|
Offset: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(params, expectedParams); diff != "" {
|
||||||
|
return nil, 0, fmt.Errorf("validation failed: %s", diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
players := []domain.PlayerWithRelations{
|
||||||
|
{
|
||||||
|
Player: domain.Player{
|
||||||
|
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: tribe.ID,
|
||||||
|
ProfileURL: "profile-997",
|
||||||
|
BestRank: 111,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1112,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Minute),
|
||||||
|
MostVillages: 1113,
|
||||||
|
MostVillagesAt: now.Add(time.Minute),
|
||||||
|
LastActivityAt: now.Add(time.Second),
|
||||||
|
ServerKey: server.Key,
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
Tribe: domain.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: domain.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Player: domain.Player{
|
||||||
|
OpponentsDefeated: domain.OpponentsDefeated{
|
||||||
|
RankAtt: 1,
|
||||||
|
ScoreAtt: 2,
|
||||||
|
RankDef: 3,
|
||||||
|
ScoreDef: 4,
|
||||||
|
RankSup: 5,
|
||||||
|
ScoreSup: 6,
|
||||||
|
RankTotal: 7,
|
||||||
|
ScoreTotal: 8,
|
||||||
|
},
|
||||||
|
ID: 998,
|
||||||
|
Name: "name 998",
|
||||||
|
NumVillages: 2,
|
||||||
|
Points: 3,
|
||||||
|
Rank: 4,
|
||||||
|
TribeID: tribe.ID,
|
||||||
|
ProfileURL: "profile-998",
|
||||||
|
BestRank: 1117,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1115,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Second),
|
||||||
|
MostVillages: 1114,
|
||||||
|
MostVillagesAt: now.Add(time.Hour),
|
||||||
|
LastActivityAt: now.Add(time.Minute),
|
||||||
|
ServerKey: server.Key,
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
Tribe: domain.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: domain.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return players, int64(len(players)), nil
|
||||||
|
})
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
target: &model.ListPlayersResp{},
|
||||||
|
expectedResponse: &model.ListPlayersResp{
|
||||||
|
Data: []model.Player{
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
ProfileURL: "profile-997",
|
||||||
|
BestRank: 111,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1112,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Minute),
|
||||||
|
MostVillages: 1113,
|
||||||
|
MostVillagesAt: now.Add(time.Minute),
|
||||||
|
LastActivityAt: now.Add(time.Second),
|
||||||
|
Tribe: model.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: model.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RankAtt: 1,
|
||||||
|
ScoreAtt: 2,
|
||||||
|
RankDef: 3,
|
||||||
|
ScoreDef: 4,
|
||||||
|
RankSup: 5,
|
||||||
|
ScoreSup: 6,
|
||||||
|
RankTotal: 7,
|
||||||
|
ScoreTotal: 8,
|
||||||
|
ID: 998,
|
||||||
|
Name: "name 998",
|
||||||
|
NumVillages: 2,
|
||||||
|
Points: 3,
|
||||||
|
Rank: 4,
|
||||||
|
ProfileURL: "profile-998",
|
||||||
|
BestRank: 1117,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1115,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Second),
|
||||||
|
MostVillages: 1114,
|
||||||
|
MostVillagesAt: now.Add(time.Hour),
|
||||||
|
LastActivityAt: now.Add(time.Minute),
|
||||||
|
Tribe: model.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: model.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: limit=1,sort=[id:asc,points:desc,scoreTotal:asc]",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
playerSvc.ListCountWithRelationsCalls(func(
|
||||||
|
_ context.Context,
|
||||||
|
params domain.ListPlayersParams,
|
||||||
|
) ([]domain.PlayerWithRelations, int64, error) {
|
||||||
|
expectedParams := domain.ListPlayersParams{
|
||||||
|
ServerKeys: []string{server.Key},
|
||||||
|
Pagination: domain.Pagination{
|
||||||
|
Limit: 1,
|
||||||
|
Offset: 0,
|
||||||
|
},
|
||||||
|
TribeID: tribe.ID,
|
||||||
|
Sort: []domain.PlayerSort{
|
||||||
|
{By: domain.PlayerSortByID, Direction: domain.SortDirectionASC},
|
||||||
|
{By: domain.PlayerSortByPoints, Direction: domain.SortDirectionDESC},
|
||||||
|
{By: domain.PlayerSortByScoreTotal, Direction: domain.SortDirectionASC},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(params, expectedParams); diff != "" {
|
||||||
|
return nil, 0, fmt.Errorf("validation failed: %s", diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
players := []domain.PlayerWithRelations{
|
||||||
|
{
|
||||||
|
Player: domain.Player{
|
||||||
|
OpponentsDefeated: domain.OpponentsDefeated{
|
||||||
|
RankAtt: 1,
|
||||||
|
ScoreAtt: 2,
|
||||||
|
RankDef: 3,
|
||||||
|
ScoreDef: 4,
|
||||||
|
RankSup: 5,
|
||||||
|
ScoreSup: 6,
|
||||||
|
RankTotal: 7,
|
||||||
|
ScoreTotal: 8,
|
||||||
|
},
|
||||||
|
ID: 998,
|
||||||
|
Name: "name 998",
|
||||||
|
NumVillages: 2,
|
||||||
|
Points: 3,
|
||||||
|
Rank: 4,
|
||||||
|
TribeID: 0,
|
||||||
|
ProfileURL: "profile-998",
|
||||||
|
BestRank: 1117,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1115,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Second),
|
||||||
|
MostVillages: 1114,
|
||||||
|
MostVillagesAt: now.Add(time.Hour),
|
||||||
|
LastActivityAt: now.Add(time.Minute),
|
||||||
|
ServerKey: server.Key,
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
Tribe: domain.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: domain.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return players, int64(len(players)) + 49, nil
|
||||||
|
})
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"limit": []string{"1"},
|
||||||
|
"sort": []string{"id:asc", "points:desc", "scoreTotal:asc"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
target: &model.ListPlayersResp{},
|
||||||
|
expectedResponse: &model.ListPlayersResp{
|
||||||
|
Data: []model.Player{
|
||||||
|
{
|
||||||
|
RankAtt: 1,
|
||||||
|
ScoreAtt: 2,
|
||||||
|
RankDef: 3,
|
||||||
|
ScoreDef: 4,
|
||||||
|
RankSup: 5,
|
||||||
|
ScoreSup: 6,
|
||||||
|
RankTotal: 7,
|
||||||
|
ScoreTotal: 8,
|
||||||
|
ID: 998,
|
||||||
|
Name: "name 998",
|
||||||
|
NumVillages: 2,
|
||||||
|
Points: 3,
|
||||||
|
Rank: 4,
|
||||||
|
ProfileURL: "profile-998",
|
||||||
|
BestRank: 1117,
|
||||||
|
BestRankAt: now,
|
||||||
|
MostPoints: 1115,
|
||||||
|
MostPointsAt: now.Add(-5 * time.Second),
|
||||||
|
MostVillages: 1114,
|
||||||
|
MostVillagesAt: now.Add(time.Hour),
|
||||||
|
LastActivityAt: now.Add(time.Minute),
|
||||||
|
Tribe: model.NullTribeMeta{
|
||||||
|
Valid: true,
|
||||||
|
Tribe: model.TribeMeta{
|
||||||
|
ID: tribe.ID,
|
||||||
|
Name: tribe.Name,
|
||||||
|
Tag: tribe.Tag,
|
||||||
|
ProfileURL: tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreatedAt: now,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: limit is not a valid int32",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"limit": []string{"asd"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "limit: strconv.ParseInt: parsing \"asd\": invalid syntax",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: offset is not a valid int32",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"offset": []string{"asd"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "offset: strconv.ParseInt: parsing \"asd\": invalid syntax",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: sort - invalid format",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"sort": []string{"id:asc", "test"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "sort[1]: parsing \"test\": invalid syntax, expected field:direction",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: sort - unsupported field",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"sort": []string{"id:asc", "test:asc"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "sort[1]: unsupported sort by: \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: sort - unsupported direction",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDReturns(tribe, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
queryParams: url.Values{
|
||||||
|
"sort": []string{"id:asc2"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "sort[0]: unsupported sort direction: \"asc2\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: tribe id is not a valid int64",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(server, nil)
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: "asdf",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeValidationError.String(),
|
||||||
|
Message: "tribeId: strconv.ParseInt: parsing \"asdf\": invalid syntax",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: version not found",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(domain.Version{}, domain.VersionNotFoundError{VerCode: version.Code + "2"})
|
||||||
|
},
|
||||||
|
versionCode: version.Code + "2",
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID,
|
||||||
|
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"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: server not found",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(domain.Server{}, domain.ServerNotFoundError{Key: server.Key + "2"})
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key + "2",
|
||||||
|
tribeID: tribeID,
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||||
|
Message: fmt.Sprintf("server (key=%s) not found", server.Key+"2"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: tribe not found",
|
||||||
|
setup: func(
|
||||||
|
versionSvc *mock.FakeVersionService,
|
||||||
|
serverSvc *mock.FakeServerService,
|
||||||
|
tribeSvc *mock.FakeTribeService,
|
||||||
|
playerSvc *mock.FakePlayerService,
|
||||||
|
) {
|
||||||
|
versionSvc.GetByCodeReturns(version, nil)
|
||||||
|
serverSvc.GetNormalByVersionCodeAndKeyReturns(domain.Server{}, nil)
|
||||||
|
tribeSvc.GetByServerKeyAndIDCalls(func(_ context.Context, _ string, id int64) (domain.Tribe, error) {
|
||||||
|
return domain.Tribe{}, domain.TribeNotFoundError{ID: id}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
versionCode: version.Code,
|
||||||
|
serverKey: server.Key,
|
||||||
|
tribeID: tribeID + "2",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
target: &model.ErrorResp{},
|
||||||
|
expectedResponse: &model.ErrorResp{
|
||||||
|
Error: model.APIError{
|
||||||
|
Code: domain.ErrorCodeEntityNotFound.String(),
|
||||||
|
Message: fmt.Sprintf("tribe (id=%s) not found", tribeID+"2"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedTotalCount: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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{}
|
||||||
|
tribeSvc := &mock.FakeTribeService{}
|
||||||
|
tt.setup(versionSvc, serverSvc, tribeSvc, playerSvc)
|
||||||
|
|
||||||
|
router := newRouter(
|
||||||
|
withVersionService(versionSvc),
|
||||||
|
withPlayerService(playerSvc),
|
||||||
|
withServerService(serverSvc),
|
||||||
|
withTribeService(tribeSvc),
|
||||||
|
)
|
||||||
|
|
||||||
|
target := fmt.Sprintf(
|
||||||
|
"/v1/versions/%s/servers/%s/tribes/%s/members?%s",
|
||||||
|
tt.versionCode,
|
||||||
|
tt.serverKey,
|
||||||
|
tt.tribeID,
|
||||||
tt.queryParams.Encode(),
|
tt.queryParams.Encode(),
|
||||||
)
|
)
|
||||||
resp := doRequest(router, http.MethodGet, target, nil)
|
resp := doRequest(router, http.MethodGet, target, nil)
|
||||||
|
|
|
@ -100,6 +100,7 @@ func New(
|
||||||
r.Get("/", tribeHandler.list)
|
r.Get("/", tribeHandler.list)
|
||||||
r.With(tribeMiddleware(tribeSvc)).Route("/{tribeId}", func(r chi.Router) {
|
r.With(tribeMiddleware(tribeSvc)).Route("/{tribeId}", func(r chi.Router) {
|
||||||
r.Get("/", tribeHandler.getByID)
|
r.Get("/", tribeHandler.getByID)
|
||||||
|
r.Get("/members", playerHandler.listTribeMembers)
|
||||||
r.Get("/ennoblements", ennoblementHandler.listTribe)
|
r.Get("/ennoblements", ennoblementHandler.listTribe)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Reference in New Issue
Block a user