aboutsummaryrefslogtreecommitdiff
path: root/user/xp.go
diff options
context:
space:
mode:
Diffstat (limited to 'user/xp.go')
-rw-r--r--user/xp.go137
1 files changed, 137 insertions, 0 deletions
diff --git a/user/xp.go b/user/xp.go
new file mode 100644
index 0000000..71a1ced
--- /dev/null
+++ b/user/xp.go
@@ -0,0 +1,137 @@
+package user
+
+import (
+ "github.com/anhgelus/gokord"
+ "github.com/anhgelus/gokord/utils"
+ "github.com/anhgelus/les-copaings-bot/config"
+ "github.com/anhgelus/les-copaings-bot/exp"
+ "github.com/bwmarrin/discordgo"
+ "slices"
+ "sync"
+)
+
+type cXP struct {
+ Cxp uint
+ *Copaing
+}
+
+func (c *cXP) ToCopaing() *Copaing {
+ return c.Copaing
+}
+
+func (c *cXP) GetXP() uint {
+ return c.Cxp
+}
+
+func (c *Copaing) AddXP(s *discordgo.Session, m *discordgo.Member, xp uint, fn func(uint, uint)) {
+ old, err := c.GetXP()
+ if err != nil {
+ utils.SendAlert("user/xp.go - Getting xp", err.Error(), "discord_id", c.DiscordID, "guild_id", c.GuildID)
+ return
+ }
+ pastLevel := exp.Level(old)
+ utils.SendDebug("Adding xp", "member", m.DisplayName(), "old xp", old, "xp to add", xp, "old level", pastLevel)
+ c.CopaingXPs = append(c.CopaingXPs, CopaingXP{CopaingID: c.ID, XP: xp, GuildID: c.GuildID})
+ if err = c.Save(); err != nil {
+ utils.SendAlert(
+ "user/xp.go - Saving user",
+ err.Error(),
+ "xp",
+ c.CopaingXPs,
+ "discord_id",
+ c.DiscordID,
+ "guild_id",
+ c.GuildID,
+ )
+ return
+ }
+ newLevel := exp.Level(old + xp)
+ if newLevel > pastLevel {
+ fn(old+xp, newLevel)
+ onNewLevel(s, m, newLevel)
+ }
+}
+
+func (c *Copaing) GetXP() (uint, error) {
+ cfg := config.GetGuildConfig(c.GuildID)
+ return c.GetXPForDays(cfg.DaysXPRemains)
+}
+
+func (c *Copaing) GetXPForDays(n uint) (uint, error) {
+ xp := uint(0)
+ rows, err := gokord.DB.
+ Model(&CopaingXP{}).
+ Where(
+ "created_at >= ? and guild_id = ? and copaing_id = ?",
+ exp.TimeStampNDaysBefore(n),
+ c.GuildID,
+ c.ID,
+ ).
+ Rows()
+ defer rows.Close()
+ if err != nil {
+ return 0, err
+ }
+ for rows.Next() {
+ var cxp CopaingXP
+ err = gokord.DB.ScanRows(rows, &cxp)
+ if err != nil {
+ utils.SendAlert("user/xp.go - Scanning rows", err.Error(), "copaing_id", c.ID, "guild_id", c.GuildID)
+ continue
+ }
+ xp += cxp.XP
+ }
+ return xp, nil
+}
+
+// GetBestXP returns n Copaing with the best XP within d days (d <= cfg.DaysXPRemain; d < 0 <=> d = cfg.DaysXPRemain)
+//
+// This function is slow
+func GetBestXP(guildId string, n uint, d int) ([]CopaingAccess, error) {
+ if d < 0 {
+ cfg := config.GetGuildConfig(guildId)
+ d = int(cfg.DaysXPRemains)
+ }
+ rows, err := gokord.DB.Model(&Copaing{}).Where("guild_id = ?", guildId).Rows()
+ defer rows.Close()
+ if err != nil {
+ return nil, err
+ }
+ var l []*cXP
+ wg := sync.WaitGroup{}
+ for rows.Next() {
+ var c Copaing
+ err = gokord.DB.ScanRows(rows, &c)
+ if err != nil {
+ utils.SendAlert("user/xp.go - Scanning rows", err.Error(), "guild_id", guildId)
+ continue
+ }
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ xp, err := c.GetXPForDays(uint(d))
+ if err != nil {
+ utils.SendAlert("user/xp.go - Fetching xp", err.Error(), "discord_id", c.DiscordID, "guild_id", guildId)
+ return
+ }
+ l = append(l, &cXP{Cxp: xp, Copaing: &c})
+ }()
+ }
+ wg.Wait()
+ slices.SortFunc(l, func(a, b *cXP) int {
+ // desc order
+ if a.Cxp < b.Cxp {
+ return 1
+ }
+ if a.Cxp > b.Cxp {
+ return -1
+ }
+ return 0
+ })
+ m := min(len(l), int(n))
+ cs := make([]CopaingAccess, m)
+ for i, c := range l[:m] {
+ cs[i] = c
+ }
+ return cs, nil
+}