aboutsummaryrefslogtreecommitdiff
path: root/rolereact
diff options
context:
space:
mode:
authorascpial <mail@ascpial.fr>2025-09-27 23:35:32 +0200
committerGitHub <noreply@github.com>2025-09-27 23:35:32 +0200
commitbc86bb4859c4537032f9ca8d57ac32cc14dbd629 (patch)
treee94686d7b091857788fe3f1b582f6ce540e00d71 /rolereact
parentcfdba5f417bb31aac564d13becc09874f17d075d (diff)
[Feat] Role reaction (#15)
* first draft of rolereact * fix(rolereact): fill description when setting it * fix(rolereact): fix some issues * feat(rolereact): split the code in multiple files
Diffstat (limited to 'rolereact')
-rw-r--r--rolereact/events.go46
-rw-r--r--rolereact/manager.go143
-rw-r--r--rolereact/rolereact.go543
-rw-r--r--rolereact/views.go212
4 files changed, 944 insertions, 0 deletions
diff --git a/rolereact/events.go b/rolereact/events.go
new file mode 100644
index 0000000..1de3fe0
--- /dev/null
+++ b/rolereact/events.go
@@ -0,0 +1,46 @@
+package rolereact
+
+import (
+ "git.anhgelus.world/anhgelus/les-copaings-bot/config"
+ oldGokord "github.com/anhgelus/gokord"
+ "github.com/nyttikord/gokord/bot"
+ "github.com/nyttikord/gokord/event"
+)
+
+type RoleReact struct {
+ RoleID string
+}
+
+func HandleReactionAdd(
+ s bot.Session,
+ e *event.MessageReactionAdd,
+) {
+ results := []RoleReact{}
+ oldGokord.DB.Model(&config.RoleReact{}).
+ Joins("JOIN role_react_messages ON role_reacts.role_react_message_id = role_react_messages.id").
+ Where("role_react_messages.message_id = ? AND role_reacts.reaction = ?", e.MessageID, e.MessageReaction.Emoji.APIName()).
+ Scan(&results)
+ for _, role := range results {
+ err := s.GuildAPI().MemberRoleAdd(e.GuildID, e.UserID, role.RoleID)
+ if err != nil {
+ s.Logger().Error("Unable to add role after member added reaction", "error", err)
+ }
+ }
+}
+
+func HandleReactionRemove(
+ s bot.Session,
+ e *event.MessageReactionRemove,
+) {
+ results := []RoleReact{}
+ oldGokord.DB.Model(&config.RoleReact{}).
+ Joins("JOIN role_react_messages ON role_reacts.role_react_message_id = role_react_messages.id").
+ Where("role_react_messages.message_id = ? AND role_reacts.reaction = ?", e.MessageID, e.MessageReaction.Emoji.APIName()).
+ Scan(&results)
+ for _, role := range results {
+ err := s.GuildAPI().MemberRoleRemove(e.GuildID, e.UserID, role.RoleID)
+ if err != nil {
+ s.Logger().Error("Unable to remove role after member removed reaction", "error", err)
+ }
+ }
+}
diff --git a/rolereact/manager.go b/rolereact/manager.go
new file mode 100644
index 0000000..2dadb7d
--- /dev/null
+++ b/rolereact/manager.go
@@ -0,0 +1,143 @@
+package rolereact
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "strings"
+ "time"
+
+ "git.anhgelus.world/anhgelus/les-copaings-bot/config"
+ oldGokord "github.com/anhgelus/gokord"
+ "github.com/nyttikord/gokord/bot"
+ "github.com/nyttikord/gokord/channel"
+ "github.com/nyttikord/gokord/emoji"
+ "github.com/nyttikord/gokord/event"
+)
+
+func MessageContent(message *config.RoleReactMessage) string {
+ content := "## Réagis pour obtenir un rôle"
+ if message.Note != "" {
+ content = fmt.Sprintf("%s\n%s", content, message.Note)
+ }
+ for _, role := range message.Roles {
+ if role.Reaction != "" && role.RoleID != "" {
+ content += fmt.Sprintf("\n> -# %s <@&%s>", FormatEmoji(role.Reaction), role.RoleID)
+ }
+ }
+ if len(message.Roles) == 0 {
+ content += "\n*Pas de rôles pour le moment*"
+ }
+ return content
+}
+
+func ApplyMessageChange(s bot.Session, i *event.InteractionCreate, message *config.RoleReactMessage) string {
+ messageContent := MessageContent(message)
+ _, err := s.ChannelAPI().MessageEditComplex(
+ &channel.MessageEdit{
+ Content: &messageContent,
+ AllowedMentions: &channel.MessageAllowedMentions{},
+ Channel: message.ChannelID,
+ ID: message.MessageID,
+ },
+ )
+ if err != nil {
+ s.Logger().Error("unable to update rolereact message", "error", err)
+ return "Impossible de mettre à jour le message."
+ }
+ for _, role := range message.Roles {
+ if role.Reaction != "" && role.RoleID != "" && err == nil {
+ err = s.ChannelAPI().MessageReactionAdd(
+ message.ChannelID,
+ message.MessageID,
+ role.Reaction,
+ )
+ }
+ }
+ if err != nil {
+ s.Logger().Error("unable to update reactions on rolereact message", "error", err)
+ return "Impossible de mettre à jour le message."
+ }
+ cfg := GetGuildConfigPreloaded(i.GuildID)
+ messageIndex := slices.IndexFunc(cfg.RrMessages, func(m config.RoleReactMessage) bool { return m.ID == message.ID })
+ if messageIndex != -1 {
+ oldMessage := cfg.RrMessages[messageIndex]
+ roles := make(map[uint]config.RoleReact, len(message.Roles))
+ for _, role := range message.Roles {
+ roles[role.ID] = *role
+ }
+ for _, role := range oldMessage.Roles {
+ _, ok := roles[role.ID]
+ if !ok {
+ err := oldGokord.DB.Delete(role).Error
+ if err != nil {
+ s.Logger().Error("unable to delete reaction role from database", "error", err)
+ return "Impossible de sauvegarder le message de rôle. Merci de contacter l'administrateur du bot."
+ }
+ }
+ }
+ cfg.RrMessages[messageIndex] = *message
+ err := oldGokord.DB.Save(cfg.RrMessages[messageIndex]).Error
+ if err != nil {
+ s.Logger().Error("unable to save rolereaction message in database", "error", err)
+ return "Impossible de sauvegarder le message de rôle. Merci de contacter l'administrateur du bot."
+ }
+ for _, role := range cfg.RrMessages[messageIndex].Roles {
+ err = oldGokord.DB.Save(role).Error
+ if err != nil {
+ s.Logger().Error("unable to save rolereaction role in database", "error", err)
+ return "Impossible de sauvegarder le message de rôle. Merci de contacter l'administrateur du bot."
+ }
+ }
+ }
+ return "Message de réaction mis à jour avec succès !"
+}
+
+func WaitForEmoji(s bot.Session, userID string, messageID string) (string, bool) {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
+ defer cancel()
+
+ emojiChann := make(chan emoji.Emoji)
+
+ cancelHandler := s.EventManager().AddHandler(func(s bot.Session, e *event.MessageReactionAdd) {
+ if e.MessageID == messageID && e.UserID == userID {
+ emojiChann <- e.Emoji
+ }
+ })
+ defer cancelHandler()
+
+ select {
+ case emoji := <-emojiChann:
+ emojiName := emoji.APIName()
+ return emojiName, true
+ case <-ctx.Done():
+ return "", false
+ }
+}
+
+func GetMessageFromEditID(i *event.InteractionCreate, editID uint) (*config.RoleReactMessage, bool) {
+ cfg := config.GetGuildConfig(i.GuildID)
+ m, ok := messageEdits[editID]
+ if !ok || m.GuildConfigID != cfg.ID {
+ return &config.RoleReactMessage{}, false
+ }
+ return m, true
+}
+
+func GetGuildConfigPreloaded(guildID string) *config.GuildConfig {
+ cfg := config.GuildConfig{GuildID: guildID}
+ // err := oldGokord.DB.Where("guild_id = ?", cfg.GuildID).Preload("XpRoles").Preload("RrMessages.Roles").FirstOrCreate(cfg).Error
+ err := oldGokord.DB.Where("guild_id = ?", cfg.GuildID).Preload("RrMessages.Roles").FirstOrCreate(&cfg).Error
+ if err != nil {
+ panic(err)
+ }
+ return &cfg
+}
+
+func FormatEmoji(apiName string) string {
+ if strings.Contains(apiName, ":") {
+ return fmt.Sprintf("<:%s>", apiName)
+ } else {
+ return apiName
+ }
+}
diff --git a/rolereact/rolereact.go b/rolereact/rolereact.go
new file mode 100644
index 0000000..ebc09be
--- /dev/null
+++ b/rolereact/rolereact.go
@@ -0,0 +1,543 @@
+package rolereact
+
+import (
+ "fmt"
+ "slices"
+
+ "git.anhgelus.world/anhgelus/les-copaings-bot/config"
+ "git.anhgelus.world/anhgelus/les-copaings-bot/dynamicid"
+ "github.com/anhgelus/gokord/cmd"
+ "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 (
+ OpenMessage = "rolereact_message"
+ ResetMessage = "rolereact_reset_message"
+ ApplyMessage = "rolereact_apply_message"
+ SetNote = "rolereact_set_note"
+ NewRole = "rolereact_new_role"
+ AddRole = "rolereact_add_role"
+ OpenRole = "rolereact_open_role"
+ SetRoleRoleID = "rolereact_set_role_roleid"
+ SetRoleReaction = "rolereact_set_role_reaction"
+ DelRole = "rolereact_del_role"
+)
+
+type EditID struct {
+ MessageEditID uint
+}
+
+type EditIDWithRole struct {
+ MessageEditID uint
+ RoleCounterID uint
+}
+
+var (
+ messageCounter uint = 1
+ roleCounter uint = 1
+ messageEdits map[uint]*config.RoleReactMessage = make(map[uint]*config.RoleReactMessage)
+)
+
+func HandleCommand(
+ s bot.Session,
+ i *event.InteractionCreate,
+ o cmd.OptionMap,
+ resp *cmd.ResponseBuilder,
+) {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseDeferredMessageUpdate,
+ Data: &interaction.ResponseData{Flags: channel.MessageFlagsEphemeral},
+ })
+ if err != nil {
+ s.Logger().Error("unable to defer interaction", "error", err)
+ return
+ }
+ c := o["salon"]
+ var channelID string
+ if c != nil {
+ channelID = c.Value.(string)
+ } else {
+ channelID = i.ChannelID
+ }
+
+ message := config.RoleReactMessage{
+ ChannelID: channelID,
+ GuildID: i.GuildID,
+ }
+ messageContent := MessageContent(&message)
+ m, err := s.ChannelAPI().MessageSendComplex(
+ channelID, &channel.MessageSend{
+ Content: messageContent,
+ AllowedMentions: &channel.MessageAllowedMentions{},
+ },
+ )
+ if err != nil {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{Content: fmt.Sprintf("Error: %s", err.Error())},
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send message", "error", err)
+ }
+ return
+ }
+ message.MessageID = m.ID
+ cfg := GetGuildConfigPreloaded(i.GuildID)
+ cfg.RrMessages = append(cfg.RrMessages, message)
+ err = cfg.Save()
+ if err != nil {
+ s.Logger().Error("Unable to save rolereact message in database", "error", err)
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource | types.InteractionResponseDeferredChannelMessageWithSource,
+ Data: &interaction.ResponseData{Content: "Unable to save message in database. Please retry later."},
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send message", "error", err)
+ }
+ return
+ }
+
+ messageEdits[messageCounter] = &cfg.RrMessages[len(cfg.RrMessages)-1]
+ editID := messageCounter
+ messageCounter++
+
+ err = s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: MessageModifyData(i, &EditID{MessageEditID: editID}),
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send edit rolereact message", "error", err)
+ }
+}
+
+func HandleModifyCommand(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.CommandInteractionData,
+ resp *cmd.ResponseBuilder,
+) {
+ messageId := data.TargetID
+ cfg := GetGuildConfigPreloaded(i.GuildID)
+ var target *config.RoleReactMessage
+ var targetEditID uint
+ for editID, message := range messageEdits {
+ if message.MessageID == messageId {
+ targetEditID = editID
+ target = message
+ }
+ }
+ if targetEditID == 0 {
+ for _, message := range cfg.RrMessages {
+ if message.MessageID == messageId {
+ target = &message
+ }
+ }
+ if target == nil {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral,
+ Content: "Le message sélectionné n'est pas un message de rôles de réaction.",
+ },
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send rolereact message not found", "error", err)
+ }
+ return
+ }
+ messageEdits[messageCounter] = target
+ targetEditID = messageCounter
+ messageCounter++
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseChannelMessageWithSource,
+ Data: MessageModifyData(i, &EditID{MessageEditID: targetEditID}),
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send modify rolereact message", "error", err)
+ }
+}
+
+func HandleModifyComponent(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: MessageModifyData(i, parameters),
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send modify rolereact message", "error", err)
+ }
+}
+
+func HandleResetMessage(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var responseData interaction.ResponseData
+ if !ok {
+ responseData = interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ }
+ } else {
+ cfg := GetGuildConfigPreloaded(i.GuildID)
+ for _, m := range cfg.RrMessages {
+ if m.ID == message.ID {
+ messageEdits[parameters.MessageEditID] = &m
+ }
+ }
+ responseData = *MessageModifyData(i, parameters)
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send reset message message", "error", err)
+ }
+}
+
+func HandleStartSetNote(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ if !ok {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ },
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send message edit not found message", "error", err)
+ }
+ return
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseModal,
+ Data: &interaction.ResponseData{
+ Title: "Changer la description",
+ CustomID: dynamicid.FormatCustomID(SetNote, *parameters),
+ Components: []component.Component{
+ &component.Label{
+ Label: "Nouvelle description",
+ Description: "Description affichée sur votre message de réaction",
+ Component: &component.TextInput{
+ Style: component.TextInputParagraph,
+ MaxLength: 2000,
+ CustomID: "note",
+ Value: message.Note,
+ },
+ },
+ },
+ },
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send edit note modal", "error", err)
+ }
+}
+
+func HandleSetNote(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.ModalSubmitData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ if !ok {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ },
+ })
+ if err != nil {
+ s.Logger().Error("unable to send set note error message", "error", err)
+ }
+ return
+ }
+ message.Note = data.Components[0].(*component.Label).Component.(*component.TextInput).Value
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: MessageModifyData(i, parameters),
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send updated note message", "error", err)
+ }
+}
+
+func HandleApplyMessage(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var responseData interaction.ResponseData
+ if !ok {
+ responseData = interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ if err != nil {
+ s.Logger().Error("unable to send apply message error message", "error", err)
+ }
+ return
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseDeferredChannelMessageWithSource,
+ Data: &interaction.ResponseData{Flags: channel.MessageFlagsEphemeral},
+ })
+ if err != nil {
+ s.Logger().Error("Unable to defer interaction", "error", err)
+ return
+ }
+ m := ApplyMessageChange(s, i, message)
+ _, err = s.InteractionAPI().ResponseEdit(i.Interaction, &channel.WebhookEdit{
+ Content: &m,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send apply rolereaction message changes", "error", err)
+ }
+}
+
+func HandleNewRole(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditID,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var responseData interaction.ResponseData
+ if !ok {
+ responseData = interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ }
+ } else {
+ message.Roles = append(message.Roles, &config.RoleReact{CounterID: roleCounter})
+ responseData = MessageModifyRoleData(i, &EditIDWithRole{MessageEditID: parameters.MessageEditID, RoleCounterID: roleCounter}, "")
+ roleCounter++
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send modify reaction role message", "error", err)
+ }
+}
+
+func HandleOpenRole(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditIDWithRole,
+ resp *cmd.ResponseBuilder,
+) {
+ _, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var responseData interaction.ResponseData
+ if !ok {
+ responseData = interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ }
+ } else {
+ responseData = MessageModifyRoleData(i, parameters, "")
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send open reaction role message", "error", err)
+ }
+}
+
+func HandleSetRole(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditIDWithRole,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var responseData interaction.ResponseData
+ var role *config.RoleReact
+ if ok {
+ roleIndex := slices.IndexFunc(message.Roles, func(role *config.RoleReact) bool { return role.CounterID == parameters.RoleCounterID })
+ if roleIndex != -1 {
+ role = message.Roles[roleIndex]
+ }
+ }
+ if !ok || role == nil {
+ responseData = interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ }
+ } else {
+ role.RoleID = data.Values[0]
+ responseData = MessageModifyRoleData(i, parameters, "")
+ }
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send open reaction role message", "error", err)
+ }
+}
+
+func HandleSetReaction(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditIDWithRole,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var role *config.RoleReact
+ if ok {
+ roleIndex := slices.IndexFunc(message.Roles, func(role *config.RoleReact) bool { return role.CounterID == parameters.RoleCounterID })
+ if roleIndex != -1 {
+ role = message.Roles[roleIndex]
+ }
+ }
+ if !ok || role == nil {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ },
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send open reaction role message", "error", err)
+ }
+ return
+ }
+ responseData := MessageModifyRoleData(i, parameters, "Ajoute la réaction que tu veux choisir au message de rôle de réaction (tu peux y accéder avec le bouton ci-dessous)")
+ s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &responseData,
+ })
+ emojiName, ok := WaitForEmoji(s, i.Member.User.ID, message.MessageID)
+ if !ok {
+ editResponseComponents := MessageModifyRoleComponents(i, parameters, "Le temps d'attente a été dépassé")
+ _, err := s.InteractionAPI().ResponseEdit(i.Interaction, &channel.WebhookEdit{
+ Components: &editResponseComponents,
+ })
+ if err != nil {
+ s.Logger().Error("unable to send timed out reaction message", "error", err)
+ }
+ return
+ }
+
+ err := s.ChannelAPI().MessageReactionAdd(message.ChannelID, message.MessageID, emojiName)
+ if err != nil {
+ editResponseComponents := MessageModifyRoleComponents(i, parameters, "La réaction n'est pas utilisable. Cela peut être résolu en l'ajoutant à ce serveur")
+ _, err := s.InteractionAPI().ResponseEdit(i.Interaction, &channel.WebhookEdit{
+ Components: &editResponseComponents,
+ })
+ if err != nil {
+ s.Logger().Error("unable to send unusable reaction message", "error", err)
+ }
+ return
+ }
+ err = s.ChannelAPI().MessageReactionRemove(message.ChannelID, message.MessageID, emojiName, i.Member.User.ID)
+ if err != nil {
+ s.Logger().Warn("unable to remove author reaction from message", "error", err)
+ }
+ role.Reaction = emojiName
+ components := MessageModifyRoleComponents(i, parameters, "")
+ _, err = s.InteractionAPI().ResponseEdit(i.Interaction, &channel.WebhookEdit{
+ Flags: channel.MessageFlagsIsComponentsV2 | channel.MessageFlagsEphemeral,
+ Components: &components,
+ })
+ if err != nil {
+ s.Logger().Error("Unable to edit original response", "error", err)
+ }
+}
+
+func HandleDelRole(
+ s bot.Session,
+ i *event.InteractionCreate,
+ data *interaction.MessageComponentData,
+ parameters *EditIDWithRole,
+ resp *cmd.ResponseBuilder,
+) {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ roleIndex := -1
+ if ok {
+ roleIndex = slices.IndexFunc(message.Roles, func(role *config.RoleReact) bool { return role.CounterID == parameters.RoleCounterID })
+ }
+ if !ok || roleIndex == -1 {
+ err := s.InteractionAPI().Respond(i.Interaction, &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: &interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ },
+ },
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send open reaction role message", "error", err)
+ }
+ return
+ }
+ message.Roles = append(message.Roles[:roleIndex],
+ message.Roles[roleIndex+1:]...,
+ )
+ err := s.InteractionAPI().Respond(i.Interaction,
+ &interaction.Response{
+ Type: types.InteractionResponseUpdateMessage,
+ Data: MessageModifyData(i, &EditID{MessageEditID: parameters.MessageEditID}),
+ })
+ if err != nil {
+ s.Logger().Error("Unable to send modify message message", "error", err)
+ }
+}
diff --git a/rolereact/views.go b/rolereact/views.go
new file mode 100644
index 0000000..eafa4dc
--- /dev/null
+++ b/rolereact/views.go
@@ -0,0 +1,212 @@
+package rolereact
+
+import (
+ "fmt"
+ "slices"
+
+ "git.anhgelus.world/anhgelus/les-copaings-bot/config"
+ "git.anhgelus.world/anhgelus/les-copaings-bot/dynamicid"
+ "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"
+)
+
+func MessageModifyData(i *event.InteractionCreate, parameters *EditID) *interaction.ResponseData {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ if !ok {
+ return &interaction.ResponseData{
+ Flags: channel.MessageFlagsIsComponentsV2,
+ Components: []component.Component{
+ &component.TextDisplay{Content: "Cette modification est trop vieille et a été oubliée."},
+ },
+ }
+ }
+ var note string
+ if message.Note != "" {
+ note = message.Note
+ } else {
+ note = "*Pas de note*"
+ }
+ components := []component.Message{
+ &component.TextDisplay{Content: "## Modifier un message de réaction"},
+ &component.Separator{},
+ &component.Section{
+ Components: []component.Message{&component.TextDisplay{Content: note}},
+ Accessory: &component.Button{
+ Label: "Modifier",
+ Style: component.ButtonStyleSecondary,
+ CustomID: dynamicid.FormatCustomID(SetNote, *parameters),
+ },
+ },
+ &component.Separator{},
+ }
+ for _, role := range message.Roles {
+ var reaction string
+ if role.Reaction != "" {
+ reaction = FormatEmoji(role.Reaction)
+ } else {
+ reaction = ":no_entry_sign:"
+ }
+ var roleMention string
+ if role.RoleID != "" {
+ roleMention = fmt.Sprintf("<@&%s>", role.RoleID)
+ } else {
+ roleMention = "*Pas de rôle sélectionné*"
+ }
+ if role.CounterID == 0 {
+ role.CounterID = roleCounter
+ roleCounter++
+ }
+ components = append(components, &component.Section{
+ Components: []component.Message{&component.TextDisplay{Content: fmt.Sprintf("%s %s", reaction, roleMention)}},
+ Accessory: &component.Button{
+ Label: "Modifier",
+ Style: component.ButtonStyleSecondary,
+ CustomID: dynamicid.FormatCustomID(OpenRole, EditIDWithRole{parameters.MessageEditID, role.CounterID}),
+ },
+ })
+ }
+ if len(message.Roles) == 0 {
+ components = append(components, &component.TextDisplay{
+ Content: "*Pas de rôles de réaction défini*",
+ })
+ }
+ components = append(components, []component.Message{
+ &component.ActionsRow{
+ Components: []component.Message{
+ &component.Button{
+ Style: component.ButtonStylePrimary,
+ Label: "Ajouter",
+ CustomID: dynamicid.FormatCustomID(NewRole, EditID{MessageEditID: parameters.MessageEditID}),
+ Disabled: len(message.Roles) >= 20,
+ },
+ },
+ },
+ &component.Separator{},
+ &component.ActionsRow{
+ Components: []component.Message{
+ &component.Button{
+ Label: "Appliquer",
+ Style: component.ButtonStylePrimary,
+ CustomID: dynamicid.FormatCustomID(ApplyMessage, EditID{MessageEditID: parameters.MessageEditID}),
+ },
+ &component.Button{
+ Label: "Réinitialiser",
+ Style: component.ButtonStyleDanger,
+ CustomID: dynamicid.FormatCustomID(ResetMessage, *parameters),
+ },
+ &component.Button{
+ Label: "Message",
+ Style: component.ButtonStyleLink,
+ URL: fmt.Sprintf("https://discord.com/channels/%s/%s/%s", message.GuildID, message.ChannelID, message.MessageID),
+ },
+ },
+ }}...)
+ responseData := &interaction.ResponseData{
+ Flags: channel.MessageFlagsIsComponentsV2 | channel.MessageFlagsEphemeral,
+ Components: []component.Component{
+ &component.Container{
+ Components: components,
+ },
+ },
+ }
+ return responseData
+}
+
+func MessageModifyRoleComponents(i *event.InteractionCreate, parameters *EditIDWithRole, emojiMessage string) []component.Message {
+ message, ok := GetMessageFromEditID(i, parameters.MessageEditID)
+ var role *config.RoleReact
+ if ok {
+ roleIndex := slices.IndexFunc(message.Roles, func(role *config.RoleReact) bool { return role.CounterID == parameters.RoleCounterID })
+ if roleIndex != -1 {
+ role = message.Roles[roleIndex]
+ }
+ }
+ if !ok || role == nil {
+ return []component.Message{
+ &component.TextDisplay{Content: "Impossible de trouver la modification de message. Veuillez réessayer."},
+ }
+ }
+ disableBack := false
+ var reactionDescription string
+ var reactionButton component.Button
+ if role.Reaction != "" {
+ reactionDescription = fmt.Sprintf("**Réaction : ** %s", FormatEmoji(role.Reaction))
+ reactionButton = component.Button{Label: "Modifier", Style: component.ButtonStyleSecondary}
+ } else {
+ reactionDescription = "*Aucune réaction pour le moment*"
+ reactionButton = component.Button{Label: "Ajouter", Style: component.ButtonStylePrimary}
+ disableBack = true
+ }
+ reactionButton.CustomID = dynamicid.FormatCustomID(SetRoleReaction, *parameters)
+ defaultRoleValues := make([]component.SelectMenuDefaultValue, 0)
+ if role.RoleID != "" {
+ defaultRoleValues = append(defaultRoleValues, component.SelectMenuDefaultValue{
+ Type: types.SelectMenuDefaultValueRole,
+ ID: role.RoleID,
+ })
+ }
+ disableBack = disableBack || (role.RoleID == "")
+ one := 1
+ components := []component.Message{
+ &component.TextDisplay{Content: "## Modifier un message de réaction"},
+ &component.Separator{},
+ &component.Section{
+ Components: []component.Message{
+ &component.TextDisplay{Content: reactionDescription},
+ },
+ Accessory: &reactionButton,
+ },
+ }
+ if emojiMessage != "" {
+ components = append(components, &component.TextDisplay{Content: "-# " + emojiMessage})
+ }
+ components = append(components,
+ []component.Message{
+ &component.ActionsRow{Components: []component.Message{
+ &component.SelectMenu{
+ MenuType: types.SelectMenuRole,
+ CustomID: dynamicid.FormatCustomID(SetRoleRoleID, *parameters),
+ MinValues: &one, MaxValues: 1,
+ Placeholder: "Sélectionner un rôle",
+ DefaultValues: defaultRoleValues,
+ },
+ }},
+ &component.ActionsRow{Components: []component.Message{
+ &component.Button{
+ Style: component.ButtonStyleDanger,
+ Label: "Supprimer",
+ CustomID: dynamicid.FormatCustomID(DelRole, *parameters),
+ },
+ }},
+ &component.Separator{},
+ &component.ActionsRow{Components: []component.Message{
+ &component.Button{
+ Label: "Retour",
+ Style: component.ButtonStyleSecondary,
+ Disabled: disableBack,
+ CustomID: dynamicid.FormatCustomID(OpenMessage, EditID{MessageEditID: parameters.MessageEditID}),
+ },
+ &component.Button{
+ Label: "Message", Style: component.ButtonStyleLink,
+ URL: fmt.Sprintf("https://discord.com/channels/%s/%s/%s", message.GuildID, message.ChannelID, message.MessageID),
+ },
+ }},
+ }...)
+ return []component.Message{&component.Container{
+ Components: components,
+ }}
+}
+
+func MessageModifyRoleData(i *event.InteractionCreate, parameters *EditIDWithRole, emojiMessage string) interaction.ResponseData {
+ components := []component.Component{}
+ for _, component := range MessageModifyRoleComponents(i, parameters, emojiMessage) {
+ components = append(components, component)
+ }
+ return interaction.ResponseData{
+ Flags: channel.MessageFlagsEphemeral | channel.MessageFlagsIsComponentsV2,
+ Components: components,
+ }
+}