Skip to content

Commit

Permalink
Fix reputation leaderboards
Browse files Browse the repository at this point in the history
Closes #135
  • Loading branch information
jogramming committed Feb 4, 2018
1 parent 31323b7 commit 3aa0795
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 42 deletions.
9 changes: 9 additions & 0 deletions bot/botrest/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/jonas747/discordgo"
"log"
"net/http"
"net/url"
"sync"
"time"
)
Expand Down Expand Up @@ -43,6 +44,14 @@ func GetBotMember(guildID string) (m *discordgo.Member, err error) {
return
}

func GetMembers(guildID string, members ...string) (m []*discordgo.Member, err error) {
query := url.Values{"users": members}
encoded := query.Encode()

err = get(guildID+"/botmember?"+encoded, &m)
return
}

func GetChannelPermissions(guildID, channelID string) (perms int64, err error) {
err = get(guildID+"/channelperms/"+channelID, &perms)
return
Expand Down
24 changes: 24 additions & 0 deletions bot/botrest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,30 @@ func HandleBotMember(w http.ResponseWriter, r *http.Request) {
ServeJson(w, r, member)
}

func HandleGetMembers(w http.ResponseWriter, r *http.Request) {
gId := pat.Param(r, "guild")
uIDs, ok := r.URL.Query()["users"]
if !ok || len(uIDs) < 1 {
ServerError(w, r, errors.New("No id's provided"))
return
}

if len(uIDs) > 100 {
ServerError(w, r, errors.New("Too many ids provided"))
return
}

guild := bot.State.Guild(true, gId)
if guild == nil {
ServerError(w, r, errors.New("Guild not found"))
return
}

members, _ := GetMembers(gId, uIDs...)

ServeJson(w, r, members)
}

func HandleChannelPermissions(w http.ResponseWriter, r *http.Request) {
gId := pat.Param(r, "guild")
cId := pat.Param(r, "channel")
Expand Down
20 changes: 20 additions & 0 deletions bot/memberfetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ func GetMember(guildID, userID string) (*discordgo.Member, error) {
return result.Member, result.Err
}

func GetMembers(guildID string, userIDs ...string) ([]*discordgo.Member, error) {
resultChan := make(chan *discordgo.Member)
for _, v := range userIDs {
go func(id string) {
m, _ := GetMember(guildID, v)
resultChan <- m
}(v)
}

result := make([]*discordgo.Member, 0, len(userIDs))
for i := 0; i < len(userIDs); i++ {
m := <-resultChan
if m != nil {
result = append(result, m)
}
}

return result, nil
}

// memberFetcher handles a per guild queue for fetching members
// This is probably overkill as the root cause for the flood of member requests (state being flushed upon guilds becoming unavailble) was fixed
// But it's here, for better or for worse
Expand Down
2 changes: 1 addition & 1 deletion reputation/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ var cmds = []*commands.YAGCommand{
return "Something went wrong... i may hae had one too many alcohol", err
}

detailed, err := DetailedLeaderboardEntries(entries)
detailed, err := DetailedLeaderboardEntries(parsed.GS.ID(), entries)
if err != nil {
return "Failed filling in the detalis of the leaderboard entries", err
}
Expand Down
2 changes: 1 addition & 1 deletion reputation/plugin_web.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func HandleLeaderboardJson(w http.ResponseWriter, r *http.Request) interface{} {
return err
}

entries, err := DetailedLeaderboardEntries(top)
entries, err := DetailedLeaderboardEntries(activeGuild.ID, top)
if err != nil {
return err
}
Expand Down
123 changes: 83 additions & 40 deletions reputation/reputation.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/Sirupsen/logrus"
"github.com/jonas747/discordgo"
"github.com/jonas747/dutil/dstate"
"github.com/jonas747/yagpdb/bot"
"github.com/jonas747/yagpdb/bot/botrest"
"github.com/jonas747/yagpdb/common"
"github.com/jonas747/yagpdb/reputation/models"
"github.com/mediocregopher/radix.v2/redis"
Expand Down Expand Up @@ -313,57 +315,98 @@ type LeaderboardEntry struct {
Avatar string `json:"avatar"`
}

func DetailedLeaderboardEntries(ranks []*RankEntry) ([]*LeaderboardEntry, error) {
if len(ranks) < 1 {
return []*LeaderboardEntry{}, nil
}

query := "SELECT id,username,bot,avatar FROM d_users WHERE id in ("
args := make([]interface{}, len(ranks))

for i, v := range ranks {
if i != 0 {
query += ","
}
func DetailedLeaderboardEntries(guildID string, ranks []*RankEntry) ([]*LeaderboardEntry, error) {
var members []*discordgo.Member
var err error

args[i] = v.UserID
query += "$" + strconv.Itoa(i+1)
compiledIDs := make([]string, len(ranks))
for i := 0; i < len(ranks); i++ {
compiledIDs[i] = strconv.FormatInt(ranks[i].UserID, 10)
}
query += ")"

result := make([]*LeaderboardEntry, len(ranks))
for i, v := range ranks {
result[i] = &LeaderboardEntry{
RankEntry: v,
}
if bot.Running {
members, err = bot.GetMembers(guildID, compiledIDs...)
} else {
members, err = botrest.GetMembers(guildID, compiledIDs...)
}

rows, err := common.DSQLStateDB.Query(query, args...)
if err != nil {
return nil, errors.WithMessage(err, "ToLeaderboardEntries")
return nil, err
}
defer rows.Close()
for rows.Next() {
var id int64
var entry LeaderboardEntry
err = rows.Scan(&id, &entry.Username, &entry.Bot, &entry.Avatar)
if err != nil {
logrus.WithError(err).Error("Failed scanning row")
continue

var resultEntries = make([]*LeaderboardEntry, len(ranks))
for i := 0; i < len(ranks); i++ {
lEntry := &LeaderboardEntry{
RankEntry: ranks[i],
Username: compiledIDs[i],
}

for i, v := range result {
if v.UserID == id {
entry.RankEntry = v.RankEntry
result[i] = &entry
if entry.Avatar != "" {
result[i].Avatar = discordgo.EndpointUserAvatar(strconv.FormatInt(id, 10), entry.Avatar)
} else {
result[i].Avatar = "/static/dist/img/unknown-user.png"
}
for _, m := range members {
if m.User.ID == compiledIDs[i] {
lEntry.Username = m.User.Username + m.User.Discriminator
lEntry.Avatar = m.User.Avatar
lEntry.Bot = m.User.Bot
break
}
}

resultEntries[i] = lEntry
}

return result, nil
return resultEntries, nil
}

// func DetailedLeaderboardEntries(ranks []*RankEntry) ([]*LeaderboardEntry, error) {
// if len(ranks) < 1 {
// return []*LeaderboardEntry{}, nil
// }

// query := "SELECT id,username,bot,avatar FROM d_users WHERE id in ("
// args := make([]interface{}, len(ranks))

// for i, v := range ranks {
// if i != 0 {
// query += ","
// }

// args[i] = v.UserID
// query += "$" + strconv.Itoa(i+1)
// }
// query += ")"

// result := make([]*LeaderboardEntry, len(ranks))
// for i, v := range ranks {
// result[i] = &LeaderboardEntry{
// RankEntry: v,
// }
// }

// rows, err := common.DSQLStateDB.Query(query, args...)
// if err != nil {
// return nil, errors.WithMessage(err, "ToLeaderboardEntries")
// }
// defer rows.Close()
// for rows.Next() {
// var id int64
// var entry LeaderboardEntry
// err = rows.Scan(&id, &entry.Username, &entry.Bot, &entry.Avatar)
// if err != nil {
// logrus.WithError(err).Error("Failed scanning row")
// continue
// }

// for i, v := range result {
// if v.UserID == id {
// entry.RankEntry = v.RankEntry
// result[i] = &entry
// if entry.Avatar != "" {
// result[i].Avatar = discordgo.EndpointUserAvatar(strconv.FormatInt(id, 10), entry.Avatar)
// } else {
// result[i].Avatar = "/static/dist/img/unknown-user.png"
// }
// }
// }
// }

// return result, nil
// }

0 comments on commit 3aa0795

Please sign in to comment.