style(files): reorganize everything

This commit is contained in:
Anhgelus Morhtuuzh 2025-05-13 12:50:20 +02:00
parent 0a445aa1c7
commit c408afc879
Signed by: anhgelus
GPG key ID: CAD341EFA92DDDE5
13 changed files with 422 additions and 389 deletions

View file

@ -5,7 +5,7 @@ import (
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/config" "github.com/anhgelus/les-copaings-bot/config"
"github.com/anhgelus/les-copaings-bot/xp" "github.com/anhgelus/les-copaings-bot/exp"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"strings" "strings"
) )
@ -17,9 +17,9 @@ func ConfigShow(s *discordgo.Session, i *discordgo.InteractionCreate) {
l := len(cfg.XpRoles) - 1 l := len(cfg.XpRoles) - 1
for i, r := range cfg.XpRoles { for i, r := range cfg.XpRoles {
if i == l { if i == l {
roles += fmt.Sprintf("> Niveau %d - <@&%s>", xp.Level(r.XP), r.RoleID) roles += fmt.Sprintf("> Niveau %d - <@&%s>", exp.Level(r.XP), r.RoleID)
} else { } else {
roles += fmt.Sprintf("> Niveau %d - <@&%s>\n", xp.Level(r.XP), r.RoleID) roles += fmt.Sprintf("> Niveau %d - <@&%s>\n", exp.Level(r.XP), r.RoleID)
} }
} }
if len(roles) == 0 { if len(roles) == 0 {
@ -98,7 +98,7 @@ func ConfigXP(s *discordgo.Session, i *discordgo.InteractionCreate) {
} }
return return
} }
exp := xp.XPForLevel(uint(level)) exp := exp.LevelXP(uint(level))
r, ok := optMap["role"] r, ok := optMap["role"]
if !ok { if !ok {
err := resp.Message("Le rôle n'a pas été renseigné.").Send() err := resp.Message("Le rôle n'a pas été renseigné.").Send()

View file

@ -3,19 +3,20 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/xp" "github.com/anhgelus/les-copaings-bot/exp"
"github.com/anhgelus/les-copaings-bot/user"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
func Rank(s *discordgo.Session, i *discordgo.InteractionCreate) { func Rank(s *discordgo.Session, i *discordgo.InteractionCreate) {
optMap := utils.GenerateOptionMap(i) optMap := utils.GenerateOptionMap(i)
c := xp.GetCopaing(i.Member.User.ID, i.GuildID) // current copaing = member who used /rank c := user.GetCopaing(i.Member.User.ID, i.GuildID) // current user = member who used /rank
xp.LastEventUpdate(s, c) // update xp and reset last event user.LastEventUpdate(s, c) // update exp and reset last event
msg := "Votre niveau" msg := "Votre niveau"
m := i.Member m := i.Member
var err error var err error
resp := utils.ResponseBuilder{C: s, I: i} resp := utils.ResponseBuilder{C: s, I: i}
if v, ok := optMap["copaing"]; ok { if v, ok := optMap["user"]; ok {
u := v.UserValue(s) u := v.UserValue(s)
if u.Bot { if u.Bot {
err = resp.Message("Imagine si les bots avaient un niveau :rolling_eyes:").IsEphemeral().Send() err = resp.Message("Imagine si les bots avaient un niveau :rolling_eyes:").IsEphemeral().Send()
@ -39,12 +40,12 @@ func Rank(s *discordgo.Session, i *discordgo.InteractionCreate) {
} }
return return
} }
c = xp.GetCopaing(u.ID, i.GuildID) // current copaing = member targeted by member who wrote /rank c = user.GetCopaing(u.ID, i.GuildID) // current user = member targeted by member who wrote /rank
xp.XPUpdate(s, c) // update xp without resetting event user.UpdateXP(s, c) // update exp without resetting event
msg = fmt.Sprintf("Le niveau de %s", m.DisplayName()) msg = fmt.Sprintf("Le niveau de %s", m.DisplayName())
} }
lvl := xp.Level(c.XP) lvl := exp.Level(c.XP)
nxtLvlXP := xp.XPForLevel(lvl + 1) nxtLvlXP := exp.LevelXP(lvl + 1)
err = resp.Message(fmt.Sprintf( err = resp.Message(fmt.Sprintf(
"%s : **%d**\n> XP : %d\n> Prochain niveau dans %d XP", "%s : **%d**\n> XP : %d\n> Prochain niveau dans %d XP",
msg, msg,

View file

@ -3,12 +3,12 @@ package commands
import ( import (
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/xp" "github.com/anhgelus/les-copaings-bot/user"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
func Reset(s *discordgo.Session, i *discordgo.InteractionCreate) { func Reset(s *discordgo.Session, i *discordgo.InteractionCreate) {
var copaings []*xp.Copaing var copaings []*user.Copaing
gokord.DB.Where("guild_id = ?", i.GuildID).Delete(&copaings) gokord.DB.Where("guild_id = ?", i.GuildID).Delete(&copaings)
resp := utils.ResponseBuilder{C: s, I: i} resp := utils.ResponseBuilder{C: s, I: i}
if err := resp.IsEphemeral().Message("L'XP a été reset.").Send(); err != nil { if err := resp.IsEphemeral().Message("L'XP a été reset.").Send(); err != nil {
@ -20,9 +20,9 @@ func ResetUser(s *discordgo.Session, i *discordgo.InteractionCreate) {
resp := utils.ResponseBuilder{C: s, I: i} resp := utils.ResponseBuilder{C: s, I: i}
resp.IsEphemeral() resp.IsEphemeral()
optMap := utils.GenerateOptionMap(i) optMap := utils.GenerateOptionMap(i)
v, ok := optMap["copaing"] v, ok := optMap["user"]
if !ok { if !ok {
if err := resp.Message("Le copaing n'a pas été renseigné.").Send(); err != nil { if err := resp.Message("Le user n'a pas été renseigné.").Send(); err != nil {
utils.SendAlert("commands/reset.go - Copaing not set", err.Error()) utils.SendAlert("commands/reset.go - Copaing not set", err.Error())
} }
return return
@ -34,8 +34,8 @@ func ResetUser(s *discordgo.Session, i *discordgo.InteractionCreate) {
} }
return return
} }
xp.GetCopaing(m.ID, i.GuildID).Reset() user.GetCopaing(m.ID, i.GuildID).Reset()
if err := resp.Message("Le copaing bien été reset.").Send(); err != nil { if err := resp.Message("Le user bien été reset.").Send(); err != nil {
utils.SendAlert("commands/reset.go - Sending success (copaing)", err.Error()) utils.SendAlert("commands/reset.go - Sending success (user)", err.Error())
} }
} }

View file

@ -4,12 +4,13 @@ import (
"fmt" "fmt"
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/xp" "github.com/anhgelus/les-copaings-bot/exp"
"github.com/anhgelus/les-copaings-bot/user"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
func Top(s *discordgo.Session, i *discordgo.InteractionCreate) { func Top(s *discordgo.Session, i *discordgo.InteractionCreate) {
xp.LastEventUpdate(s, xp.GetCopaing(i.Member.User.ID, i.GuildID)) user.LastEventUpdate(s, user.GetCopaing(i.Member.User.ID, i.GuildID))
resp := utils.ResponseBuilder{C: s, I: i} resp := utils.ResponseBuilder{C: s, I: i}
err := resp.IsDeferred().Send() err := resp.IsDeferred().Send()
if err != nil { if err != nil {
@ -18,14 +19,14 @@ func Top(s *discordgo.Session, i *discordgo.InteractionCreate) {
} }
resp.NotDeferred().IsEdit() resp.NotDeferred().IsEdit()
go func() { go func() {
var tops []xp.Copaing var tops []user.Copaing
gokord.DB.Where("guild_id = ?", i.GuildID).Limit(10).Order("xp desc").Find(&tops) gokord.DB.Where("guild_id = ?", i.GuildID).Limit(10).Order("exp desc").Find(&tops)
msg := "" msg := ""
for i, c := range tops { for i, c := range tops {
if i == 9 { if i == 9 {
msg += fmt.Sprintf("%d. **<@%s>** - niveau %d", i+1, c.DiscordID, xp.Level(c.XP)) msg += fmt.Sprintf("%d. **<@%s>** - niveau %d", i+1, c.DiscordID, exp.Level(c.XP))
} else { } else {
msg += fmt.Sprintf("%d. **<@%s>** - niveau %d\n", i+1, c.DiscordID, xp.Level(c.XP)) msg += fmt.Sprintf("%d. **<@%s>** - niveau %d\n", i+1, c.DiscordID, exp.Level(c.XP))
} }
} }
err = resp.Embeds([]*discordgo.MessageEmbed{ err = resp.Embeds([]*discordgo.MessageEmbed{

View file

@ -10,7 +10,7 @@ import (
type GuildConfig struct { type GuildConfig struct {
gorm.Model gorm.Model
GuildID string `gorm:"not null;unique"` GuildID string `gorm:"not null;unique"`
XpRoles []*XpRole XpRoles []XpRole
DisabledChannels string DisabledChannels string
FallbackChannel string FallbackChannel string
} }
@ -46,7 +46,7 @@ func (cfg *GuildConfig) IsDisabled(channelID string) bool {
func (cfg *GuildConfig) FindXpRole(roleID string) (int, *XpRole) { func (cfg *GuildConfig) FindXpRole(roleID string) (int, *XpRole) {
for i, r := range cfg.XpRoles { for i, r := range cfg.XpRoles {
if r.RoleID == roleID { if r.RoleID == roleID {
return i, r return i, &r
} }
} }
return 0, nil return 0, nil

28
config/redis.go Normal file
View file

@ -0,0 +1,28 @@
package config
import (
"github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils"
"github.com/redis/go-redis/v9"
)
var redisClient *redis.Client
func GetRedisClient() (*redis.Client, error) {
if redisClient == nil {
var err error
redisClient, err = gokord.BaseCfg.GetRedisCredentials().Connect()
return redisClient, err
}
return redisClient, nil
}
func CloseRedisClient() {
if redisClient == nil {
return
}
err := redisClient.Close()
if err != nil {
utils.SendAlert("exp/member.go - Closing redis client", err.Error())
}
}

View file

@ -1,4 +1,4 @@
package xp package main
import ( import (
"context" "context"
@ -7,6 +7,8 @@ import (
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/config" "github.com/anhgelus/les-copaings-bot/config"
xp2 "github.com/anhgelus/les-copaings-bot/exp"
"github.com/anhgelus/les-copaings-bot/user"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"slices" "slices"
@ -30,20 +32,20 @@ func OnMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
if cfg.IsDisabled(m.ChannelID) { if cfg.IsDisabled(m.ChannelID) {
return return
} }
c := GetCopaing(m.Author.ID, m.GuildID) c := user.GetCopaing(m.Author.ID, m.GuildID)
LastEventUpdate(s, c) user.LastEventUpdate(s, c)
// add xp // add exp
trimmed := utils.TrimMessage(strings.ToLower(m.Content)) trimmed := utils.TrimMessage(strings.ToLower(m.Content))
m.Member.User = m.Author m.Member.User = m.Author
m.Member.GuildID = m.GuildID m.Member.GuildID = m.GuildID
xp := XPMessage(uint(len(trimmed)), calcDiversity(trimmed)) xp := xp2.MessageXP(uint(len(trimmed)), calcDiversity(trimmed))
if xp > MaxXpPerMessage { if xp > MaxXpPerMessage {
xp = MaxXpPerMessage xp = MaxXpPerMessage
} }
c.AddXP(s, m.Member, xp, func(_ uint, _ uint) { c.AddXP(s, m.Member, xp, func(_ uint, _ uint) {
if err := s.MessageReactionAdd(m.ChannelID, m.Message.ID, "⬆"); err != nil { if err := s.MessageReactionAdd(m.ChannelID, m.Message.ID, "⬆"); err != nil {
utils.SendAlert( utils.SendAlert(
"xp/events.go - add reaction for new level", err.Error(), "exp/events.go - add reaction for new level", err.Error(),
"channel id", m.ChannelID, "channel id", m.ChannelID,
"message id", m.Message.ID, "message id", m.Message.ID,
) )
@ -65,11 +67,11 @@ func OnVoiceUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) {
if e.Member.User.Bot { if e.Member.User.Bot {
return return
} }
LastEventUpdate(s, GetCopaing(e.UserID, e.GuildID)) user.LastEventUpdate(s, user.GetCopaing(e.UserID, e.GuildID))
cfg := config.GetGuildConfig(e.GuildID) cfg := config.GetGuildConfig(e.GuildID)
client, err := getRedisClient() client, err := config.GetRedisClient()
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Getting redis client", err.Error()) utils.SendAlert("exp/events.go - Getting redis client", err.Error())
return return
} }
if e.BeforeUpdate == nil && e.ChannelID != "" { if e.BeforeUpdate == nil && e.ChannelID != "" {
@ -87,7 +89,7 @@ func OnVoiceUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) {
func onConnection(_ *discordgo.Session, e *discordgo.VoiceStateUpdate, client *redis.Client) { func onConnection(_ *discordgo.Session, e *discordgo.VoiceStateUpdate, client *redis.Client) {
utils.SendDebug("User connected", "username", e.Member.DisplayName()) utils.SendDebug("User connected", "username", e.Member.DisplayName())
c := GetCopaing(e.UserID, e.GuildID) c := user.GetCopaing(e.UserID, e.GuildID)
err := client.Set( err := client.Set(
context.Background(), context.Background(),
c.GenKey(ConnectedSince), c.GenKey(ConnectedSince),
@ -95,13 +97,13 @@ func onConnection(_ *discordgo.Session, e *discordgo.VoiceStateUpdate, client *r
0, 0,
).Err() ).Err()
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Setting connected_since", err.Error()) utils.SendAlert("exp/events.go - Setting connected_since", err.Error())
} }
} }
func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, client *redis.Client) { func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, client *redis.Client) {
now := time.Now().Unix() now := time.Now().Unix()
c := GetCopaing(e.UserID, e.GuildID) c := user.GetCopaing(e.UserID, e.GuildID)
key := c.GenKey(ConnectedSince) key := c.GenKey(ConnectedSince)
res := client.Get(context.Background(), key) res := client.Get(context.Background(), key)
// check validity of user (1) // check validity of user (1)
@ -112,16 +114,16 @@ func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, client *r
return return
} }
if res.Err() != nil { if res.Err() != nil {
utils.SendAlert("xp/events.go - Getting connected_since", res.Err().Error()) utils.SendAlert("exp/events.go - Getting connected_since", res.Err().Error())
err := client.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err() err := client.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err()
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Set connected_since to not connected after get err", err.Error()) utils.SendAlert("exp/events.go - Set connected_since to not connected after get err", err.Error())
} }
return return
} }
con, err := res.Int64() con, err := res.Int64()
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Converting result to int64", err.Error()) utils.SendAlert("exp/events.go - Converting result to int64", err.Error())
return return
} }
// check validity of user (2) // check validity of user (2)
@ -134,12 +136,12 @@ func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, client *r
utils.SendDebug("User disconnected", "username", e.Member.DisplayName(), "since", con) utils.SendDebug("User disconnected", "username", e.Member.DisplayName(), "since", con)
err = client.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err() err = client.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err()
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Set connected_since to not connected", err.Error()) utils.SendAlert("exp/events.go - Set connected_since to not connected", err.Error())
} }
// add xp // add exp
timeInVocal := now - con timeInVocal := now - con
if timeInVocal < 0 { if timeInVocal < 0 {
utils.SendAlert("xp/events.go - Calculating time spent in vocal", "the time is negative") utils.SendAlert("exp/events.go - Calculating time spent in vocal", "the time is negative")
return return
} }
if timeInVocal > MaxTimeInVocal { if timeInVocal > MaxTimeInVocal {
@ -147,23 +149,23 @@ func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, client *r
timeInVocal = MaxTimeInVocal timeInVocal = MaxTimeInVocal
} }
e.Member.GuildID = e.GuildID e.Member.GuildID = e.GuildID
c.AddXP(s, e.Member, XPVocal(uint(timeInVocal)), func(_ uint, newLevel uint) { c.AddXP(s, e.Member, xp2.VocalXP(uint(timeInVocal)), func(_ uint, newLevel uint) {
cfg := config.GetGuildConfig(e.GuildID) cfg := config.GetGuildConfig(e.GuildID)
_, err = s.ChannelMessageSend(cfg.FallbackChannel, fmt.Sprintf( _, err = s.ChannelMessageSend(cfg.FallbackChannel, fmt.Sprintf(
"%s est maintenant niveau %d", e.Member.Mention(), newLevel, "%s est maintenant niveau %d", e.Member.Mention(), newLevel,
)) ))
if err != nil { if err != nil {
utils.SendAlert("xp/events.go - Sending new level in fallback channel", err.Error()) utils.SendAlert("exp/events.go - Sending new level in fallback channel", err.Error())
} }
}) })
} }
func OnLeave(_ *discordgo.Session, e *discordgo.GuildMemberRemove) { func OnLeave(_ *discordgo.Session, e *discordgo.GuildMemberRemove) {
utils.SendDebug("Leave event", "user_id", e.User.ID) utils.SendDebug("Leave event", "user_id", e.User.ID)
c := GetCopaing(e.User.ID, e.GuildID) c := user.GetCopaing(e.User.ID, e.GuildID)
if err := gokord.DB.Where("guild_id = ?", e.GuildID).Delete(c).Error; err != nil { if err := gokord.DB.Where("guild_id = ?", e.GuildID).Delete(c).Error; err != nil {
utils.SendAlert( utils.SendAlert(
"xp/events.go - deleting copaing from db", err.Error(), "exp/events.go - deleting user from db", err.Error(),
"user_id", e.User.ID, "user_id", e.User.ID,
"guild_id", e.GuildID, "guild_id", e.GuildID,
) )

View file

@ -1,29 +1,33 @@
package xp package exp
import ( import (
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"math" "math"
) )
func XPMessage(length uint, diversity uint) uint { func MessageXP(length uint, diversity uint) uint {
return uint(math.Floor( return uint(math.Floor(
0.025*math.Pow(float64(length), 1.25)*math.Sqrt(float64(diversity)) + 1, 0.025*math.Pow(float64(length), 1.25)*math.Sqrt(float64(diversity)) + 1,
)) ))
} }
func XPVocal(time uint) uint { func VocalXP(time uint) uint {
return uint(math.Floor( return uint(math.Floor(
0.01*math.Pow(float64(time), 1.3) + 1, 0.01*math.Pow(float64(time), 1.3) + 1,
)) ))
} }
// Level gives the level with the given XP.
// See LevelXP to get the XP required to get a level.
func Level(xp uint) uint { func Level(xp uint) uint {
return uint(math.Floor( return uint(math.Floor(
0.2 * math.Sqrt(float64(xp)), 0.2 * math.Sqrt(float64(xp)),
)) ))
} }
func XPForLevel(level uint) uint { // LevelXP gives the XP required to get this level.
// See Level to get the level with the given XP.
func LevelXP(level uint) uint {
return uint(math.Floor( return uint(math.Floor(
math.Pow(float64(5*level), 2), math.Pow(float64(5*level), 2),
)) ))
@ -33,7 +37,7 @@ func Lose(time uint, xp uint) uint {
if gokord.Debug { if gokord.Debug {
return uint(math.Floor( return uint(math.Floor(
math.Pow(float64(time), 3) * math.Pow(10, -2+math.Log(float64(time))) * math.Floor(float64(xp/500)+1), math.Pow(float64(time), 3) * math.Pow(10, -2+math.Log(float64(time))) * math.Floor(float64(xp/500)+1),
)) // a little bit faster to lose xp )) // a little bit faster to lose exp
} }
return uint(math.Floor( return uint(math.Floor(
math.Pow(float64(time), 2) * math.Pow(10, -2+math.Log(float64(time/85))) * math.Floor(float64(xp/500)+1), math.Pow(float64(time), 2) * math.Pow(10, -2+math.Log(float64(time/85))) * math.Floor(float64(xp/500)+1),

26
main.go
View file

@ -7,7 +7,7 @@ import (
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/commands" "github.com/anhgelus/les-copaings-bot/commands"
"github.com/anhgelus/les-copaings-bot/config" "github.com/anhgelus/les-copaings-bot/config"
"github.com/anhgelus/les-copaings-bot/xp" "github.com/anhgelus/les-copaings-bot/user"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"time" "time"
) )
@ -36,18 +36,18 @@ func main() {
panic(err) panic(err)
} }
err = gokord.DB.AutoMigrate(&xp.Copaing{}, &config.GuildConfig{}, &config.XpRole{}) err = gokord.DB.AutoMigrate(&user.Copaing{}, &config.GuildConfig{}, &config.XpRole{})
if err != nil { if err != nil {
panic(err) panic(err)
} }
adm := gokord.AdminPermission adm := gokord.AdminPermission
rankCmd := gokord.NewCommand("rank", "Affiche le niveau d'un copaing"). rankCmd := gokord.NewCommand("rank", "Affiche le niveau d'un user").
HasOption(). HasOption().
AddOption(gokord.NewOption( AddOption(gokord.NewOption(
discordgo.ApplicationCommandOptionUser, discordgo.ApplicationCommandOptionUser,
"copaing", "user",
"Le niveau du Copaing que vous souhaitez obtenir", "Le niveau du Copaing que vous souhaitez obtenir",
)). )).
SetHandler(commands.Rank) SetHandler(commands.Rank)
@ -58,7 +58,7 @@ func main() {
gokord.NewCommand("show", "Affiche la config").SetHandler(commands.ConfigShow), gokord.NewCommand("show", "Affiche la config").SetHandler(commands.ConfigShow),
). ).
AddSub( AddSub(
gokord.NewCommand("xp", "Modifie l'xp"). gokord.NewCommand("exp", "Modifie l'exp").
HasOption(). HasOption().
AddOption(gokord.NewOption( AddOption(gokord.NewOption(
discordgo.ApplicationCommandOptionString, discordgo.ApplicationCommandOptionString,
@ -114,16 +114,16 @@ func main() {
HasOption(). HasOption().
SetHandler(commands.Top) SetHandler(commands.Top)
resetCmd := gokord.NewCommand("reset", "Reset l'xp"). resetCmd := gokord.NewCommand("reset", "Reset l'exp").
HasOption(). HasOption().
SetHandler(commands.Reset). SetHandler(commands.Reset).
SetPermission(&adm) SetPermission(&adm)
resetUserCmd := gokord.NewCommand("reset-user", "Reset l'xp d'un utilisation"). resetUserCmd := gokord.NewCommand("reset-user", "Reset l'exp d'un utilisation").
HasOption(). HasOption().
AddOption(gokord.NewOption( AddOption(gokord.NewOption(
discordgo.ApplicationCommandOptionUser, discordgo.ApplicationCommandOptionUser,
"copaing", "user",
"Copaing a reset", "Copaing a reset",
).IsRequired()). ).IsRequired()).
SetHandler(commands.ResetUser). SetHandler(commands.ResetUser).
@ -176,14 +176,14 @@ func main() {
stopPeriodicReducer <- true stopPeriodicReducer <- true
} }
xp.CloseRedisClient() config.CloseRedisClient()
} }
func afterInit(dg *discordgo.Session) { func afterInit(dg *discordgo.Session) {
// handlers // handlers
dg.AddHandler(xp.OnMessage) dg.AddHandler(OnMessage)
dg.AddHandler(xp.OnVoiceUpdate) dg.AddHandler(OnVoiceUpdate)
dg.AddHandler(xp.OnLeave) dg.AddHandler(OnLeave)
// setup timer for periodic reducer // setup timer for periodic reducer
d := 24 * time.Hour d := 24 * time.Hour
@ -192,6 +192,6 @@ func afterInit(dg *discordgo.Session) {
d = time.Minute d = time.Minute
} }
stopPeriodicReducer = utils.NewTimer(d, func(stop chan<- interface{}) { stopPeriodicReducer = utils.NewTimer(d, func(stop chan<- interface{}) {
xp.PeriodicReducer(dg) user.PeriodicReducer(dg)
}) })
} }

View file

@ -1,9 +1,10 @@
package xp package user
import ( import (
"github.com/anhgelus/gokord" "github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils" "github.com/anhgelus/gokord/utils"
"github.com/anhgelus/les-copaings-bot/config" "github.com/anhgelus/les-copaings-bot/config"
"github.com/anhgelus/les-copaings-bot/exp"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"slices" "slices"
"sync" "sync"
@ -12,7 +13,7 @@ import (
func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) {
cfg := config.GetGuildConfig(m.GuildID) cfg := config.GetGuildConfig(m.GuildID)
xpForLevel := XPForLevel(level) xpForLevel := exp.LevelXP(level)
for _, role := range cfg.XpRoles { for _, role := range cfg.XpRoles {
if role.XP <= xpForLevel && !slices.Contains(m.Roles, role.RoleID) { if role.XP <= xpForLevel && !slices.Contains(m.Roles, role.RoleID) {
utils.SendDebug( utils.SendDebug(
@ -23,7 +24,7 @@ func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) {
) )
err := dg.GuildMemberRoleAdd(m.GuildID, m.User.ID, role.RoleID) err := dg.GuildMemberRoleAdd(m.GuildID, m.User.ID, role.RoleID)
if err != nil { if err != nil {
utils.SendAlert("xp/level.go - Adding role", err.Error(), "role_id", role.RoleID) utils.SendAlert("exp/level.go - Adding role", err.Error(), "role_id", role.RoleID)
} }
} else if role.XP > xpForLevel && slices.Contains(m.Roles, role.RoleID) { } else if role.XP > xpForLevel && slices.Contains(m.Roles, role.RoleID) {
utils.SendDebug( utils.SendDebug(
@ -34,7 +35,7 @@ func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) {
) )
err := dg.GuildMemberRoleRemove(m.GuildID, m.User.ID, role.RoleID) err := dg.GuildMemberRoleRemove(m.GuildID, m.User.ID, role.RoleID)
if err != nil { if err != nil {
utils.SendAlert("xp/level.go - Removing role", err.Error(), "role_id", role.RoleID) utils.SendAlert("exp/level.go - Removing role", err.Error(), "role_id", role.RoleID)
} }
} }
} }
@ -44,7 +45,7 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) {
m, err := dg.GuildMember(c.GuildID, c.DiscordID) m, err := dg.GuildMember(c.GuildID, c.DiscordID)
if err != nil { if err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Getting member for new level", err.Error(), "exp/level.go - Getting member for new level", err.Error(),
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", c.GuildID, "guild_id", c.GuildID,
) )
@ -55,11 +56,11 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) {
func LastEventUpdate(dg *discordgo.Session, c *Copaing) { func LastEventUpdate(dg *discordgo.Session, c *Copaing) {
h := c.HourSinceLastEvent() h := c.HourSinceLastEvent()
l := Lose(h, c.XP) l := exp.Lose(h, c.XP)
xp := c.XPAlreadyRemoved() xp := c.XPAlreadyRemoved()
oldXP := c.XP oldXP := c.XP
if l-xp < 0 { if l-xp < 0 {
utils.SendWarn("lose - xp already removed is negative", "lose", l, "xp", xp) utils.SendWarn("lose - exp already removed is negative", "lose", l, "exp", xp)
c.XP = 0 c.XP = 0
} else { } else {
calc := int(c.XP) - int(l) + int(c.XPAlreadyRemoved()) calc := int(c.XP) - int(l) + int(c.XPAlreadyRemoved())
@ -70,11 +71,11 @@ func LastEventUpdate(dg *discordgo.Session, c *Copaing) {
} }
} }
if oldXP != c.XP { if oldXP != c.XP {
lvl := Level(c.XP) lvl := exp.Level(c.XP)
if Level(oldXP) != lvl { if exp.Level(oldXP) != lvl {
utils.SendDebug( utils.SendDebug(
"Level changed", "Level changed",
"old", Level(oldXP), "old", exp.Level(oldXP),
"new", lvl, "new", lvl,
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", c.GuildID, "guild_id", c.GuildID,
@ -83,8 +84,8 @@ func LastEventUpdate(dg *discordgo.Session, c *Copaing) {
} }
if err := c.Save(); err != nil { if err := c.Save(); err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Saving copaing", err.Error(), "exp/level.go - Saving user", err.Error(),
"xp", c.XP, "exp", c.XP,
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", c.GuildID, "guild_id", c.GuildID,
) )
@ -93,16 +94,16 @@ func LastEventUpdate(dg *discordgo.Session, c *Copaing) {
c.SetLastEvent() c.SetLastEvent()
} }
func XPUpdate(dg *discordgo.Session, c *Copaing) { func UpdateXP(dg *discordgo.Session, c *Copaing) {
oldXP := c.XP oldXP := c.XP
if oldXP == 0 { if oldXP == 0 {
return return
} }
h := c.HourSinceLastEvent() h := c.HourSinceLastEvent()
l := Lose(h, c.XP) l := exp.Lose(h, c.XP)
xp := c.XPAlreadyRemoved() xp := c.XPAlreadyRemoved()
if l-xp < 0 { if l-xp < 0 {
utils.SendWarn("lose - xp_removed is negative", "lose", l, "xp removed", xp) utils.SendWarn("lose - xp_removed is negative", "lose", l, "exp removed", xp)
c.AddXPAlreadyRemoved(0) c.AddXPAlreadyRemoved(0)
} else { } else {
calc := int(c.XP) - int(l) + int(xp) calc := int(c.XP) - int(l) + int(xp)
@ -115,11 +116,11 @@ func XPUpdate(dg *discordgo.Session, c *Copaing) {
} }
} }
if oldXP != c.XP { if oldXP != c.XP {
lvl := Level(c.XP) lvl := exp.Level(c.XP)
if Level(oldXP) != lvl { if exp.Level(oldXP) != lvl {
utils.SendDebug( utils.SendDebug(
"Level updated", "Level updated",
"old", Level(oldXP), "old", exp.Level(oldXP),
"new", lvl, "new", lvl,
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", c.GuildID, "guild_id", c.GuildID,
@ -129,8 +130,8 @@ func XPUpdate(dg *discordgo.Session, c *Copaing) {
utils.SendDebug("Save XP", "old", oldXP, "new", c.XP, "user", c.DiscordID) utils.SendDebug("Save XP", "old", oldXP, "new", c.XP, "user", c.DiscordID)
if err := c.Save(); err != nil { if err := c.Save(); err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Saving copaing", err.Error(), "exp/level.go - Saving user", err.Error(),
"xp", c.XP, "exp", c.XP,
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", c.GuildID, "guild_id", c.GuildID,
) )
@ -144,7 +145,7 @@ func PeriodicReducer(dg *discordgo.Session) {
var cs []*Copaing var cs []*Copaing
err := gokord.DB.Where("guild_id = ?", g.ID).Find(&cs).Error err := gokord.DB.Where("guild_id = ?", g.ID).Find(&cs).Error
if err != nil { if err != nil {
utils.SendAlert("xp/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID) utils.SendAlert("exp/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID)
continue continue
} }
for i, c := range cs { for i, c := range cs {
@ -155,14 +156,14 @@ func PeriodicReducer(dg *discordgo.Session) {
u, err = dg.User(c.DiscordID) u, err = dg.User(c.DiscordID)
if err != nil { if err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Fetching user", err.Error(), "exp/level.go - Fetching user", err.Error(),
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", g.ID, "guild_id", g.ID,
) )
utils.SendWarn("Removing user from database", "discord_id", c.DiscordID) utils.SendWarn("Removing user from database", "discord_id", c.DiscordID)
if err = gokord.DB.Delete(c).Error; err != nil { if err = gokord.DB.Delete(c).Error; err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Removing user from database", err.Error(), "exp/level.go - Removing user from database", err.Error(),
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", g.ID, "guild_id", g.ID,
) )
@ -174,7 +175,7 @@ func PeriodicReducer(dg *discordgo.Session) {
} }
if _, err = dg.GuildMember(g.ID, c.DiscordID); err != nil { if _, err = dg.GuildMember(g.ID, c.DiscordID); err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Fetching member", err.Error(), "exp/level.go - Fetching member", err.Error(),
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", g.ID, "guild_id", g.ID,
) )
@ -185,7 +186,7 @@ func PeriodicReducer(dg *discordgo.Session) {
) )
if err = gokord.DB.Where("guild_id = ?", g.ID).Delete(c).Error; err != nil { if err = gokord.DB.Where("guild_id = ?", g.ID).Delete(c).Error; err != nil {
utils.SendAlert( utils.SendAlert(
"xp/level.go - Removing user from guild in database", err.Error(), "exp/level.go - Removing user from guild in database", err.Error(),
"discord_id", c.DiscordID, "discord_id", c.DiscordID,
"guild_id", g.ID, "guild_id", g.ID,
) )
@ -194,7 +195,7 @@ func PeriodicReducer(dg *discordgo.Session) {
} }
wg.Add(1) wg.Add(1)
go func() { go func() {
XPUpdate(dg, c) UpdateXP(dg, c)
wg.Done() wg.Done()
}() }()
} }

107
user/member.go Normal file
View file

@ -0,0 +1,107 @@
package user
import (
"fmt"
"github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils"
"gorm.io/gorm"
)
type Copaing struct {
gorm.Model
DiscordID string `gorm:"not null"`
//XP []CopaingXP
XP uint `gorm:"default:0"`
GuildID string `gorm:"not null"`
}
type leftCopaing struct {
ID uint
StopDelete chan<- interface{}
}
//type CopaingXP struct {
// gorm.Model
// XP uint `gorm:"default:0"`
// CopaingID uint
//}
var (
leftCopaingsMap = map[string]*leftCopaing{}
)
const (
LastEvent = "last_event"
AlreadyRemoved = "already_removed"
)
func GetCopaing(discordID string, guildID string) *Copaing {
c := Copaing{DiscordID: discordID, GuildID: guildID}
if err := c.Load(); err != nil {
utils.SendAlert(
"exp/member.go - Loading user",
err.Error(),
"discord_id",
discordID,
"guild_id",
guildID,
)
return nil
}
return &c
}
func (c *Copaing) Load() error {
// check if user left in the past 48 hours
k := c.GuildID + ":" + c.DiscordID
l, ok := leftCopaingsMap[k]
if !ok || l == nil {
// if not, common first or create
return gokord.DB.Where("discord_id = ? and guild_id = ?", c.DiscordID, c.GuildID).FirstOrCreate(c).Error
}
// else, getting last data
tmp := Copaing{
Model: gorm.Model{
ID: c.ID,
},
DiscordID: c.DiscordID,
GuildID: c.GuildID,
}
if err := gokord.DB.Unscoped().Find(&tmp).Error; err != nil {
// if error, avoid getting old data and use new one
utils.SendAlert(
"exp/member.go - Getting user in soft delete", err.Error(),
"discord_id", c.DiscordID,
"guild_id", c.DiscordID,
"last_id", l.ID,
)
return gokord.DB.Where("discord_id = ? and guild_id = ?", c.DiscordID, c.GuildID).FirstOrCreate(c).Error
}
// resetting internal data
tmp.Model = gorm.Model{}
l.StopDelete <- true
leftCopaingsMap[k] = nil
// creating new data
err := gokord.DB.Create(&tmp).Error
if err != nil {
return err
}
// delete old data
if err = gokord.DB.Unscoped().Delete(&tmp).Error; err != nil {
utils.SendAlert(
"exp/member.go - Deleting user in soft delete", err.Error(),
"discord_id", c.DiscordID,
"guild_id", c.DiscordID,
"last_id", l.ID,
)
}
return nil
}
func (c *Copaing) Save() error {
return gokord.DB.Save(c).Error
}
func (c *Copaing) GenKey(key string) string {
return fmt.Sprintf("%s:%s:%s", c.GuildID, c.DiscordID, key)
}

185
user/xp.go Normal file
View file

@ -0,0 +1,185 @@
package user
import (
"context"
"errors"
"fmt"
"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"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"math"
"strconv"
"time"
)
func (c *Copaing) AddXP(s *discordgo.Session, m *discordgo.Member, xp uint, fn func(uint, uint)) {
pastLevel := exp.Level(c.XP)
old := c.XP
c.XP += xp
if err := c.Save(); err != nil {
utils.SendAlert(
"exp/level.go - Saving user",
err.Error(),
"exp",
c.XP,
"discord_id",
c.DiscordID,
"guild_id",
c.GuildID,
)
c.XP = old
return
}
newLevel := exp.Level(c.XP)
if newLevel > pastLevel {
fn(c.XP, newLevel)
onNewLevel(s, m, newLevel)
}
}
func (c *Copaing) SetLastEvent() {
client, err := config.GetRedisClient()
if err != nil {
utils.SendAlert("exp/member.go - Getting redis client (set)", err.Error())
return
}
t := time.Now().Unix()
err = client.Set(context.Background(), c.GenKey(LastEvent), strconv.FormatInt(t, 10), 0).Err()
if err != nil {
utils.SendAlert("exp/member.go - Setting last event", err.Error(), "time", t, "base_key", c.GenKey(""))
return
}
err = client.Set(context.Background(), c.GenKey(AlreadyRemoved), "0", 0).Err()
if err != nil {
utils.SendAlert(
"exp/member.go - Setting already removed to 0",
err.Error(),
"time",
t,
"base_key",
c.GenKey(""),
)
return
}
}
func (c *Copaing) HourSinceLastEvent() uint {
client, err := config.GetRedisClient()
if err != nil {
utils.SendAlert("exp/member.go - Getting redis client (get)", err.Error())
return 0
}
res := client.Get(context.Background(), c.GenKey(LastEvent))
if errors.Is(res.Err(), redis.Nil) {
return 0
} else if res.Err() != nil {
utils.SendAlert("exp/member.go - Getting last event", res.Err().Error(), "base_key", c.GenKey(""))
return 0
}
t := time.Now().Unix()
last, err := strconv.Atoi(res.Val())
if err != nil {
utils.SendAlert(
"exp/member.go - Converting time fetched into int (last event)",
err.Error(),
"base_key",
c.GenKey(""),
"val",
res.Val(),
)
return 0
}
if gokord.Debug {
return uint(math.Floor(float64(t-int64(last)) / 60)) // not hours of unix, is minutes of unix
}
return utils.HoursOfUnix(t - int64(last))
}
func (c *Copaing) AddXPAlreadyRemoved(xp uint) uint {
client, err := config.GetRedisClient()
if err != nil {
utils.SendAlert("exp/member.go - Getting redis client (set)", err.Error())
return 0
}
exp := xp + c.XPAlreadyRemoved()
err = client.Set(context.Background(), c.GenKey(AlreadyRemoved), exp, 0).Err()
if err != nil {
utils.SendAlert(
"exp/member.go - Setting already removed",
err.Error(),
"exp already removed",
exp,
"base_key",
c.GenKey(""),
)
return 0
}
return exp
}
func (c *Copaing) XPAlreadyRemoved() uint {
client, err := config.GetRedisClient()
if err != nil {
utils.SendAlert("exp/member.go - Getting redis client (exp)", err.Error())
return 0
}
res := client.Get(context.Background(), fmt.Sprintf("%s:%s", c.GenKey(""), AlreadyRemoved))
if errors.Is(res.Err(), redis.Nil) {
return 0
} else if res.Err() != nil {
utils.SendAlert("exp/member.go - Getting already removed", res.Err().Error(), "base_key", c.GenKey(""))
return 0
}
xp, err := strconv.Atoi(res.Val())
if err != nil {
utils.SendAlert(
"exp/member.go - Converting time fetched into int (already removed)",
err.Error(),
"base_key",
c.GenKey(""),
"val",
res.Val(),
)
return 0
}
if xp < 0 {
utils.SendAlert(
"exp/member.go - Assertion exp >= 0",
"exp is negative",
"base_key",
c.GenKey(""),
"exp",
xp,
)
return 0
}
return uint(xp)
}
func (c *Copaing) Reset() {
gokord.DB.Where("guild_id = ? AND discord_id = ?", c.GuildID, c.DiscordID).Delete(c)
}
func (c *Copaing) AfterDelete(db *gorm.DB) error {
id := c.ID
dID := c.DiscordID
gID := c.GuildID
k := c.GuildID + ":" + c.DiscordID
ch := utils.NewTimer(48*time.Hour, func(stop chan<- interface{}) {
if err := db.Unscoped().Where("id = ?", id).Delete(c).Error; err != nil {
utils.SendAlert(
"exp/member.go - Removing user from database", err.Error(),
"discord_id", dID,
"guild_id", gID,
)
}
stop <- true
leftCopaingsMap[k] = nil
})
leftCopaingsMap[k] = &leftCopaing{id, ch}
return nil
}

View file

@ -1,296 +0,0 @@
package xp
import (
"context"
"errors"
"fmt"
"github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/utils"
"github.com/bwmarrin/discordgo"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"math"
"strconv"
"time"
)
type Copaing struct {
gorm.Model
DiscordID string `gorm:"not null"`
XP uint `gorm:"default:0"`
GuildID string `gorm:"not null"`
}
type leftCopaing struct {
ID uint
StopDelete chan<- interface{}
}
var (
redisClient *redis.Client
leftCopaingsMap = map[string]*leftCopaing{}
)
const (
LastEvent = "last_event"
AlreadyRemoved = "already_removed"
)
func GetCopaing(discordID string, guildID string) *Copaing {
c := Copaing{DiscordID: discordID, GuildID: guildID}
if err := c.Load(); err != nil {
utils.SendAlert(
"xp/member.go - Loading copaing",
err.Error(),
"discord_id",
discordID,
"guild_id",
guildID,
)
return nil
}
return &c
}
func (c *Copaing) Load() error {
// check if user left in the past 48 hours
k := c.GuildID + ":" + c.DiscordID
l, ok := leftCopaingsMap[k]
if !ok || l == nil {
// if not, common first or create
return gokord.DB.Where("discord_id = ? and guild_id = ?", c.DiscordID, c.GuildID).FirstOrCreate(c).Error
}
// else, getting last data
tmp := Copaing{
Model: gorm.Model{
ID: c.ID,
},
DiscordID: c.DiscordID,
GuildID: c.GuildID,
}
if err := gokord.DB.Unscoped().Find(&tmp).Error; err != nil {
// if error, avoid getting old data and use new one
utils.SendAlert(
"xp/member.go - Getting copaing in soft delete", err.Error(),
"discord_id", c.DiscordID,
"guild_id", c.DiscordID,
"last_id", l.ID,
)
return gokord.DB.Where("discord_id = ? and guild_id = ?", c.DiscordID, c.GuildID).FirstOrCreate(c).Error
}
// resetting internal data
tmp.Model = gorm.Model{}
l.StopDelete <- true
leftCopaingsMap[k] = nil
// creating new data
err := gokord.DB.Create(&tmp).Error
if err != nil {
return err
}
// delete old data
if err = gokord.DB.Unscoped().Delete(&tmp).Error; err != nil {
utils.SendAlert(
"xp/member.go - Deleting copaing in soft delete", err.Error(),
"discord_id", c.DiscordID,
"guild_id", c.DiscordID,
"last_id", l.ID,
)
}
return nil
}
func (c *Copaing) Save() error {
return gokord.DB.Save(c).Error
}
func (c *Copaing) GenKey(key string) string {
return fmt.Sprintf("%s:%s:%s", c.GuildID, c.DiscordID, key)
}
func (c *Copaing) AddXP(s *discordgo.Session, m *discordgo.Member, xp uint, fn func(uint, uint)) {
pastLevel := Level(c.XP)
old := c.XP
c.XP += xp
if err := c.Save(); err != nil {
utils.SendAlert(
"xp/level.go - Saving copaing",
err.Error(),
"xp",
c.XP,
"discord_id",
c.DiscordID,
"guild_id",
c.GuildID,
)
c.XP = old
return
}
newLevel := Level(c.XP)
if newLevel > pastLevel {
fn(c.XP, newLevel)
onNewLevel(s, m, newLevel)
}
}
func (c *Copaing) SetLastEvent() {
client, err := getRedisClient()
if err != nil {
utils.SendAlert("xp/member.go - Getting redis client (set)", err.Error())
return
}
t := time.Now().Unix()
err = client.Set(context.Background(), c.GenKey(LastEvent), strconv.FormatInt(t, 10), 0).Err()
if err != nil {
utils.SendAlert("xp/member.go - Setting last event", err.Error(), "time", t, "base_key", c.GenKey(""))
return
}
err = client.Set(context.Background(), c.GenKey(AlreadyRemoved), "0", 0).Err()
if err != nil {
utils.SendAlert(
"xp/member.go - Setting already removed to 0",
err.Error(),
"time",
t,
"base_key",
c.GenKey(""),
)
return
}
}
func (c *Copaing) HourSinceLastEvent() uint {
client, err := getRedisClient()
if err != nil {
utils.SendAlert("xp/member.go - Getting redis client (get)", err.Error())
return 0
}
res := client.Get(context.Background(), c.GenKey(LastEvent))
if errors.Is(res.Err(), redis.Nil) {
return 0
} else if res.Err() != nil {
utils.SendAlert("xp/member.go - Getting last event", res.Err().Error(), "base_key", c.GenKey(""))
return 0
}
t := time.Now().Unix()
last, err := strconv.Atoi(res.Val())
if err != nil {
utils.SendAlert(
"xp/member.go - Converting time fetched into int (last event)",
err.Error(),
"base_key",
c.GenKey(""),
"val",
res.Val(),
)
return 0
}
if gokord.Debug {
return uint(math.Floor(float64(t-int64(last)) / 60)) // not hours of unix, is minutes of unix
}
return utils.HoursOfUnix(t - int64(last))
}
func (c *Copaing) AddXPAlreadyRemoved(xp uint) uint {
client, err := getRedisClient()
if err != nil {
utils.SendAlert("xp/member.go - Getting redis client (set)", err.Error())
return 0
}
exp := xp + c.XPAlreadyRemoved()
err = client.Set(context.Background(), c.GenKey(AlreadyRemoved), exp, 0).Err()
if err != nil {
utils.SendAlert(
"xp/member.go - Setting already removed",
err.Error(),
"xp already removed",
exp,
"base_key",
c.GenKey(""),
)
return 0
}
return exp
}
func (c *Copaing) XPAlreadyRemoved() uint {
client, err := getRedisClient()
if err != nil {
utils.SendAlert("xp/member.go - Getting redis client (xp)", err.Error())
return 0
}
res := client.Get(context.Background(), fmt.Sprintf("%s:%s", c.GenKey(""), AlreadyRemoved))
if errors.Is(res.Err(), redis.Nil) {
return 0
} else if res.Err() != nil {
utils.SendAlert("xp/member.go - Getting already removed", res.Err().Error(), "base_key", c.GenKey(""))
return 0
}
xp, err := strconv.Atoi(res.Val())
if err != nil {
utils.SendAlert(
"xp/member.go - Converting time fetched into int (already removed)",
err.Error(),
"base_key",
c.GenKey(""),
"val",
res.Val(),
)
return 0
}
if xp < 0 {
utils.SendAlert(
"xp/member.go - Assertion xp >= 0",
"xp is negative",
"base_key",
c.GenKey(""),
"xp",
xp,
)
return 0
}
return uint(xp)
}
func (c *Copaing) Reset() {
gokord.DB.Where("guild_id = ? AND discord_id = ?", c.GuildID, c.DiscordID).Delete(c)
}
func (c *Copaing) AfterDelete(db *gorm.DB) error {
id := c.ID
dID := c.DiscordID
gID := c.GuildID
k := c.GuildID + ":" + c.DiscordID
ch := utils.NewTimer(48*time.Hour, func(stop chan<- interface{}) {
if err := db.Unscoped().Where("id = ?", id).Delete(c).Error; err != nil {
utils.SendAlert(
"xp/member.go - Removing copaing from database", err.Error(),
"discord_id", dID,
"guild_id", gID,
)
}
stop <- true
leftCopaingsMap[k] = nil
})
leftCopaingsMap[k] = &leftCopaing{id, ch}
return nil
}
func getRedisClient() (*redis.Client, error) {
if redisClient == nil {
var err error
redisClient, err = gokord.BaseCfg.GetRedisCredentials().Connect()
return redisClient, err
}
return redisClient, nil
}
func CloseRedisClient() {
if redisClient == nil {
return
}
err := redisClient.Close()
if err != nil {
utils.SendAlert("xp/member.go - Closing redis client", err.Error())
}
}