Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning pending applications and invites in retrieveClan route #46

Merged
merged 6 commits into from
Aug 22, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 applications 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.MostRecentFirst, models.OldestFirst), c)
}
options.PendingApplicationsOrder = pendingApplicationsOrder
}
if pendingInvitesOrder != "" {
if !models.IsValidOrder(pendingInvitesOrder) {
return FailWith(400, fmt.Sprintf("Pending applications order is invalid (valid orders are %s or %s).", models.MostRecentFirst, models.OldestFirst), 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"`
}

// MostRecentFirst is the constant "mostRecentFirst"
const MostRecentFirst string = "mostRecentFirst"
matheuscscp marked this conversation as resolved.
Show resolved Hide resolved

// OldestFirst is the constant "oldestFirst"
const OldestFirst string = "oldestFirst"

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

func getSQLOrderFromSemanticOrder(semantic string) (sql string) {
if semantic == MostRecentFirst {
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, MostRecentFirst)
config.SetDefault(pendingInvitesOrderKey, MostRecentFirst)
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 {
matheuscscp marked this conversation as resolved.
Show resolved Hide resolved
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