aboutsummaryrefslogtreecommitdiff
path: root/config/xp_role_events.go
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2026-03-08 18:51:05 +0100
committerAnhgelus Morhtuuzh <william@herges.fr>2026-03-08 18:51:05 +0100
commit6e92feaba23a4992e0ec4b529660921a6bcb492a (patch)
tree05024b52d4c8ede041facdc48ac65af5ba0259da /config/xp_role_events.go
parent3bcf74c47d1597ba650dc5a55868f83f5f547ad7 (diff)
feat(config): leave gorm
Diffstat (limited to 'config/xp_role_events.go')
-rw-r--r--config/xp_role_events.go358
1 files changed, 358 insertions, 0 deletions
diff --git a/config/xp_role_events.go b/config/xp_role_events.go
new file mode 100644
index 0000000..cda90d5
--- /dev/null
+++ b/config/xp_role_events.go
@@ -0,0 +1,358 @@
+package config
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "strconv"
+
+ "git.anhgelus.world/anhgelus/les-copaings-bot/dynamicid"
+ "git.anhgelus.world/anhgelus/les-copaings-bot/exp"
+ "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/interaction"
+)
+
+type XpRoleId struct {
+ ID uint64
+}
+
+const (
+ ModifyXpRole = "xp_role"
+ XpRoleNew = "xp_role_add"
+ XpRoleAdd = "xp_role_add_level"
+ XpRoleEdit = `xp_role_edit`
+ XpRoleEditLevel = `xp_role_edit_level`
+ XpRoleEditLevelStart = `xp_role_edit_level_start`
+ XpRoleEditRole = `xp_role_edit_role`
+ XpRoleDel = `xp_role_del`
+)
+
+func HandleXpRole(ctx context.Context, dg bot.Session, i *interaction.Interaction) {
+ cfg := GetGuild(ctx, i.GuildID)
+ container := component.Container{
+ Components: []component.Message{
+ &component.TextDisplay{Content: "## Configuration / Rôles de niveaux"},
+ &component.TextDisplay{Content: "Ces rôles seront donnés et retirés en fonction du niveau de chacun"},
+ &component.Separator{},
+ },
+ }
+ slices.SortFunc(cfg.XpRoles, func(xp1, xp2 XpRole) int {
+ return int(xp2.XP) - int(xp1.XP)
+ })
+ for _, r := range cfg.XpRoles {
+ container.Components = append(container.Components, &component.Section{
+ Components: []component.Message{
+ &component.TextDisplay{
+ Content: fmt.Sprintf("<@&%d> - Niveau %d", r.RoleID, exp.Level(r.XP)),
+ },
+ },
+ Accessory: &component.Button{
+ CustomID: dynamicid.FormatCustomID(XpRoleEdit, XpRoleId{ID: r.RoleID}),
+ Style: component.ButtonStyleSecondary,
+ Label: "Modifier",
+ },
+ })
+ }
+ container.Components = append(container.Components,
+ &component.ActionsRow{
+ Components: []component.Message{
+ &component.Button{
+ CustomID: XpRoleNew,
+ Style: component.ButtonStylePrimary,
+ Label: "Nouveau rôle",
+ },
+ },
+ },
+ &component.Separator{},
+ &component.ActionsRow{
+ Components: []component.Message{
+ &component.Button{CustomID: "config", Style: component.ButtonStyleSecondary, Label: "Retour"},
+ },
+ },
+ )
+
+ response := &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Components: []component.Component{&container},
+ Flags: channel.MessageFlagsIsComponentsV2,
+ },
+ }
+ err := interaction.Respond(i, response).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending config", "error", err)
+ }
+}
+
+func HandleXpRoleNew(ctx context.Context, dg bot.Session, i *interaction.MessageComponent) {
+ one := 1
+ resp := interaction.NewModalResponse().
+ Title("Nouveau rôle de niveau").
+ CustomID(XpRoleAdd).
+ AddComponent(&component.Label{
+ Label: "Niveau",
+ Component: &component.TextInput{
+ CustomID: "level",
+ Style: component.TextInputShort,
+ Placeholder: "5",
+ MinLength: 1,
+ MaxLength: 5,
+ Required: true,
+ },
+ }).
+ AddComponent(&component.Label{
+ Label: "Rôle",
+ Component: &component.SelectMenu{
+ MenuType: types.SelectMenuRole,
+ CustomID: "role",
+ MinValues: &one,
+ MaxValues: one,
+ },
+ }).
+ Response()
+ err := interaction.Respond(i.Interaction, resp).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending modal to add", "error", err)
+ }
+}
+
+func HandleXpRoleEdit(ctx context.Context, dg bot.Session, i *interaction.Interaction, params *XpRoleId) {
+ config := GetGuild(ctx, i.GuildID)
+ id := params.ID
+ _, role := config.FindXpRole(id)
+ if role == nil {
+ HandleXpRole(ctx, dg, i)
+ return
+ }
+
+ roleSelect := &component.SelectMenu{
+ MenuType: types.SelectMenuRole,
+ CustomID: dynamicid.FormatCustomID(XpRoleEditRole, XpRoleId{ID: id}),
+ DefaultValues: []component.SelectMenuDefaultValue{
+ {ID: role.RoleID, Type: types.SelectMenuDefaultValueRole},
+ },
+ }
+
+ container := &component.Container{
+ Components: []component.Message{
+ &component.TextDisplay{Content: "## Configuration / Rôles de niveaux"},
+ &component.Separator{},
+ &component.Section{
+ Components: []component.Message{
+ &component.TextDisplay{Content: fmt.Sprintf("Niveau **%d**", exp.Level(role.XP))},
+ },
+ Accessory: &component.Button{
+ CustomID: dynamicid.FormatCustomID(XpRoleEditLevelStart, XpRoleId{ID: id}),
+ Style: component.ButtonStyleSecondary,
+ Label: "Modifier",
+ },
+ },
+ &component.ActionsRow{Components: []component.Message{roleSelect}},
+ &component.ActionsRow{Components: []component.Message{
+ &component.Button{
+ CustomID: dynamicid.FormatCustomID(XpRoleDel, XpRoleId{ID: id}),
+ Style: component.ButtonStyleDanger,
+ Label: "Supprimer",
+ },
+ }},
+ &component.Separator{},
+ &component.ActionsRow{Components: []component.Message{
+ &component.Button{Label: "Retour", CustomID: ModifyXpRole, Style: component.ButtonStyleSecondary},
+ }},
+ },
+ }
+
+ response := &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Components: []component.Component{container},
+ Flags: channel.MessageFlagsIsComponentsV2,
+ },
+ }
+
+ err := interaction.Respond(i, response).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending xp_role config", "error", err)
+ }
+}
+
+func HandleXpRoleEditRole(ctx context.Context, dg bot.Session, i *interaction.MessageComponent, params *XpRoleId) {
+ id := params.ID
+ role, err := strconv.ParseUint(i.Data.Values[0], 10, 64)
+ if err != nil {
+ // panic because must ensure that the role is valid before
+ panic(err)
+ }
+ cfg := GetGuild(ctx, i.GuildID)
+ _, xpRole := cfg.FindXpRole(id)
+ if xpRole == nil {
+ err := interaction.Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral,
+ Content: "Impossible de modifier le rôle. Peut-être a-t-il été supprimé ?",
+ },
+ }).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending unable to get role message", "error", err)
+ }
+ return
+ }
+ xpRole.RoleID = role
+ err = xpRole.Save(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("saving config", "error", err, "guild", i.GuildID, "id", id, "type", "add")
+ }
+ HandleXpRoleEdit(ctx, dg, i.Interaction, params)
+}
+
+func HandleXpRoleEditLevelStart(ctx context.Context, dg bot.Session, i *interaction.MessageComponent, params *XpRoleId) {
+ id := params.ID
+ cfg := GetGuild(ctx, i.GuildID)
+ _, xpRole := cfg.FindXpRole(id)
+ if xpRole == nil {
+ err := interaction.Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral,
+ Content: "Impossible de trouver le rôle. Peut-être a-t-il été supprimé ?",
+ },
+ }).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending unable to get role message", "error", err)
+ }
+ return
+ }
+ response := &interaction.Response{
+ Type: types.InteractionResponseModal,
+ Data: &interaction.ResponseData{
+ Title: "Modification du niveau lié au rôle",
+ CustomID: dynamicid.FormatCustomID(XpRoleEditLevel, XpRoleId{ID: id}),
+ Components: []component.Component{
+ &component.Label{
+ Label: "Nouveau niveau",
+ Component: &component.TextInput{
+ Style: component.TextInputShort,
+ Required: true,
+ CustomID: "level",
+ MinLength: 1,
+ MaxLength: 5,
+ Placeholder: "5",
+ Value: strconv.FormatUint(uint64(exp.Level(xpRole.XP)), 10),
+ },
+ },
+ },
+ },
+ }
+ err := interaction.Respond(i.Interaction, response).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending edit level modal", "error", err)
+ }
+}
+
+func HandleXpRoleEditLevel(ctx context.Context, dg bot.Session, i *interaction.ModalSubmit, params *XpRoleId) {
+ id := params.ID
+
+ levelInput := i.Data.Components[0].(*component.Label).Component.(*component.TextInput)
+ level, err := strconv.Atoi(levelInput.Value)
+ if err != nil || level < 0 {
+ resp := interaction.NewMessageResponse().
+ IsEphemeral().
+ Message(fmt.Sprintf("Le niveau doit être un nombre entier positif.\n-# Trouvé : %s", levelInput.Value)).
+ Response()
+ err = interaction.Respond(i.Interaction, resp).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending bad number warning message", "error", err)
+ }
+ return
+ }
+ xp := exp.LevelXP(uint(level))
+
+ cfg := GetGuild(ctx, i.GuildID)
+ _, xpRole := cfg.FindXpRole(id)
+ if xpRole == nil {
+ err = interaction.Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral,
+ Content: "Impossible de modifier le rôle. Peut-être a-t-il été supprimé ?",
+ },
+ }).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending unable to modify role message", "error", err)
+ }
+ return
+ }
+ xpRole.XP = xp
+ err = xpRole.Save(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("saving config", "guild", i.GuildID, "id", id, "type", "edit")
+ }
+ HandleXpRoleEdit(ctx, dg, i.Interaction, params)
+}
+
+func HandleXpRoleDel(ctx context.Context, dg bot.Session, i *interaction.MessageComponent, parameters *XpRoleId) {
+ id := parameters.ID
+ cfg := GetGuild(ctx, i.GuildID)
+ _, role := cfg.FindXpRole(id)
+ if role == nil {
+ err := interaction.Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Content: "Rôle introuvable. Peut-être a-t-il déjà été supprimé ?",
+ Flags: channel.MessageFlagsEphemeral,
+ },
+ }).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending role not found message", "error", err)
+ }
+ return
+ }
+ err := role.Delete(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("deleting entry", "error", err, "guild", i.GuildID, "id", id, "type", "del")
+ }
+
+ HandleXpRole(ctx, dg, i.Interaction)
+}
+
+func HandleXpRoleAdd(ctx context.Context, dg bot.Session, i *interaction.ModalSubmit) {
+ levelInput := i.Data.Components[0].(*component.Label).Component.(*component.TextInput)
+
+ in, err := strconv.Atoi(levelInput.Value)
+ if err != nil || in < 0 {
+ resp := interaction.NewMessageResponse().
+ IsEphemeral().
+ Message(fmt.Sprintf("Le niveau doit être un nombre entier positif.\n-# Trouvé : %s", levelInput.Value)).
+ Response()
+ err = interaction.Respond(i.Interaction, resp).Do(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("sending bad number warning message", "error", err)
+ }
+ return
+ }
+ xp := exp.LevelXP(uint(in))
+
+ rawRoleId := i.Data.Components[1].(*component.Label).Component.(*component.SelectMenu).Values[0]
+ roleId, err := strconv.ParseUint(rawRoleId, 10, 64)
+ if err != nil {
+ // panic because select menu must ensure that the value is valid
+ panic(err)
+ }
+
+ cfg := GetGuild(ctx, i.GuildID)
+ cfg.XpRoles = append(cfg.XpRoles, XpRole{
+ XP: xp,
+ RoleID: roleId,
+ })
+ err = cfg.Save(ctx)
+ if err != nil {
+ bot.Logger(ctx).Error("saving config", "error", err, "role", roleId, "guild", i.GuildID)
+ return
+ }
+
+ HandleXpRole(ctx, dg, i.Interaction)
+}