aboutsummaryrefslogtreecommitdiff
path: root/commands
diff options
context:
space:
mode:
authorWilliam Hergès <william@herges.fr>2025-09-27 18:23:27 +0200
committerWilliam Hergès <william@herges.fr>2025-09-27 18:23:27 +0200
commitb1d3bca64702e66b5ecfe5c9ea5f43aa9dc1d1e6 (patch)
tree67474ed704f529fe4941c179b7697b54099cc326 /commands
parentc46d1c34a29b10dac2a059b9d78e99a3d5d76f96 (diff)
parentcfdba5f417bb31aac564d13becc09874f17d075d (diff)
Merge branch 'main' into feat/xp-boostfeat/xp-boost
Diffstat (limited to 'commands')
-rw-r--r--commands/config.go216
-rw-r--r--commands/credits.go11
-rw-r--r--commands/rank.go39
-rw-r--r--commands/reset.go22
-rw-r--r--commands/stats.go118
-rw-r--r--commands/top.go27
6 files changed, 248 insertions, 185 deletions
diff --git a/commands/config.go b/commands/config.go
index c4644bc..336e66a 100644
--- a/commands/config.go
+++ b/commands/config.go
@@ -2,24 +2,32 @@ package commands
import (
"fmt"
+ "slices"
"strings"
"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"
+ "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"
)
const (
ConfigModify = "config_modify"
+ OpenConfig = "config"
)
-func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMap, resp *cmd.ResponseBuilder) {
+func ConfigResponse(i *event.InteractionCreate) *interaction.Response {
cfg := config.GetGuildConfig(i.GuildID)
roles := ""
l := len(cfg.XpRoles) - 1
+ 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 {
roles += fmt.Sprintf("> Niveau %d - <@&%s>", exp.Level(r.XP), r.RoleID)
@@ -28,94 +36,130 @@ func Config(_ *discordgo.Session, i *discordgo.InteractionCreate, _ cmd.OptionMa
}
}
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)
+ var 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 []component.SelectMenuDefaultValue
+ if len(cfg.FallbackChannel) > 0 {
+ defaultChan = append(defaultChan, component.SelectMenuDefaultValue{
+ ID: cfg.FallbackChannel,
+ Type: types.SelectMenuDefaultValueChannel,
+ })
}
- var defaultChan string
- if len(cfg.FallbackChannel) == 0 {
- defaultChan = "Pas de valeur"
- } else {
- defaultChan = fmt.Sprintf("<#%s>", cfg.FallbackChannel)
+ zero := 0
+ content := []component.Component{
+ &component.Container{
+ Components: []component.Message{
+ &component.TextDisplay{Content: "## Configuration"},
+ &component.Separator{},
+ &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.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,
+ },
+ },
+ },
+ },
}
- //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(
- // 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: "⌛"}),
- // ),
- // ))
- 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.SetComponents(comp).SetMessage(msg).IsEphemeral().Send()
+ return &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Components: content,
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ },
+ }
+}
+
+func ConfigCommand(
+ s bot.Session,
+ i *event.InteractionCreate,
+ _ cmd.OptionMap,
+ resp *cmd.ResponseBuilder,
+) {
+ err := s.InteractionAPI().Respond(i.Interaction, ConfigResponse(i))
+
+ if err != nil {
+ s.Logger().Error("sending config", "error", err)
+ }
+}
+
+func ConfigMessageComponent(
+ s bot.Session,
+ i *event.InteractionCreate,
+ _ *interaction.MessageComponentData,
+ _ *cmd.ResponseBuilder,
+) {
+ response := ConfigResponse(i)
+ response.Type = types.InteractionResponseUpdateMessage
+ err := s.InteractionAPI().Respond(i.Interaction, response)
+
+ if err != nil {
+ s.Logger().Error("sending config", "error", err)
+ }
+}
+
+func ConfigModal(
+ s bot.Session,
+ i *event.InteractionCreate,
+ _ *interaction.ModalSubmitData,
+ _ *cmd.ResponseBuilder,
+) {
+ response := ConfigResponse(i)
+ response.Type = types.InteractionResponseUpdateMessage
+ err := s.InteractionAPI().Respond(i.Interaction, response)
+
if err != nil {
- logger.Alert("config/guild.go - Sending config", err.Error())
+ s.Logger().Error("sending config", "error", err)
}
}
diff --git a/commands/credits.go b/commands/credits.go
index f0a8c46..340ea57 100644
--- a/commands/credits.go
+++ b/commands/credits.go
@@ -3,17 +3,18 @@ package commands
import (
"github.com/anhgelus/gokord"
"github.com/anhgelus/gokord/cmd"
- "github.com/anhgelus/gokord/logger"
- discordgo "github.com/nyttikord/gokord"
+ "github.com/nyttikord/gokord/bot"
+ "github.com/nyttikord/gokord/event"
)
-func Credits(_ *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](<https://anhgelus.world/>).\n"
msg += "Code source : <https://git.anhgelus.world/anhgelus/les-copaings-bot>\n\n"
msg += "Host du bot : " + gokord.BaseCfg.GetAuthor() + ".\n\n"
- msg += "Utilise :\n- [anhgelus/gokord](<https://github.com/anhgelus/gokord>)"
+ msg += "Utilise :\n- [anhgelus/gokord](<https://github.com/anhgelus/gokord>)\n"
+ msg += "- [Inter](<https://github.com/rsms/inter>)"
err := resp.SetMessage(msg).Send()
if err != nil {
- logger.Alert("commands/credits.go - Sending credits", err.Error(), "guild_id", i.GuildID)
+ s.Logger().Error("sending credits", "error", err)
}
}
diff --git a/commands/rank.go b/commands/rank.go
index 94dabf2..4080864 100644
--- a/commands/rank.go
+++ b/commands/rank.go
@@ -6,55 +6,42 @@ 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/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
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())
+ s.Logger().Error("reply error user is a bot", "error", err)
}
+ return
}
- 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",
- err.Error(),
- "discord_id",
- u.ID,
- "guild_id",
- 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 {
- logger.Alert("commands/rank.go - Reply error fetching guild member", err.Error())
+ 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 {
- logger.Alert(
- "commands/rank.go - Fetching xp",
- err.Error(),
- "discord_id",
- c.ID,
- "guild_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 {
- logger.Alert("commands/rank.go - Reply error fetching xp", err.Error())
+ s.Logger().Error("reply error fetching xp", "error", err)
}
return
}
@@ -68,6 +55,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.Logger().Error("sending rank", "error", err)
}
}
diff --git a/commands/reset.go b/commands/reset.go
index 07e3ba3..21bfeb7 100644
--- a/commands/reset.go
+++ b/commands/reset.go
@@ -4,43 +4,43 @@ 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"
+ "github.com/nyttikord/gokord/bot"
+ "github.com/nyttikord/gokord/event"
)
-func Reset(_ *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 {
- logger.Alert("commands/reset.go - Sending success (all)", err.Error())
+ s.Logger().Error("sending reset success", "error", err)
}
}
-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 {
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.Logger().Error("sending error copaing not set", "error", err)
}
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())
+ s.Logger().Error("sending error bot does not have xp", "error", err)
}
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.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 {
- logger.Alert("commands/reset.go - Error deleting", err.Error())
+ s.Logger().Error("sending error while deleting", "error", err)
}
}
if err = resp.SetMessage("Le user bien été reset.").Send(); err != nil {
- logger.Alert("commands/reset.go - Sending success (user)", err.Error())
+ s.Logger().Error("sending reset success", "error", err)
}
}
diff --git a/commands/stats.go b/commands/stats.go
index f93f6a0..4fc35ae 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"
@@ -16,12 +15,15 @@ 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/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"
+ "gonum.org/v1/plot/vg/draw"
+ "gorm.io/gorm"
)
type data struct {
@@ -36,78 +38,91 @@ type dbData struct {
CopaingID int
}
-func Stats(s *discordgo.Session, i *discordgo.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) {
+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 bot.Session, i *event.InteractionCreate, opt cmd.OptionMap, resp *cmd.ResponseBuilder) {
cfg := config.GetGuildConfig(i.GuildID)
- days := cfg.DaysXPRemains
+ days := 15
+ if gokord.Debug {
+ days = 90
+ }
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 {
- logger.Alert("commands/stats.go - Sending invalid days", err.Error())
+ 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.Logger().Error("sending error invalid days", "error", err)
}
return
}
- days = uint(in)
+ days = int(in)
}
err := resp.IsDeferred().Send()
if err != nil {
- logger.Alert("commands/stats.go - Sending deferred", err.Error())
+ s.Logger().Error("sending deferred", "error", err)
return
}
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)
}
if err != nil {
+ s.Logger().Error("generating stats", "error", err, "guild", 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.Logger().Error("sending error occurred", "error", err)
}
return
}
b := new(bytes.Buffer)
_, err = w.WriteTo(b)
if err != nil {
- logger.Alert("commands/stats.go - Writing png", err.Error())
+ s.Logger().Error("writing png", "error", err)
}
- err = resp.AddFile(&discordgo.File{
+ err = resp.AddFile(&channel.File{
Name: "plot.png",
ContentType: "image/png",
Reader: b,
}).Send()
if err != nil {
- logger.Alert("commands/stats.go - Sending response", err.Error())
+ s.Logger().Error("sending stats", "error", err)
}
}()
}
-func statsAll(s *discordgo.Session, i *discordgo.InteractionCreate, days uint) (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(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) {
- _, err := s.GuildMember(i.GuildID, discordID)
+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
}
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 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
if err := execSql("SELECT * FROM copaing_xps ", "").Scan(&rawCopaingData).Error; err != nil {
- logger.Alert("commands/stats.go - Fetching result", err.Error())
+ s.Logger().Error("fetching result", "error", err)
return nil, err
}
rawData = make([]*data, len(rawCopaingData))
@@ -123,7 +138,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, exec
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.Logger().Error("fetching result", "error", err)
return nil, err
}
rawData = make([]*data, len(rawDbData))
@@ -145,10 +160,10 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, exec
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.Logger().Error("finding copaing", "error", err, "copaing", raw.CopaingID)
return nil, err
}
- logger.Warn("Copaing not found, skipping entry", "old_id", raw.CopaingID)
+ s.Logger().Warn("copaing not found, skipping", "copaing", raw.CopaingID)
continue
}
copaings[raw.CopaingID] = &cp
@@ -159,7 +174,7 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, exec
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,
}
}
@@ -168,6 +183,8 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, exec
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),
@@ -177,22 +194,35 @@ func stats(s *discordgo.Session, i *discordgo.InteractionCreate, days uint, exec
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()
- 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{}
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)
+ m, err := s.GuildAPI().Member(i.GuildID, c.DiscordID)
if err != nil {
- logger.Alert("commands/stats.go - Fetching guild member", err.Error())
+ s.Logger().Error("fetching guild member", "error", err)
return nil, err
}
slices.SortFunc(stats[in], func(a, b plotter.XY) int {
@@ -204,21 +234,21 @@ 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)]
+ 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")
- if err != nil {
- logger.Alert("commands/stats.go - Generating png", err.Error())
- 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 ecbf6f4..bb08144 100644
--- a/commands/top.go
+++ b/commands/top.go
@@ -8,33 +8,34 @@ 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/bot"
+ "github.com/nyttikord/gokord/channel"
+ "github.com/nyttikord/gokord/event"
)
-func Top(_ *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 {
- logger.Alert("commands/top.go - Sending deferred", err.Error())
+ s.Logger().Error("sending deferred", "error", err)
return
}
- embeds := make([]*discordgo.MessageEmbed, 3)
+ 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)
+ tops, err := user.GetBestXP(s.Logger(), 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{
- Title: s,
+ 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",
Color: 0x831010,
}
return
}
- embeds[id] = &discordgo.MessageEmbed{
- Title: s,
+ embeds[id] = &channel.MessageEmbed{
+ Title: str,
Description: genTopsMessage(tops),
Color: 0x10E6AD,
}
@@ -59,7 +60,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.Logger().Error("sending response top", "error", err)
}
}()
}