diff options
| author | ascpial <mail@ascpial.fr> | 2025-09-27 23:35:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-27 23:35:32 +0200 |
| commit | bc86bb4859c4537032f9ca8d57ac32cc14dbd629 (patch) | |
| tree | e94686d7b091857788fe3f1b582f6ce540e00d71 /rolereact | |
| parent | cfdba5f417bb31aac564d13becc09874f17d075d (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.go | 46 | ||||
| -rw-r--r-- | rolereact/manager.go | 143 | ||||
| -rw-r--r-- | rolereact/rolereact.go | 543 | ||||
| -rw-r--r-- | rolereact/views.go | 212 |
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, + } +} |
