Skip to content

Commit

Permalink
Returning pending applications and invites in retrieveClan route (#46)
Browse files Browse the repository at this point in the history
* Removing unused struct

* Returning pending applications and invites in retrieveClan route

* Fixing bug on query

* Returning bad request if route inputs are invalid

* Fixing tests

* Changing order strings
  • Loading branch information
matheuscscp authored and cscatolini committed Aug 22, 2019
1 parent 947d3cf commit 52fde2b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 26 deletions.
41 changes: 41 additions & 0 deletions api/clan.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
package api

import (
"fmt"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -747,6 +749,44 @@ func RetrieveClanHandler(app *App) func(c echo.Context) error {
gameID := c.Param("gameID")
publicID := c.Param("clanPublicID")
shortID := c.QueryParam("shortID")
maxPendingApplications := c.QueryParam("maxPendingApplications")
maxPendingInvites := c.QueryParam("maxPendingInvites")
pendingApplicationsOrder := c.QueryParam("pendingApplicationsOrder")
pendingInvitesOrder := c.QueryParam("pendingInvitesOrder")

options := models.NewDefaultGetClanDetailsOptions(app.Config)
if maxPendingApplications != "" {
maxApps, err := strconv.ParseUint(maxPendingApplications, 10, 16)
if err != nil {
return FailWith(400, err.Error(), c)
}
if int(maxApps) > options.MaxPendingApplications {
return FailWith(400, fmt.Sprintf("Maximum pending applications above allowed (%v).", options.MaxPendingApplications), c)
}
options.MaxPendingApplications = int(maxApps)
}
if maxPendingInvites != "" {
maxInvs, err := strconv.ParseUint(maxPendingInvites, 10, 16)
if err != nil {
return FailWith(400, err.Error(), c)
}
if int(maxInvs) > options.MaxPendingInvites {
return FailWith(400, fmt.Sprintf("Maximum pending invites above allowed (%v).", options.MaxPendingInvites), c)
}
options.MaxPendingInvites = int(maxInvs)
}
if pendingApplicationsOrder != "" {
if !models.IsValidOrder(pendingApplicationsOrder) {
return FailWith(400, fmt.Sprintf("Pending applications order is invalid (valid orders are %s or %s).", models.Newest, models.Oldest), c)
}
options.PendingApplicationsOrder = pendingApplicationsOrder
}
if pendingInvitesOrder != "" {
if !models.IsValidOrder(pendingInvitesOrder) {
return FailWith(400, fmt.Sprintf("Pending invites order is invalid (valid orders are %s or %s).", models.Newest, models.Oldest), c)
}
options.PendingInvitesOrder = pendingInvitesOrder
}

db := app.Db(c.StdContext())

Expand Down Expand Up @@ -805,6 +845,7 @@ func RetrieveClanHandler(app *App) func(c echo.Context) error {
gameID,
clan,
game.MaxClansPerPlayer,
options,
)

if err != nil {
Expand Down
89 changes: 72 additions & 17 deletions models/clan.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"os"
"strings"

"github.com/spf13/viper"

"github.com/globalsign/mgo/bson"
"github.com/go-gorp/gorp"
workers "github.com/jrallison/go-workers"
Expand Down Expand Up @@ -53,6 +55,52 @@ type Clan struct {
DeletedAt int64 `db:"deleted_at" json:"deletedAt" bson:"deletedAt"`
}

// Newest is the constant "newest"
const Newest string = "newest"

// Oldest is the constant "oldest"
const Oldest string = "oldest"

// IsValidOrder returns whether the input is equal to Newest or Oldest
func IsValidOrder(order string) bool {
return order == Newest || order == Oldest
}

func getSQLOrderFromSemanticOrder(semantic string) (sql string) {
if semantic == Newest {
sql = "DESC"
} else {
sql = "ASC"
}
return
}

// GetClanDetailsOptions holds options to change the output of GetClanDetails()
type GetClanDetailsOptions struct {
MaxPendingApplications int
MaxPendingInvites int
PendingApplicationsOrder string
PendingInvitesOrder string
}

// NewDefaultGetClanDetailsOptions returns a new options structure with default values for GetClanDetails()
func NewDefaultGetClanDetailsOptions(config *viper.Viper) *GetClanDetailsOptions {
maxPendingApplicationsKey := "getClanDetails.defaultOptions.maxPendingApplications"
maxPendingInvitesKey := "getClanDetails.defaultOptions.maxPendingInvites"
pendingApplicationsOrderKey := "getClanDetails.defaultOptions.pendingApplicationsOrder"
pendingInvitesOrderKey := "getClanDetails.defaultOptions.pendingInvitesOrder"
config.SetDefault(maxPendingApplicationsKey, 100)
config.SetDefault(maxPendingInvitesKey, 100)
config.SetDefault(pendingApplicationsOrderKey, Newest)
config.SetDefault(pendingInvitesOrderKey, Newest)
return &GetClanDetailsOptions{
MaxPendingApplications: config.GetInt(maxPendingApplicationsKey),
MaxPendingInvites: config.GetInt(maxPendingInvitesKey),
PendingApplicationsOrder: config.GetString(pendingApplicationsOrderKey),
PendingInvitesOrder: config.GetString(pendingInvitesOrderKey),
}
}

//ToJSON returns the clan as JSON
func (c *Clan) ToJSON() ([]byte, error) {
w := jwriter.Writer{}
Expand Down Expand Up @@ -688,8 +736,8 @@ func GetClanMembers(db DB, gameID, publicID string) (map[string]interface{}, err
}

// GetClanDetails returns all details for a given clan by its game id and public id
func GetClanDetails(db DB, gameID string, clan *Clan, maxClansPerPlayer int) (map[string]interface{}, error) {
query := `
func GetClanDetails(db DB, gameID string, clan *Clan, maxClansPerPlayer int, options *GetClanDetailsOptions) (map[string]interface{}, error) {
query := fmt.Sprintf(`
SELECT
c.game_id GameID,
c.public_id ClanPublicID, c.name ClanName, c.metadata ClanMetadata,
Expand All @@ -709,19 +757,36 @@ func GetClanDetails(db DB, gameID string, clan *Clan, maxClansPerPlayer int) (ma
FROM clans c
INNER JOIN players o ON c.owner_id=o.id
LEFT OUTER JOIN (
SELECT *
FROM memberships im
WHERE im.clan_id=$2 AND im.deleted_at=0 AND (im.approved=true OR im.denied=true OR im.banned=true)
(
SELECT *
FROM memberships im
WHERE im.clan_id=$2 AND im.deleted_at=0 AND im.approved=false AND im.denied=false AND im.banned=false AND im.requestor_id=im.player_id
ORDER BY im.id %s
LIMIT $3
)
UNION ALL (
SELECT *
FROM memberships im
WHERE im.clan_id=$2 AND im.deleted_at=0 AND im.approved=false AND im.denied=false AND im.banned=false AND im.requestor_id<>im.player_id
ORDER BY im.id %s
LIMIT $4
)
UNION ALL (
SELECT *
FROM memberships im
WHERE im.clan_id=$2 AND im.deleted_at=0 AND (im.approved=true OR im.denied=true OR im.banned=true)
)
) m ON m.clan_id=c.id
LEFT OUTER JOIN players r ON m.requestor_id=r.id
LEFT OUTER JOIN players a ON m.approver_id=a.id
LEFT OUTER JOIN players p ON m.player_id=p.id
LEFT OUTER JOIN players y ON m.denier_id=y.id
WHERE
c.game_id=$1 AND c.id=$2
`
`, getSQLOrderFromSemanticOrder(options.PendingApplicationsOrder), getSQLOrderFromSemanticOrder(options.PendingInvitesOrder))

var details []clanDetailsDAO
_, err := db.Select(&details, query, gameID, clan.ID)
_, err := db.Select(&details, query, gameID, clan.ID, options.MaxPendingApplications, options.MaxPendingInvites)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -840,16 +905,6 @@ func GetClansSummaries(db DB, gameID string, publicIDs []string) ([]map[string]i
return resultClans, nil
}

type mongoResult struct {
OK int `bson:"ok"`
WaitedMS int `bson:"waitedMS"`
Cursor struct {
ID interface{} `bson:"id"`
NS string `bson:"ns"`
FirstBatch []bson.Raw `bson:"firstBatch"`
} `bson:"cursor"`
}

func min(x, y int) int {
if x < y {
return x
Expand Down
18 changes: 9 additions & 9 deletions models/clan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
uuid "github.com/satori/go.uuid"
"github.com/spf13/viper"
"github.com/topfreegames/extensions/mongo/interfaces"
. "github.com/topfreegames/khan/models"
"github.com/topfreegames/khan/testing"
Expand Down Expand Up @@ -750,7 +751,7 @@ var _ = Describe("Clan Model", func() {
_, clan, _, _, _, err := GetClanWithMemberships(
testDb, 10, 3, 4, 5, gameID, uuid.NewV4().String(),
)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(err).NotTo(HaveOccurred())

clanPlayers, err := GetClanMembers(testDb, clan.GameID, clan.PublicID)
Expand All @@ -769,7 +770,7 @@ var _ = Describe("Clan Model", func() {
_, clan, _, _, _, err := GetClanWithMemberships(
testDb, 0, 3, 4, 5, gameID, uuid.NewV4().String(),
)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(err).NotTo(HaveOccurred())

clanPlayers, err := GetClanMembers(testDb, clan.GameID, clan.PublicID)
Expand All @@ -788,7 +789,7 @@ var _ = Describe("Clan Model", func() {
)
Expect(err).NotTo(HaveOccurred())

clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(err).NotTo(HaveOccurred())
Expect(clanData["name"]).To(Equal(clan.Name))
Expect(clanData["metadata"]).To(Equal(clan.Metadata))
Expand All @@ -801,9 +802,8 @@ var _ = Describe("Clan Model", func() {
pendingApplications := clanData["memberships"].(map[string]interface{})["pendingApplications"].([]map[string]interface{})
Expect(len(pendingApplications)).To(Equal(0))

//We do not return pending invites or applications anymore
pendingInvites := clanData["memberships"].(map[string]interface{})["pendingInvites"].([]map[string]interface{})
Expect(len(pendingInvites)).To(Equal(0))
Expect(len(pendingInvites)).To(Equal(5))

banned := clanData["memberships"].(map[string]interface{})["banned"].([]map[string]interface{})
Expect(len(banned)).To(Equal(4))
Expand Down Expand Up @@ -893,7 +893,7 @@ var _ = Describe("Clan Model", func() {
_, err = testDb.Update(memberships[9])
Expect(err).NotTo(HaveOccurred())

clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(err).NotTo(HaveOccurred())
Expect(clanData["name"]).To(Equal(clan.Name))
Expect(clanData["metadata"]).To(Equal(clan.Metadata))
Expand Down Expand Up @@ -925,7 +925,7 @@ var _ = Describe("Clan Model", func() {
_, err = testDb.Update(clan)
Expect(err).NotTo(HaveOccurred())

clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1)
clanData, err := GetClanDetails(testDb, clan.GameID, clan, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(err).NotTo(HaveOccurred())
Expect(clanData["name"]).To(Equal(clan.Name))
Expect(clanData["metadata"]).To(Equal(clan.Metadata))
Expand All @@ -937,7 +937,7 @@ var _ = Describe("Clan Model", func() {
})

It("Should fail if clan does not exist", func() {
clanData, err := GetClanDetails(testDb, "fake-game-id", &Clan{PublicID: "fake-public-id"}, 1)
clanData, err := GetClanDetails(testDb, "fake-game-id", &Clan{PublicID: "fake-public-id"}, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(clanData).To(BeNil())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Clan was not found with id: fake-public-id"))
Expand All @@ -964,7 +964,7 @@ var _ = Describe("Clan Model", func() {
})

It("Should fail if clan does not exist", func() {
clanData, err := GetClanDetails(testDb, "fake-game-id", &Clan{PublicID: "fake-public-id"}, 1)
clanData, err := GetClanDetails(testDb, "fake-game-id", &Clan{PublicID: "fake-public-id"}, 1, NewDefaultGetClanDetailsOptions(viper.New()))
Expect(clanData).To(BeNil())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Clan was not found with id: fake-public-id"))
Expand Down

0 comments on commit 52fde2b

Please sign in to comment.