From d869fa2fa47e71a4c0fea40f468d654d03aa6211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Thu, 11 Sep 2025 12:54:02 +0200 Subject: feat(commands): static colors for stats --- commands/stats.go | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'commands') diff --git a/commands/stats.go b/commands/stats.go index f93f6a0..15fb556 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -3,11 +3,10 @@ package commands import ( "bytes" "errors" - "gorm.io/gorm" + "fmt" "image/color" "io" "math" - "math/rand/v2" "slices" "time" @@ -22,6 +21,7 @@ import ( "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" + "gorm.io/gorm" ) type data struct { @@ -36,18 +36,27 @@ type dbData struct { CopaingID int } +var colors = []color.RGBA{ + {38, 70, 83, 255}, + {42, 157, 143, 255}, + {244, 162, 97, 255}, + {231, 111, 81, 255}, + {193, 18, 31, 255}, +} + func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) { cfg := config.GetGuildConfig(i.GuildID) - days := cfg.DaysXPRemains + days := 15 if v, ok := opt["days"]; ok { in := v.IntValue() - if in < 0 || uint(in) > days { - if err := resp.SetMessage("Nombre de jours invalide").IsEphemeral().Send(); err != nil { + if in < 1 || uint(in) > cfg.DaysXPRemains { + msg := fmt.Sprintf("Nombre de jours invalide. Il doit être strictement positif et inférieur à %d", cfg.DaysXPRemains) + if err := resp.SetMessage(msg).IsEphemeral().Send(); err != nil { logger.Alert("commands/stats.go - Sending invalid days", err.Error()) } return } - days = uint(in) + days = int(in) } err := resp.IsDeferred().Send() if err != nil { @@ -83,13 +92,13 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM }() } -func statsAll(s *discordgo.Session, i *discordgo.InteractionCreate, days uint) (io.WriterTo, error) { +func statsAll(s *discordgo.Session, i *discordgo.InteractionCreate, days int) (io.WriterTo, error) { return stats(s, i, days, func(before, after string) *gorm.DB { - return gokord.DB.Raw(before+"WHERE guild_id = ? and created_at > ?"+after, i.GuildID, exp.TimeStampNDaysBefore(days)) + return gokord.DB.Raw(before+"WHERE guild_id = ? and created_at > ?"+after, i.GuildID, exp.TimeStampNDaysBefore(uint(days))) }) } -func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, discordID string) (io.WriterTo, error) { +func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days int, discordID string) (io.WriterTo, error) { _, err := s.GuildMember(i.GuildID, discordID) if err != nil { return nil, err @@ -97,12 +106,12 @@ func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days uint return stats(s, i, days, func(before, after string) *gorm.DB { return gokord.DB.Raw( before+"WHERE guild_id = ? and created_at > ? and copaing_id = ?"+after, - i.GuildID, exp.TimeStampNDaysBefore(days), user.GetCopaing(discordID, i.GuildID).ID, + i.GuildID, exp.TimeStampNDaysBefore(uint(days)), user.GetCopaing(discordID, i.GuildID).ID, ) }) } -func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, execSql func(before, after string) *gorm.DB) (io.WriterTo, error) { +func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execSql func(before, after string) *gorm.DB) (io.WriterTo, error) { var rawData []*data if gokord.Debug { var rawCopaingData []*user.CopaingXP @@ -188,7 +197,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings p.Add(plotter.NewGrid()) - r := rand.New(rand.NewPCG(uint64(time.Now().Unix()), uint64(time.Now().Unix()))) + cnt := 0 for in, c := range copaings { m, err := s.GuildMember(i.GuildID, c.DiscordID) if err != nil { @@ -204,16 +213,15 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings } return 0 }) - l, err := plotter.NewLine(plotter.XYs(stats[in])) + l, _, err := plotter.NewLinePoints(plotter.XYs(stats[in])) if err != nil { logger.Alert("commands/stats.go - Adding line points", err.Error()) return nil, err } - l.LineStyle.Width = vg.Points(1) - l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)} - l.LineStyle.Color = color.RGBA{R: uint8(r.UintN(255)), G: uint8(r.UintN(255)), B: uint8(r.UintN(255)), A: 255} + l.Color = colors[cnt%len(colors)] p.Add(l) p.Legend.Add(m.DisplayName(), l) + cnt++ } w, err := p.WriterTo(8*vg.Inch, 6*vg.Inch, "png") if err != nil { -- cgit v1.2.3 From 8cec1c5a30f9bf679f3b4704b27684b4c4bf531b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Thu, 11 Sep 2025 14:35:32 +0200 Subject: docs(info): add inter as deps in readme and credits --- commands/credits.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'commands') diff --git a/commands/credits.go b/commands/credits.go index f0a8c46..d58547e 100644 --- a/commands/credits.go +++ b/commands/credits.go @@ -11,7 +11,8 @@ func Credits(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionM msg := "**Les Copaings**, le bot gérant les serveurs privés de [anhgelus]().\n" msg += "Code source : \n\n" msg += "Host du bot : " + gokord.BaseCfg.GetAuthor() + ".\n\n" - msg += "Utilise :\n- [anhgelus/gokord]()" + msg += "Utilise :\n- [anhgelus/gokord]()\n" + msg += "- [Inter]()" err := resp.SetMessage(msg).Send() if err != nil { logger.Alert("commands/credits.go - Sending credits", err.Error(), "guild_id", i.GuildID) -- cgit v1.2.3 From 8885566932c965926ee64fad6404e6f26bc13220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 13 Sep 2025 13:32:01 +0200 Subject: build(gokord): upgrade to latest version --- commands/config.go | 36 +----------------------------------- commands/rank.go | 4 ++-- commands/reset.go | 2 +- commands/stats.go | 9 +++++---- commands/top.go | 7 ++++--- 5 files changed, 13 insertions(+), 45 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index c4644bc..838f7e9 100644 --- a/commands/config.go +++ b/commands/config.go @@ -7,7 +7,6 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/config" "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/component" "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" ) @@ -50,14 +49,6 @@ func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa defaultChan = fmt.Sprintf("<#%s>", cfg.FallbackChannel) } //comp := component.New(). - // Add(component.NewTextDisplay("# Config")). - // Add(component.NewTextDisplay("**Salon par défaut**\n" + defaultChan)). - // Add(component.NewSeparator()). - // Add(component.NewTextDisplay("**Rôles liés aux niveaux**\n" + roles)). - // Add(component.NewSeparator()). - // Add(component.NewTextDisplay("**Salons désactivés**\n" + chans)). - // Add(component.NewSeparator()). - // Add(component.NewTextDisplay(fmt.Sprintf("**%s**\n%d", "Jours avant la réduction", cfg.DaysXPRemains))). // Add(component.NewActionRow().Add(component.NewStringSelect(ConfigModify). // SetPlaceholder("Modifier..."). // AddOption( @@ -82,31 +73,6 @@ func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa // SetEmoji(&discordgo.ComponentEmoji{Name: "⌛"}), // ), // )) - comp := component.New(). - Add(component.NewActionRow().Add(component.NewStringSelect(ConfigModify). - SetPlaceholder("Modifier..."). - AddOption( - component.NewSelectOption("Rôles liés à l'XP", config.ModifyXpRole). - SetDescription("Gère les rôles liés à l'XP"). - SetEmoji(&discordgo.ComponentEmoji{Name: "🏅"}), - ). - AddOption( - component.NewSelectOption("Salons désactivés", config.ModifyDisChannel). - SetDescription("Gère les salons désactivés"). - SetEmoji(&discordgo.ComponentEmoji{Name: "❌"}), - ). - AddOption( - // I don't have a better idea for this... - component.NewSelectOption("Salons par défaut", config.ModifyFallbackChannel). - SetDescription("Spécifie le salon par défaut"). - SetEmoji(&discordgo.ComponentEmoji{Name: "💾"}), - ). - AddOption( - component.NewSelectOption("Temps avec la réduction", config.ModifyTimeReduce). - SetDescription("Gère le temps avant la réduction d'XP"). - SetEmoji(&discordgo.ComponentEmoji{Name: "⌛"}), - ), - )) msg := fmt.Sprintf( "# Config\n**Salon par défaut**\n%s\n\n**Rôles liés aux niveaux**\n%s\n\n**Salons désactivés**\n%s\n\n**Jours avant la réduction**\n%d", defaultChan, @@ -114,7 +80,7 @@ func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa chans, cfg.DaysXPRemains, ) - err := resp.SetComponents(comp).SetMessage(msg).IsEphemeral().Send() + err := resp.SetMessage(msg).IsEphemeral().Send() if err != nil { logger.Alert("config/guild.go - Sending config", err.Error()) } diff --git a/commands/rank.go b/commands/rank.go index 94dabf2..0adfde6 100644 --- a/commands/rank.go +++ b/commands/rank.go @@ -16,14 +16,14 @@ func Rank(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.Optio m := i.Member var err error if v, ok := optMap["copaing"]; ok { - u := v.UserValue(s) + u := v.UserValue(s.UserAPI()) if u.Bot { err = resp.SetMessage("Imagine si les bots avaient un niveau :rolling_eyes:").IsEphemeral().Send() if err != nil { logger.Alert("commands/rank.go - Reply error user is a bot", err.Error()) } } - m, err = s.GuildMember(i.GuildID, u.ID) + m, err = s.GuildAPI().Member(i.GuildID, u.ID) if err != nil { logger.Alert( "commands/rank.go - Fetching guild member", diff --git a/commands/reset.go b/commands/reset.go index 07e3ba3..f50bb21 100644 --- a/commands/reset.go +++ b/commands/reset.go @@ -25,7 +25,7 @@ func ResetUser(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd. } return } - m := v.UserValue(s) + m := v.UserValue(s.UserAPI()) if m.Bot { if err := resp.SetMessage("Les bots n'ont pas de niveau :upside_down:").Send(); err != nil { logger.Alert("commands/reset.go - Copaing not set", err.Error()) diff --git a/commands/stats.go b/commands/stats.go index 15fb556..1a7a379 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -18,6 +18,7 @@ import ( "github.com/anhgelus/gokord/logger" "github.com/jackc/pgx/v5/pgtype" discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/channel" "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" @@ -66,7 +67,7 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM go func() { var w io.WriterTo if v, ok := opt["user"]; ok { - w, err = statsMember(s, i, days, v.UserValue(s).ID) + w, err = statsMember(s, i, days, v.UserValue(s.UserAPI()).ID) } else { w, err = statsAll(s, i, days) } @@ -81,7 +82,7 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM if err != nil { logger.Alert("commands/stats.go - Writing png", err.Error()) } - err = resp.AddFile(&discordgo.File{ + err = resp.AddFile(&channel.File{ Name: "plot.png", ContentType: "image/png", Reader: b, @@ -99,7 +100,7 @@ func statsAll(s *discordgo.Session, i *discordgo.InteractionCreate, days int) (i } func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days int, discordID string) (io.WriterTo, error) { - _, err := s.GuildMember(i.GuildID, discordID) + _, err := s.GuildAPI().Member(i.GuildID, discordID) if err != nil { return nil, err } @@ -199,7 +200,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings cnt := 0 for in, c := range copaings { - m, err := s.GuildMember(i.GuildID, c.DiscordID) + m, err := s.GuildAPI().Member(i.GuildID, c.DiscordID) if err != nil { logger.Alert("commands/stats.go - Fetching guild member", err.Error()) return nil, err diff --git a/commands/top.go b/commands/top.go index ecbf6f4..21a1456 100644 --- a/commands/top.go +++ b/commands/top.go @@ -10,6 +10,7 @@ import ( "github.com/anhgelus/gokord/cmd" "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/channel" ) func Top(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { @@ -18,7 +19,7 @@ func Top(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, logger.Alert("commands/top.go - Sending deferred", err.Error()) return } - embeds := make([]*discordgo.MessageEmbed, 3) + embeds := make([]*channel.MessageEmbed, 3) wg := sync.WaitGroup{} fn := func(s string, n uint, d int, id int) { @@ -26,14 +27,14 @@ func Top(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, tops, err := user.GetBestXP(i.GuildID, n, d) if err != nil { logger.Alert("commands/top.go - Fetching best xp", err.Error(), "n", n, "d", d, "id", id, "guild_id", i.GuildID) - embeds[id] = &discordgo.MessageEmbed{ + embeds[id] = &channel.MessageEmbed{ Title: s, Description: "Erreur : impossible de récupérer la liste", Color: 0x831010, } return } - embeds[id] = &discordgo.MessageEmbed{ + embeds[id] = &channel.MessageEmbed{ Title: s, Description: genTopsMessage(tops), Color: 0x10E6AD, -- cgit v1.2.3 From e42ecdd7154d740800ef392c6318220944b55a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 13 Sep 2025 21:31:16 +0200 Subject: build(gokord): use latest version --- commands/config.go | 5 ++--- commands/credits.go | 5 ++--- commands/rank.go | 28 +++++++--------------------- commands/reset.go | 15 +++++++-------- commands/stats.go | 26 +++++++++++++------------- commands/top.go | 15 +++++++-------- 6 files changed, 38 insertions(+), 56 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index 838f7e9..cc1e942 100644 --- a/commands/config.go +++ b/commands/config.go @@ -7,7 +7,6 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/config" "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" ) @@ -15,7 +14,7 @@ const ( ConfigModify = "config_modify" ) -func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Config(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { cfg := config.GetGuildConfig(i.GuildID) roles := "" l := len(cfg.XpRoles) - 1 @@ -82,6 +81,6 @@ func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa ) err := resp.SetMessage(msg).IsEphemeral().Send() if err != nil { - logger.Alert("config/guild.go - Sending config", err.Error()) + s.LogError(err, "sending config") } } diff --git a/commands/credits.go b/commands/credits.go index d58547e..e5fd711 100644 --- a/commands/credits.go +++ b/commands/credits.go @@ -3,11 +3,10 @@ package commands import ( "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" ) -func Credits(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Credits(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { msg := "**Les Copaings**, le bot gérant les serveurs privés de [anhgelus]().\n" msg += "Code source : \n\n" msg += "Host du bot : " + gokord.BaseCfg.GetAuthor() + ".\n\n" @@ -15,6 +14,6 @@ func Credits(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionM msg += "- [Inter]()" err := resp.SetMessage(msg).Send() if err != nil { - logger.Alert("commands/credits.go - Sending credits", err.Error(), "guild_id", i.GuildID) + s.LogError(err, "sending credits") } } diff --git a/commands/rank.go b/commands/rank.go index 0adfde6..d3a9f70 100644 --- a/commands/rank.go +++ b/commands/rank.go @@ -6,7 +6,6 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" ) @@ -20,22 +19,16 @@ func Rank(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.Optio if u.Bot { err = resp.SetMessage("Imagine si les bots avaient un niveau :rolling_eyes:").IsEphemeral().Send() if err != nil { - logger.Alert("commands/rank.go - Reply error user is a bot", err.Error()) + s.LogError(err, "reply error user is a bot") } + return } m, err = s.GuildAPI().Member(i.GuildID, u.ID) if err != nil { - logger.Alert( - "commands/rank.go - Fetching guild member", - err.Error(), - "discord_id", - u.ID, - "guild_id", - i.GuildID, - ) + s.LogError(err, "Fetching guild member %s in %s", u.Username, i.GuildID) err = resp.SetMessage("Erreur : impossible de récupérer le membre").IsEphemeral().Send() if err != nil { - logger.Alert("commands/rank.go - Reply error fetching guild member", err.Error()) + s.LogError(err, "reply error fetching guild member") } return } @@ -44,17 +37,10 @@ func Rank(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.Optio } xp, err := c.GetXP() if err != nil { - logger.Alert( - "commands/rank.go - Fetching xp", - err.Error(), - "discord_id", - c.ID, - "guild_id", - i.GuildID, - ) + s.LogError(err, "fetching xp for copaing %s in %s", c.ID, i.GuildID) err = resp.SetMessage("Erreur : impossible de récupérer l'XP").IsEphemeral().Send() if err != nil { - logger.Alert("commands/rank.go - Reply error fetching xp", err.Error()) + s.LogError(err, "reply error fetching xp") } return } @@ -68,6 +54,6 @@ func Rank(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.Optio nxtLvlXP-xp, )).Send() if err != nil { - logger.Alert("commands/rank.go - Sending rank", err.Error()) + s.LogError(err, "sending rank") } } diff --git a/commands/reset.go b/commands/reset.go index f50bb21..77561c1 100644 --- a/commands/reset.go +++ b/commands/reset.go @@ -4,15 +4,14 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" ) -func Reset(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Reset(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { var copaings []*user.Copaing gokord.DB.Where("guild_id = ?", i.GuildID).Delete(&copaings) if err := resp.IsEphemeral().SetMessage("L'XP a été reset.").Send(); err != nil { - logger.Alert("commands/reset.go - Sending success (all)", err.Error()) + s.LogError(err, "sending reset success") } } @@ -21,26 +20,26 @@ func ResetUser(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd. v, ok := optMap["user"] if !ok { if err := resp.SetMessage("Le user n'a pas été renseigné.").Send(); err != nil { - logger.Alert("commands/reset.go - Copaing not set", err.Error()) + s.LogError(err, "sending error copaing not set") } return } m := v.UserValue(s.UserAPI()) if m.Bot { if err := resp.SetMessage("Les bots n'ont pas de niveau :upside_down:").Send(); err != nil { - logger.Alert("commands/reset.go - Copaing not set", err.Error()) + s.LogError(err, "sending error bot does not have xp") } return } err := user.GetCopaing(m.ID, i.GuildID).Delete() if err != nil { - logger.Alert("commands/reset.go - Copaing not deleted", err.Error(), "discord_id", m.ID, "guild_id", i.GuildID) + s.LogError(err, "deleting copaings %s in %s", m.Username, i.GuildID) err = resp.SetMessage("Erreur : impossible de reset l'utilisateur").Send() if err != nil { - logger.Alert("commands/reset.go - Error deleting", err.Error()) + s.LogError(err, "sending error while deleting") } } if err = resp.SetMessage("Le user bien été reset.").Send(); err != nil { - logger.Alert("commands/reset.go - Sending success (user)", err.Error()) + s.LogError(err, "sending reset success") } } diff --git a/commands/stats.go b/commands/stats.go index 1a7a379..e2c2ba4 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -15,7 +15,6 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" "github.com/jackc/pgx/v5/pgtype" discordgo "github.com/nyttikord/gokord" "github.com/nyttikord/gokord/channel" @@ -53,7 +52,7 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM if in < 1 || uint(in) > cfg.DaysXPRemains { msg := fmt.Sprintf("Nombre de jours invalide. Il doit être strictement positif et inférieur à %d", cfg.DaysXPRemains) if err := resp.SetMessage(msg).IsEphemeral().Send(); err != nil { - logger.Alert("commands/stats.go - Sending invalid days", err.Error()) + s.LogError(err, "sending error invalid days") } return } @@ -61,7 +60,7 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM } err := resp.IsDeferred().Send() if err != nil { - logger.Alert("commands/stats.go - Sending deferred", err.Error()) + s.LogError(err, "sending deferred") return } go func() { @@ -72,15 +71,16 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM w, err = statsAll(s, i, days) } if err != nil { + s.LogError(err, "generating stats in %s", i.GuildID) if err = resp.IsEphemeral().SetMessage("Il y a eu une erreur...").Send(); err != nil { - logger.Alert("commands/stats.go - Sending error occurred", err.Error()) + s.LogError(err, "sending error occurred") } return } b := new(bytes.Buffer) _, err = w.WriteTo(b) if err != nil { - logger.Alert("commands/stats.go - Writing png", err.Error()) + s.LogError(err, "writing png") } err = resp.AddFile(&channel.File{ Name: "plot.png", @@ -88,7 +88,7 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM Reader: b, }).Send() if err != nil { - logger.Alert("commands/stats.go - Sending response", err.Error()) + s.LogError(err, "sending stats") } }() } @@ -117,7 +117,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS if gokord.Debug { var rawCopaingData []*user.CopaingXP if err := execSql("SELECT * FROM copaing_xps ", "").Scan(&rawCopaingData).Error; err != nil { - logger.Alert("commands/stats.go - Fetching result", err.Error()) + s.LogError(err, "fetching result") return nil, err } rawData = make([]*data, len(rawCopaingData)) @@ -133,7 +133,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS if err := execSql( `SELECT "created_at"::date::text, sum("xp") as xp, "copaing_id" FROM copaing_xps `, ` GROUP BY "created_at"::date, "copaing_id"`, ).Scan(&rawDbData).Error; err != nil { - logger.Alert("commands/stats.go - Fetching result", err.Error()) + s.LogError(err, "fetching result") return nil, err } rawData = make([]*data, len(rawDbData)) @@ -155,10 +155,10 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS var cp user.Copaing if err := gokord.DB.First(&cp, raw.CopaingID).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Alert("commands/stats.go - Finding copaing", err.Error(), "id", raw.CopaingID) + s.LogError(err, "finding copaing %d", raw.CopaingID) return nil, err } - logger.Warn("Copaing not found, skipping entry", "old_id", raw.CopaingID) + s.LogWarn("Copaing %d not found, skipping", raw.CopaingID) continue } copaings[raw.CopaingID] = &cp @@ -202,7 +202,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings for in, c := range copaings { m, err := s.GuildAPI().Member(i.GuildID, c.DiscordID) if err != nil { - logger.Alert("commands/stats.go - Fetching guild member", err.Error()) + s.LogError(err, "fetching guild member") return nil, err } slices.SortFunc(stats[in], func(a, b plotter.XY) int { @@ -216,7 +216,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings }) l, _, err := plotter.NewLinePoints(plotter.XYs(stats[in])) if err != nil { - logger.Alert("commands/stats.go - Adding line points", err.Error()) + s.LogError(err, "adding line points") return nil, err } l.Color = colors[cnt%len(colors)] @@ -226,7 +226,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings } w, err := p.WriterTo(8*vg.Inch, 6*vg.Inch, "png") if err != nil { - logger.Alert("commands/stats.go - Generating png", err.Error()) + s.LogError(err, "generating png") return nil, err } return w, nil diff --git a/commands/top.go b/commands/top.go index 21a1456..195ee9b 100644 --- a/commands/top.go +++ b/commands/top.go @@ -8,34 +8,33 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord/cmd" - "github.com/anhgelus/gokord/logger" discordgo "github.com/nyttikord/gokord" "github.com/nyttikord/gokord/channel" ) -func Top(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Top(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { err := resp.IsDeferred().Send() if err != nil { - logger.Alert("commands/top.go - Sending deferred", err.Error()) + s.LogError(err, "sending deferred") return } embeds := make([]*channel.MessageEmbed, 3) wg := sync.WaitGroup{} - fn := func(s string, n uint, d int, id int) { + fn := func(str string, n uint, d int, id int) { defer wg.Done() tops, err := user.GetBestXP(i.GuildID, n, d) if err != nil { - logger.Alert("commands/top.go - Fetching best xp", err.Error(), "n", n, "d", d, "id", id, "guild_id", i.GuildID) + s.LogError(err, "fetching best xp, n: %d, d: %d, id: %d, guild: %s", n, d, id, i.GuildID) embeds[id] = &channel.MessageEmbed{ - Title: s, + Title: str, Description: "Erreur : impossible de récupérer la liste", Color: 0x831010, } return } embeds[id] = &channel.MessageEmbed{ - Title: s, + Title: str, Description: genTopsMessage(tops), Color: 0x10E6AD, } @@ -60,7 +59,7 @@ func Top(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, } err = resp.Send() if err != nil { - logger.Alert("commands/top.go - Sending response top", err.Error()) + s.LogError(err, "sending response top") } }() } -- cgit v1.2.3 From 24519b76b48f521f1ef4c7e5e038574eaa66ebcd Mon Sep 17 00:00:00 2001 From: ascpial Date: Sat, 13 Sep 2025 21:40:24 +0200 Subject: feat(config): improve /config look and xp_role usability --- commands/config.go | 120 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 35 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index cc1e942..1c2db8c 100644 --- a/commands/config.go +++ b/commands/config.go @@ -8,13 +8,19 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "github.com/anhgelus/gokord/cmd" discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/channel" + "github.com/nyttikord/gokord/component" + "github.com/nyttikord/gokord/discord/types" + "github.com/nyttikord/gokord/emoji" + "github.com/nyttikord/gokord/interaction" ) const ( ConfigModify = "config_modify" + OpenConfig = "config" ) -func Config(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { cfg := config.GetGuildConfig(i.GuildID) roles := "" l := len(cfg.XpRoles) - 1 @@ -47,40 +53,84 @@ func Config(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa } else { defaultChan = fmt.Sprintf("<#%s>", cfg.FallbackChannel) } - //comp := component.New(). - // Add(component.NewActionRow().Add(component.NewStringSelect(ConfigModify). - // SetPlaceholder("Modifier..."). - // AddOption( - // component.NewSelectOption("Rôles liés à l'XP", config.ModifyXpRole). - // SetDescription("Gère les rôles liés à l'XP"). - // SetEmoji(&discordgo.ComponentEmoji{Name: "🏅"}), - // ). - // AddOption( - // component.NewSelectOption("Salons désactivés", config.ModifyDisChannel). - // SetDescription("Gère les salons désactivés"). - // SetEmoji(&discordgo.ComponentEmoji{Name: "❌"}), - // ). - // AddOption( - // // I don't have a better idea for this... - // component.NewSelectOption("Salons par défaut", config.ModifyFallbackChannel). - // SetDescription("Spécifie le salon par défaut"). - // SetEmoji(&discordgo.ComponentEmoji{Name: "💾"}), - // ). - // AddOption( - // component.NewSelectOption("Temps avec la réduction", config.ModifyTimeReduce). - // SetDescription("Gère le temps avant la réduction d'XP"). - // SetEmoji(&discordgo.ComponentEmoji{Name: "⌛"}), - // ), - // )) - msg := fmt.Sprintf( - "# Config\n**Salon par défaut**\n%s\n\n**Rôles liés aux niveaux**\n%s\n\n**Salons désactivés**\n%s\n\n**Jours avant la réduction**\n%d", - defaultChan, - roles, - chans, - cfg.DaysXPRemains, - ) - err := resp.SetMessage(msg).IsEphemeral().Send() + content := []component.Component{ + &component.Container{ + Components: []component.Message{ + &component.TextDisplay{Content: "## Configuration"}, + &component.Separator{}, + &component.TextDisplay{Content: "**Salon par défaut**\n" + defaultChan}, + &component.TextDisplay{Content: "**Rôles de niveau**\n" + roles}, + &component.TextDisplay{Content: "**Salons ignorés**\n" + chans}, + &component.TextDisplay{ + Content: fmt.Sprintf("**Jours avant la réduction**\n%d jours", cfg.DaysXPRemains), + }, + &component.ActionsRow{ + Components: []component.Message{ + &component.SelectMenu{ + MenuType: types.SelectMenuString, + Placeholder: "Gestion des paramètres", + CustomID: ConfigModify, + Options: []component.SelectMenuOption{ + { + Label: "Salons par défaut", + Value: config.ModifyFallbackChannel, + Emoji: &emoji.Component{Name: "📣"}, + }, + { + Label: "Rôles de niveaux", + Value: config.ModifyXpRole, + Emoji: &emoji.Component{Name: "🏅"}, + }, + { + Label: "Salons ignorés", + Value: config.ModifyDisChannel, + Emoji: &emoji.Component{Name: "🫣"}, + }, + { + Label: "Temps avant la réduction d'expérience", + Value: config.ModifyTimeReduce, + Emoji: &emoji.Component{Name: "📉"}, + }, + }, + }, + }, + }, + }, + }, + } + return &interaction.Response{ + Type: types.InteractionResponseChannelMessageWithSource, + Data: &interaction.ResponseData{ + Components: content, + Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2, + }, + } +} + +func ConfigCommand( + session *discordgo.Session, + i *discordgo.InteractionCreate, + _ cmd.OptionMap, + resp *cmd.ResponseBuilder, +) { + err := session.InteractionAPI().Respond(i.Interaction, ConfigResponse(i)) + + if err != nil { + session.LogError(err, "config/guild.go - Sending config") + } +} + +func ConfigMessageComponent( + session *discordgo.Session, + i *discordgo.InteractionCreate, + _ interaction.MessageComponentData, + resp *cmd.ResponseBuilder, +) { + response := ConfigResponse(i) + response.Type = types.InteractionResponseUpdateMessage + err := session.InteractionAPI().Respond(i.Interaction, response) + if err != nil { - s.LogError(err, "sending config") + session.LogError(err, "sending config") } } -- cgit v1.2.3 From 398213f2088b775787d4c022b5704366fdfe1aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Fri, 19 Sep 2025 18:42:07 +0200 Subject: build(gokord): bump to latest nightly --- commands/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index 1c2db8c..d1e144d 100644 --- a/commands/config.go +++ b/commands/config.go @@ -123,8 +123,8 @@ func ConfigCommand( func ConfigMessageComponent( session *discordgo.Session, i *discordgo.InteractionCreate, - _ interaction.MessageComponentData, - resp *cmd.ResponseBuilder, + _ *interaction.MessageComponentData, + _ *cmd.ResponseBuilder, ) { response := ConfigResponse(i) response.Type = types.InteractionResponseUpdateMessage -- cgit v1.2.3 From 8d6fa726069bd5364ada1521b400bb5eb7865d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 20 Sep 2025 14:01:39 +0200 Subject: feat(stats): custom scale for Y to show level --- commands/stats.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'commands') diff --git a/commands/stats.go b/commands/stats.go index e2c2ba4..3156fd9 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -47,6 +47,9 @@ var colors = []color.RGBA{ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) { cfg := config.GetGuildConfig(i.GuildID) days := 15 + if gokord.Debug { + days = 90 + } if v, ok := opt["days"]; ok { in := v.IntValue() if in < 1 || uint(in) > cfg.DaysXPRemains { @@ -195,6 +198,7 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings p.X.Label.Text = "Secondes" } p.Y.Label.Text = "XP" + p.Y.Scale = exp.LevelScale{} p.Add(plotter.NewGrid()) -- cgit v1.2.3 From a0e93b4e031857e7379e2ab2d7bdae24561f4e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 20 Sep 2025 15:39:51 +0200 Subject: feat(stats): better style for the graph --- commands/stats.go | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'commands') diff --git a/commands/stats.go b/commands/stats.go index 3156fd9..fcb0c29 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -21,6 +21,7 @@ import ( "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" + "gonum.org/v1/plot/vg/draw" "gorm.io/gorm" ) @@ -172,7 +173,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS pts = make([]plotter.XY, days+1) for i := 0; i < len(pts); i++ { pts[i] = plotter.XY{ - X: float64(i - int(days)), + X: float64(i - days), Y: 0, } } @@ -181,6 +182,8 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS t := raw.CreatedAt.Unix() - now if !gokord.Debug { t = int64(math.Ceil(float64(t) / (24 * 60 * 60))) + } else { + t = int64(math.Ceil(float64(t) / exp.DebugFactor)) } pts[int64(days)+t] = plotter.XY{ // because t <= 0 X: float64(t), @@ -192,10 +195,22 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings map[int]*user.Copaing, stats map[int][]plotter.XY) (io.WriterTo, error) { p := plot.New() - p.Title.Text = "Évolution de l'XP" + fontSizeTitle := vg.Length(16) + fontSize := vg.Length(12) + // set font size + p.Title.TextStyle.Font.Size = fontSizeTitle + p.X.Label.TextStyle.Font.Size = fontSizeTitle + p.Y.Label.TextStyle.Font.Size = fontSizeTitle + p.Legend.TextStyle.Font.Size = fontSize + // set legend style + p.Legend.YPosition = draw.PosTop + p.Legend.Top = true + p.Legend.Padding = vg.Points(2) + // set scales + p.Title.Text = "XP gagnées" p.X.Label.Text = "Jours" if gokord.Debug { - p.X.Label.Text = "Secondes" + p.X.Label.Text = fmt.Sprintf("%d secondes", exp.DebugFactor) } p.Y.Label.Text = "XP" p.Y.Scale = exp.LevelScale{} @@ -224,11 +239,19 @@ func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings return nil, err } l.Color = colors[cnt%len(colors)] + if len(copaings) < 4 { + l.Width = vg.Points(2) + } + if cnt/len(colors) > 0 { + size := 7 / min(cnt/len(colors), 7) + l.Dashes = []vg.Length{vg.Points(float64(size)), vg.Points(float64(size))} + } p.Add(l) p.Legend.Add(m.DisplayName(), l) cnt++ } - w, err := p.WriterTo(8*vg.Inch, 6*vg.Inch, "png") + w, err := p.WriterTo(12*vg.Inch, 8*vg.Inch, "png") + if err != nil { s.LogError(err, "generating png") return nil, err -- cgit v1.2.3 From 8a7189c3835a431b7fc16b189162f6f343e80b84 Mon Sep 17 00:00:00 2001 From: ascpial Date: Sat, 20 Sep 2025 23:33:29 +0200 Subject: feat(config): finish upgrading config --- commands/config.go | 128 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 50 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index d1e144d..5a2f763 100644 --- a/commands/config.go +++ b/commands/config.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "sort" "strings" "git.anhgelus.world/anhgelus/les-copaings-bot/config" @@ -11,7 +12,6 @@ import ( "github.com/nyttikord/gokord/channel" "github.com/nyttikord/gokord/component" "github.com/nyttikord/gokord/discord/types" - "github.com/nyttikord/gokord/emoji" "github.com/nyttikord/gokord/interaction" ) @@ -24,6 +24,9 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { cfg := config.GetGuildConfig(i.GuildID) roles := "" l := len(cfg.XpRoles) - 1 + sort.Slice(cfg.XpRoles, func(i, j int) bool { + return cfg.XpRoles[i].XP > cfg.XpRoles[j].XP + }) for i, r := range cfg.XpRoles { if i == l { roles += fmt.Sprintf("> Niveau %d - <@&%s>", exp.Level(r.XP), r.RoleID) @@ -32,68 +35,78 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { } } if len(roles) == 0 { - roles = "Aucun rôle configuré :(" + roles = "Aucun rôle configuré" } disChans := strings.Split(cfg.DisabledChannels, ";") - l = len(disChans) - 1 - chans := "" - for i, c := range disChans { - if i == l-1 { - chans += fmt.Sprintf("> <#%s>", c) - } else if i != l { - chans += fmt.Sprintf("> <#%s>\n", c) + disChansDefault := []component.SelectMenuDefaultValue{} + for _, c := range disChans { + if c != "" { + disChansDefault = append(disChansDefault, component.SelectMenuDefaultValue{ + ID: c, + Type: types.SelectMenuDefaultValueChannel, + }) } } - if len(chans) == 0 { - chans = "Aucun salon désactivé :)" - } - var defaultChan string - if len(cfg.FallbackChannel) == 0 { - defaultChan = "Pas de valeur" - } else { - defaultChan = fmt.Sprintf("<#%s>", cfg.FallbackChannel) + defaultChan := []component.SelectMenuDefaultValue{} + if len(cfg.FallbackChannel) > 0 { + defaultChan = append(defaultChan, component.SelectMenuDefaultValue{ + ID: cfg.FallbackChannel, + Type: types.SelectMenuDefaultValueChannel, + }) } + zero := 0 content := []component.Component{ &component.Container{ Components: []component.Message{ &component.TextDisplay{Content: "## Configuration"}, &component.Separator{}, - &component.TextDisplay{Content: "**Salon par défaut**\n" + defaultChan}, - &component.TextDisplay{Content: "**Rôles de niveau**\n" + roles}, - &component.TextDisplay{Content: "**Salons ignorés**\n" + chans}, - &component.TextDisplay{ - Content: fmt.Sprintf("**Jours avant la réduction**\n%d jours", cfg.DaysXPRemains), + &component.TextDisplay{Content: "**Salons par défaut**\n-# Les niveaux obtenue grâce à un appel sont affichés ici"}, + &component.ActionsRow{ + Components: []component.Message{ + &component.SelectMenu{ + MenuType: types.SelectMenuChannel, + CustomID: config.ModifyFallbackChannel, + Placeholder: "Pas de salon par défaut", + MinValues: &zero, + MaxValues: 1, + DefaultValues: defaultChan, + }, + }, }, + &component.TextDisplay{Content: "**Salons désactivé**\n-# Les messages ne donneront pas d'expérience dans ces salons"}, &component.ActionsRow{ Components: []component.Message{ &component.SelectMenu{ - MenuType: types.SelectMenuString, - Placeholder: "Gestion des paramètres", - CustomID: ConfigModify, - Options: []component.SelectMenuOption{ - { - Label: "Salons par défaut", - Value: config.ModifyFallbackChannel, - Emoji: &emoji.Component{Name: "📣"}, - }, - { - Label: "Rôles de niveaux", - Value: config.ModifyXpRole, - Emoji: &emoji.Component{Name: "🏅"}, - }, - { - Label: "Salons ignorés", - Value: config.ModifyDisChannel, - Emoji: &emoji.Component{Name: "🫣"}, - }, - { - Label: "Temps avant la réduction d'expérience", - Value: config.ModifyTimeReduce, - Emoji: &emoji.Component{Name: "📉"}, - }, - }, + MenuType: types.SelectMenuChannel, + CustomID: config.ModifyDisChannel, + Placeholder: "Pas de salons désactivé", + MinValues: &zero, + MaxValues: 25, + DefaultValues: disChansDefault, + }, + }, + }, + &component.Section{ + Components: []component.Message{ + &component.TextDisplay{Content: "**Rôles de niveau**\n" + roles}, + }, + Accessory: &component.Button{ + Label: "Modifier", + Style: component.ButtonStyleSecondary, + CustomID: config.ModifyXpRole, + }, + }, + &component.Section{ + Components: []component.Message{ + &component.TextDisplay{ + Content: fmt.Sprintf("**Jours avant la réduction**\n-# Seule l'expérience gagnée les x derniers jours est comptabilisée dans le niveau par défaut\n%d jours", cfg.DaysXPRemains), }, }, + Accessory: &component.Button{ + Label: "Modifier", + Style: component.ButtonStyleSecondary, + CustomID: config.ModifyTimeReduce, + }, }, }, }, @@ -121,16 +134,31 @@ func ConfigCommand( } func ConfigMessageComponent( - session *discordgo.Session, + s *discordgo.Session, i *discordgo.InteractionCreate, _ *interaction.MessageComponentData, _ *cmd.ResponseBuilder, ) { response := ConfigResponse(i) response.Type = types.InteractionResponseUpdateMessage - err := session.InteractionAPI().Respond(i.Interaction, response) + err := s.InteractionAPI().Respond(i.Interaction, response) + + if err != nil { + s.LogError(err, "sending config") + } +} + +func ConfigModal( + s *discordgo.Session, + i *discordgo.InteractionCreate, + _ *interaction.ModalSubmitData, + resp *cmd.ResponseBuilder, +) { + response := ConfigResponse(i) + response.Type = types.InteractionResponseUpdateMessage + err := s.InteractionAPI().Respond(i.Interaction, response) if err != nil { - session.LogError(err, "sending config") + s.LogError(err, "sending config") } } -- cgit v1.2.3 From beaea94172f16c350515cb28941f3d5a2101b690 Mon Sep 17 00:00:00 2001 From: ascpial Date: Sun, 21 Sep 2025 00:18:15 +0200 Subject: perf(config): use more modern slices.SortFunc --- commands/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index 5a2f763..fc15a5c 100644 --- a/commands/config.go +++ b/commands/config.go @@ -2,7 +2,7 @@ package commands import ( "fmt" - "sort" + "slices" "strings" "git.anhgelus.world/anhgelus/les-copaings-bot/config" @@ -24,8 +24,8 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { cfg := config.GetGuildConfig(i.GuildID) roles := "" l := len(cfg.XpRoles) - 1 - sort.Slice(cfg.XpRoles, func(i, j int) bool { - return cfg.XpRoles[i].XP > cfg.XpRoles[j].XP + slices.SortFunc(cfg.XpRoles, func(xp1, xp2 config.XpRole) int { + return int(xp2.XP) - int(xp1.XP) }) for i, r := range cfg.XpRoles { if i == l { -- cgit v1.2.3 From b61a834b608df3d5e617912eefb28924ef3a46df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Fri, 26 Sep 2025 18:30:57 +0200 Subject: build(gokord): bump to latest nightly --- commands/config.go | 27 ++++++++++++++------------- commands/credits.go | 5 +++-- commands/rank.go | 5 +++-- commands/reset.go | 7 ++++--- commands/stats.go | 13 +++++++------ commands/top.go | 5 +++-- 6 files changed, 34 insertions(+), 28 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index fc15a5c..7ffd4af 100644 --- a/commands/config.go +++ b/commands/config.go @@ -8,10 +8,11 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/config" "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "github.com/anhgelus/gokord/cmd" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/channel" "github.com/nyttikord/gokord/component" "github.com/nyttikord/gokord/discord/types" + "github.com/nyttikord/gokord/event" "github.com/nyttikord/gokord/interaction" ) @@ -20,7 +21,7 @@ const ( OpenConfig = "config" ) -func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { +func ConfigResponse(i *event.InteractionCreate) *interaction.Response { cfg := config.GetGuildConfig(i.GuildID) roles := "" l := len(cfg.XpRoles) - 1 @@ -38,7 +39,7 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { roles = "Aucun rôle configuré" } disChans := strings.Split(cfg.DisabledChannels, ";") - disChansDefault := []component.SelectMenuDefaultValue{} + var disChansDefault []component.SelectMenuDefaultValue for _, c := range disChans { if c != "" { disChansDefault = append(disChansDefault, component.SelectMenuDefaultValue{ @@ -47,7 +48,7 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { }) } } - defaultChan := []component.SelectMenuDefaultValue{} + var defaultChan []component.SelectMenuDefaultValue if len(cfg.FallbackChannel) > 0 { defaultChan = append(defaultChan, component.SelectMenuDefaultValue{ ID: cfg.FallbackChannel, @@ -121,21 +122,21 @@ func ConfigResponse(i *discordgo.InteractionCreate) *interaction.Response { } func ConfigCommand( - session *discordgo.Session, - i *discordgo.InteractionCreate, + s bot.Session, + i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder, ) { - err := session.InteractionAPI().Respond(i.Interaction, ConfigResponse(i)) + err := s.InteractionAPI().Respond(i.Interaction, ConfigResponse(i)) if err != nil { - session.LogError(err, "config/guild.go - Sending config") + s.LogError(err, "config/guild.go - Sending config") } } func ConfigMessageComponent( - s *discordgo.Session, - i *discordgo.InteractionCreate, + s bot.Session, + i *event.InteractionCreate, _ *interaction.MessageComponentData, _ *cmd.ResponseBuilder, ) { @@ -149,10 +150,10 @@ func ConfigMessageComponent( } func ConfigModal( - s *discordgo.Session, - i *discordgo.InteractionCreate, + s bot.Session, + i *event.InteractionCreate, _ *interaction.ModalSubmitData, - resp *cmd.ResponseBuilder, + _ *cmd.ResponseBuilder, ) { response := ConfigResponse(i) response.Type = types.InteractionResponseUpdateMessage diff --git a/commands/credits.go b/commands/credits.go index e5fd711..b303834 100644 --- a/commands/credits.go +++ b/commands/credits.go @@ -3,10 +3,11 @@ package commands import ( "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" + "github.com/nyttikord/gokord/event" ) -func Credits(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Credits(s bot.Session, _ *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { msg := "**Les Copaings**, le bot gérant les serveurs privés de [anhgelus]().\n" msg += "Code source : \n\n" msg += "Host du bot : " + gokord.BaseCfg.GetAuthor() + ".\n\n" diff --git a/commands/rank.go b/commands/rank.go index d3a9f70..8f3090f 100644 --- a/commands/rank.go +++ b/commands/rank.go @@ -6,10 +6,11 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord/cmd" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" + "github.com/nyttikord/gokord/event" ) -func Rank(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Rank(s bot.Session, i *event.InteractionCreate, optMap cmd.OptionMap, resp *cmd.ResponseBuilder) { c := user.GetCopaing(i.Member.User.ID, i.GuildID) // current user = member who used /rank msg := "Votre niveau" m := i.Member diff --git a/commands/reset.go b/commands/reset.go index 77561c1..7caa238 100644 --- a/commands/reset.go +++ b/commands/reset.go @@ -4,10 +4,11 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" + "github.com/nyttikord/gokord/event" ) -func Reset(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Reset(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { var copaings []*user.Copaing gokord.DB.Where("guild_id = ?", i.GuildID).Delete(&copaings) if err := resp.IsEphemeral().SetMessage("L'XP a été reset.").Send(); err != nil { @@ -15,7 +16,7 @@ func Reset(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap } } -func ResetUser(s *discordgo.Session, i *discordgo.InteractionCreate, optMap cmd.OptionMap, resp *cmd.ResponseBuilder) { +func ResetUser(s bot.Session, i *event.InteractionCreate, optMap cmd.OptionMap, resp *cmd.ResponseBuilder) { resp.IsEphemeral() v, ok := optMap["user"] if !ok { diff --git a/commands/stats.go b/commands/stats.go index fcb0c29..2c22f0d 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -16,8 +16,9 @@ import ( "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/cmd" "github.com/jackc/pgx/v5/pgtype" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/channel" + "github.com/nyttikord/gokord/event" "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" @@ -45,7 +46,7 @@ var colors = []color.RGBA{ {193, 18, 31, 255}, } -func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Stats(s bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) { cfg := config.GetGuildConfig(i.GuildID) days := 15 if gokord.Debug { @@ -97,13 +98,13 @@ func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionM }() } -func statsAll(s *discordgo.Session, i *discordgo.InteractionCreate, days int) (io.WriterTo, error) { +func statsAll(s bot.Session, i *event.InteractionCreate, days int) (io.WriterTo, error) { return stats(s, i, days, func(before, after string) *gorm.DB { return gokord.DB.Raw(before+"WHERE guild_id = ? and created_at > ?"+after, i.GuildID, exp.TimeStampNDaysBefore(uint(days))) }) } -func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days int, discordID string) (io.WriterTo, error) { +func statsMember(s bot.Session, i *event.InteractionCreate, days int, discordID string) (io.WriterTo, error) { _, err := s.GuildAPI().Member(i.GuildID, discordID) if err != nil { return nil, err @@ -116,7 +117,7 @@ func statsMember(s *discordgo.Session, i *discordgo.InteractionCreate, days int, }) } -func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execSql func(before, after string) *gorm.DB) (io.WriterTo, error) { +func stats(s bot.Session, i *event.InteractionCreate, days int, execSql func(before, after string) *gorm.DB) (io.WriterTo, error) { var rawData []*data if gokord.Debug { var rawCopaingData []*user.CopaingXP @@ -193,7 +194,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days int, execS return generatePlot(s, i, copaings, stats) } -func generatePlot(s *discordgo.Session, i *discordgo.InteractionCreate, copaings map[int]*user.Copaing, stats map[int][]plotter.XY) (io.WriterTo, error) { +func generatePlot(s bot.Session, i *event.InteractionCreate, copaings map[int]*user.Copaing, stats map[int][]plotter.XY) (io.WriterTo, error) { p := plot.New() fontSizeTitle := vg.Length(16) fontSize := vg.Length(12) diff --git a/commands/top.go b/commands/top.go index 195ee9b..751f7fa 100644 --- a/commands/top.go +++ b/commands/top.go @@ -8,11 +8,12 @@ import ( "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "git.anhgelus.world/anhgelus/les-copaings-bot/user" "github.com/anhgelus/gokord/cmd" - discordgo "github.com/nyttikord/gokord" + "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/channel" + "github.com/nyttikord/gokord/event" ) -func Top(s *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { +func Top(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { err := resp.IsDeferred().Send() if err != nil { s.LogError(err, "sending deferred") -- cgit v1.2.3 From cfdba5f417bb31aac564d13becc09874f17d075d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 27 Sep 2025 17:34:38 +0200 Subject: build(gokord): bump to latest nightly --- commands/config.go | 6 +++--- commands/credits.go | 2 +- commands/rank.go | 14 +++++++------- commands/reset.go | 12 ++++++------ commands/stats.go | 31 ++++++++++++------------------- commands/top.go | 8 ++++---- 6 files changed, 33 insertions(+), 40 deletions(-) (limited to 'commands') diff --git a/commands/config.go b/commands/config.go index 7ffd4af..336e66a 100644 --- a/commands/config.go +++ b/commands/config.go @@ -130,7 +130,7 @@ func ConfigCommand( err := s.InteractionAPI().Respond(i.Interaction, ConfigResponse(i)) if err != nil { - s.LogError(err, "config/guild.go - Sending config") + s.Logger().Error("sending config", "error", err) } } @@ -145,7 +145,7 @@ func ConfigMessageComponent( err := s.InteractionAPI().Respond(i.Interaction, response) if err != nil { - s.LogError(err, "sending config") + s.Logger().Error("sending config", "error", err) } } @@ -160,6 +160,6 @@ func ConfigModal( err := s.InteractionAPI().Respond(i.Interaction, response) if err != nil { - s.LogError(err, "sending config") + s.Logger().Error("sending config", "error", err) } } diff --git a/commands/credits.go b/commands/credits.go index b303834..340ea57 100644 --- a/commands/credits.go +++ b/commands/credits.go @@ -15,6 +15,6 @@ func Credits(s bot.Session, _ *event.InteractionCreate, _ cmd.OptionMap, resp *c msg += "- [Inter]()" err := resp.SetMessage(msg).Send() if err != nil { - s.LogError(err, "sending credits") + s.Logger().Error("sending credits", "error", err) } } diff --git a/commands/rank.go b/commands/rank.go index 8f3090f..4080864 100644 --- a/commands/rank.go +++ b/commands/rank.go @@ -20,28 +20,28 @@ func Rank(s bot.Session, i *event.InteractionCreate, optMap cmd.OptionMap, resp if u.Bot { err = resp.SetMessage("Imagine si les bots avaient un niveau :rolling_eyes:").IsEphemeral().Send() if err != nil { - s.LogError(err, "reply error user is a bot") + s.Logger().Error("reply error user is a bot", "error", err) } return } m, err = s.GuildAPI().Member(i.GuildID, u.ID) if err != nil { - s.LogError(err, "Fetching guild member %s in %s", u.Username, i.GuildID) + s.Logger().Error("fetching guild member", "error", err, "user", u.Username, "guild", i.GuildID) err = resp.SetMessage("Erreur : impossible de récupérer le membre").IsEphemeral().Send() if err != nil { - s.LogError(err, "reply error fetching guild member") + s.Logger().Error("reply error fetching guild member", "error", err) } return } c = user.GetCopaing(u.ID, i.GuildID) // current user = member targeted by member who wrote /rank msg = fmt.Sprintf("Le niveau de %s", m.DisplayName()) } - xp, err := c.GetXP() + xp, err := c.GetXP(s.Logger()) if err != nil { - s.LogError(err, "fetching xp for copaing %s in %s", c.ID, i.GuildID) + s.Logger().Error("fetching xp", "error", err, "copaing", c.ID, "guild", i.GuildID) err = resp.SetMessage("Erreur : impossible de récupérer l'XP").IsEphemeral().Send() if err != nil { - s.LogError(err, "reply error fetching xp") + s.Logger().Error("reply error fetching xp", "error", err) } return } @@ -55,6 +55,6 @@ func Rank(s bot.Session, i *event.InteractionCreate, optMap cmd.OptionMap, resp nxtLvlXP-xp, )).Send() if err != nil { - s.LogError(err, "sending rank") + s.Logger().Error("sending rank", "error", err) } } diff --git a/commands/reset.go b/commands/reset.go index 7caa238..21bfeb7 100644 --- a/commands/reset.go +++ b/commands/reset.go @@ -12,7 +12,7 @@ func Reset(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd var copaings []*user.Copaing gokord.DB.Where("guild_id = ?", i.GuildID).Delete(&copaings) if err := resp.IsEphemeral().SetMessage("L'XP a été reset.").Send(); err != nil { - s.LogError(err, "sending reset success") + s.Logger().Error("sending reset success", "error", err) } } @@ -21,26 +21,26 @@ func ResetUser(s bot.Session, i *event.InteractionCreate, optMap cmd.OptionMap, v, ok := optMap["user"] if !ok { if err := resp.SetMessage("Le user n'a pas été renseigné.").Send(); err != nil { - s.LogError(err, "sending error copaing not set") + s.Logger().Error("sending error copaing not set", "error", err) } return } m := v.UserValue(s.UserAPI()) if m.Bot { if err := resp.SetMessage("Les bots n'ont pas de niveau :upside_down:").Send(); err != nil { - s.LogError(err, "sending error bot does not have xp") + s.Logger().Error("sending error bot does not have xp", "error", err) } return } err := user.GetCopaing(m.ID, i.GuildID).Delete() if err != nil { - s.LogError(err, "deleting copaings %s in %s", m.Username, i.GuildID) + s.Logger().Error("deleting copaing", "error", err, "user", m.Username, "guild", i.GuildID) err = resp.SetMessage("Erreur : impossible de reset l'utilisateur").Send() if err != nil { - s.LogError(err, "sending error while deleting") + s.Logger().Error("sending error while deleting", "error", err) } } if err = resp.SetMessage("Le user bien été reset.").Send(); err != nil { - s.LogError(err, "sending reset success") + s.Logger().Error("sending reset success", "error", err) } } diff --git a/commands/stats.go b/commands/stats.go index 2c22f0d..4fc35ae 100644 --- a/commands/stats.go +++ b/commands/stats.go @@ -57,7 +57,7 @@ func Stats(s bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *c if in < 1 || uint(in) > cfg.DaysXPRemains { msg := fmt.Sprintf("Nombre de jours invalide. Il doit être strictement positif et inférieur à %d", cfg.DaysXPRemains) if err := resp.SetMessage(msg).IsEphemeral().Send(); err != nil { - s.LogError(err, "sending error invalid days") + s.Logger().Error("sending error invalid days", "error", err) } return } @@ -65,7 +65,7 @@ func Stats(s bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *c } err := resp.IsDeferred().Send() if err != nil { - s.LogError(err, "sending deferred") + s.Logger().Error("sending deferred", "error", err) return } go func() { @@ -76,16 +76,16 @@ func Stats(s bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *c w, err = statsAll(s, i, days) } if err != nil { - s.LogError(err, "generating stats in %s", i.GuildID) + s.Logger().Error("generating stats", "error", err, "guild", i.GuildID) if err = resp.IsEphemeral().SetMessage("Il y a eu une erreur...").Send(); err != nil { - s.LogError(err, "sending error occurred") + s.Logger().Error("sending error occurred", "error", err) } return } b := new(bytes.Buffer) _, err = w.WriteTo(b) if err != nil { - s.LogError(err, "writing png") + s.Logger().Error("writing png", "error", err) } err = resp.AddFile(&channel.File{ Name: "plot.png", @@ -93,7 +93,7 @@ func Stats(s bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *c Reader: b, }).Send() if err != nil { - s.LogError(err, "sending stats") + s.Logger().Error("sending stats", "error", err) } }() } @@ -122,7 +122,7 @@ func stats(s bot.Session, i *event.InteractionCreate, days int, execSql func(bef if gokord.Debug { var rawCopaingData []*user.CopaingXP if err := execSql("SELECT * FROM copaing_xps ", "").Scan(&rawCopaingData).Error; err != nil { - s.LogError(err, "fetching result") + s.Logger().Error("fetching result", "error", err) return nil, err } rawData = make([]*data, len(rawCopaingData)) @@ -138,7 +138,7 @@ func stats(s bot.Session, i *event.InteractionCreate, days int, execSql func(bef if err := execSql( `SELECT "created_at"::date::text, sum("xp") as xp, "copaing_id" FROM copaing_xps `, ` GROUP BY "created_at"::date, "copaing_id"`, ).Scan(&rawDbData).Error; err != nil { - s.LogError(err, "fetching result") + s.Logger().Error("fetching result", "error", err) return nil, err } rawData = make([]*data, len(rawDbData)) @@ -160,10 +160,10 @@ func stats(s bot.Session, i *event.InteractionCreate, days int, execSql func(bef var cp user.Copaing if err := gokord.DB.First(&cp, raw.CopaingID).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { - s.LogError(err, "finding copaing %d", raw.CopaingID) + s.Logger().Error("finding copaing", "error", err, "copaing", raw.CopaingID) return nil, err } - s.LogWarn("Copaing %d not found, skipping", raw.CopaingID) + s.Logger().Warn("copaing not found, skipping", "copaing", raw.CopaingID) continue } copaings[raw.CopaingID] = &cp @@ -222,7 +222,7 @@ func generatePlot(s bot.Session, i *event.InteractionCreate, copaings map[int]*u for in, c := range copaings { m, err := s.GuildAPI().Member(i.GuildID, c.DiscordID) if err != nil { - s.LogError(err, "fetching guild member") + s.Logger().Error("fetching guild member", "error", err) return nil, err } slices.SortFunc(stats[in], func(a, b plotter.XY) int { @@ -236,7 +236,6 @@ func generatePlot(s bot.Session, i *event.InteractionCreate, copaings map[int]*u }) l, _, err := plotter.NewLinePoints(plotter.XYs(stats[in])) if err != nil { - s.LogError(err, "adding line points") return nil, err } l.Color = colors[cnt%len(colors)] @@ -251,11 +250,5 @@ func generatePlot(s bot.Session, i *event.InteractionCreate, copaings map[int]*u p.Legend.Add(m.DisplayName(), l) cnt++ } - w, err := p.WriterTo(12*vg.Inch, 8*vg.Inch, "png") - - if err != nil { - s.LogError(err, "generating png") - return nil, err - } - return w, nil + return p.WriterTo(12*vg.Inch, 8*vg.Inch, "png") } diff --git a/commands/top.go b/commands/top.go index 751f7fa..bb08144 100644 --- a/commands/top.go +++ b/commands/top.go @@ -16,7 +16,7 @@ import ( func Top(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) { err := resp.IsDeferred().Send() if err != nil { - s.LogError(err, "sending deferred") + s.Logger().Error("sending deferred", "error", err) return } embeds := make([]*channel.MessageEmbed, 3) @@ -24,9 +24,9 @@ func Top(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.R fn := func(str string, n uint, d int, id int) { defer wg.Done() - tops, err := user.GetBestXP(i.GuildID, n, d) + tops, err := user.GetBestXP(s.Logger(), i.GuildID, n, d) if err != nil { - s.LogError(err, "fetching best xp, n: %d, d: %d, id: %d, guild: %s", n, d, id, i.GuildID) + s.Logger().Error("fetching best xp", "error", err, "n", n, "d", d, "id", id, "guild", i.GuildID) embeds[id] = &channel.MessageEmbed{ Title: str, Description: "Erreur : impossible de récupérer la liste", @@ -60,7 +60,7 @@ func Top(s bot.Session, i *event.InteractionCreate, _ cmd.OptionMap, resp *cmd.R } err = resp.Send() if err != nil { - s.LogError(err, "sending response top") + s.Logger().Error("sending response top", "error", err) } }() } -- cgit v1.2.3