From 830790524b5266587f8be0ccdcbf961bb3e50e03 Mon Sep 17 00:00:00 2001 From: Kesuaheli Date: Sat, 14 Dec 2024 18:51:25 +0100 Subject: [PATCH] feat(Secret Santa): added secret santa admin commands --- data/lang/de.yaml | 11 +++ data/lang/en.yaml | 11 +++ event/command/commandBase.go | 1 + modules/secretsanta/chatCommand.go | 72 +++++++++++++++++++ modules/secretsanta/handleChatCommandShow.go | 19 +++++ .../secretsanta/handleChatCommandUpdate.go | 53 ++++++++++++++ modules/secretsanta/handleComponentSetup.go | 24 +------ modules/secretsanta/secretsantabase.go | 23 ++++++ util/discord.go | 28 ++++++++ 9 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 modules/secretsanta/chatCommand.go create mode 100644 modules/secretsanta/handleChatCommandShow.go create mode 100644 modules/secretsanta/handleChatCommandUpdate.go diff --git a/data/lang/de.yaml b/data/lang/de.yaml index 5733840..ce7b01c 100644 --- a/data/lang/de.yaml +++ b/data/lang/de.yaml @@ -129,6 +129,14 @@ discord.command: title: Wichteln + cmd: + base: wichteln + base.description: Admin Commands für das Wichteln + option.show: auflisten + option.show.description: Alle Teilnehmer anzeigen + option.update: aktualisieren + option.update.description: Die Nachricht all Teilnehmer aktualisieren + msg.setup.no_reactions: Diese Nachricht hat keine Reaktionen. Nur Leute, die mit %s reagiert haben, werden eingeschlossen. msg.setup.not_enough_reactions: Nicht genug Reaktionen um zu starten. Es werden mindestens %d Reaktionen benötigt. msg.setup.users: Teilnehmer @@ -138,6 +146,9 @@ discord.command: msg.setup.error: "%d Einladungen konnten nicht verschickt werden." msg.setup.success: Einladungen wurden verschickt! + msg.cmd.update.error: "%d Einladung(en) konnte(n) nicht aktualisiert werden.%s" + msg.cmd.update.success: "%d Einladungen wurden aktualisiert!" + msg.invite.title: Einladung zum Wichteln. msg.invite.description: Du nimmst am Cake4Everyone Wichteln teil. Klicke die Knöpfe unten, um deinen Partner zu sehen und deine Adresse einzutragen. msg.invite.set_address.match: Dein Partner hat eine Adresse eingetragen diff --git a/data/lang/en.yaml b/data/lang/en.yaml index 3e0e369..cb48010 100644 --- a/data/lang/en.yaml +++ b/data/lang/en.yaml @@ -129,6 +129,14 @@ discord.command: title: Secret Santa + cmd: + base: secretsanta + base.description: Admin commands for the Secret Santa Game + option.show: show + option.show.description: Show all participants + option.update: update + option.update.description: Update the message off all participants + msg.setup.no_reactions: This message doesn't have any vote reactions. Only members who reated with %s are included. msg.setup.not_enough_reactions: Not enough votes to start a game. At least %d votes are required. msg.setup.users: Members @@ -138,6 +146,9 @@ discord.command: msg.setup.error: Failed to send %d invites. msg.setup.success: Invites sent! + msg.cmd.update.error: Failed to update %d invites.%s + msg.cmd.update.success: "%d invites updated!" + msg.invite.title: Invite for secret santa. msg.invite.description: You are participating in Cake4Everyone Secret Santa. Click the buttons below to see your partner and set your address. msg.invite.set_address.match: Your partner has set an address diff --git a/event/command/commandBase.go b/event/command/commandBase.go index ee709e0..2dc7ad4 100644 --- a/event/command/commandBase.go +++ b/event/command/commandBase.go @@ -70,6 +70,7 @@ func Register(s *discordgo.Session, guildID string) error { commandsList = append(commandsList, &birthday.Chat{}) commandsList = append(commandsList, &info.Chat{}) commandsList = append(commandsList, &adventcalendar.Chat{}) + commandsList = append(commandsList, &secretsanta.Chat{}) commandsList = append(commandsList, &secretsanta.MsgCmd{}) // messsage commands // user commands diff --git a/modules/secretsanta/chatCommand.go b/modules/secretsanta/chatCommand.go new file mode 100644 index 0000000..1a15882 --- /dev/null +++ b/modules/secretsanta/chatCommand.go @@ -0,0 +1,72 @@ +package secretsanta + +import ( + "cake4everybot/data/lang" + "cake4everybot/util" + + "github.com/bwmarrin/discordgo" +) + +// The Chat (slash) command of the secret santa package. +type Chat struct { + secretSantaBase + ID string +} + +// AppCmd (ApplicationCommand) returns the definition of the chat command +func (Chat) AppCmd() *discordgo.ApplicationCommand { + return &discordgo.ApplicationCommand{ + Name: lang.GetDefault(tp + "cmd.base"), + NameLocalizations: util.TranslateLocalization(tp + "cmd.base"), + Description: lang.GetDefault(tp + "cmd.base.description"), + DescriptionLocalizations: util.TranslateLocalization(tp + "cmd.base.description"), + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionSubCommand, + Name: lang.GetDefault(tp + "cmd.option.show"), + NameLocalizations: *util.TranslateLocalization(tp + "cmd.option.show"), + Description: lang.GetDefault(tp + "cmd.option.show.description"), + DescriptionLocalizations: *util.TranslateLocalization(tp + "cmd.option.show.description"), + }, + { + Type: discordgo.ApplicationCommandOptionSubCommand, + Name: lang.GetDefault(tp + "cmd.option.update"), + NameLocalizations: *util.TranslateLocalization(tp + "cmd.option.update"), + Description: lang.GetDefault(tp + "cmd.option.update.description"), + DescriptionLocalizations: *util.TranslateLocalization(tp + "cmd.option.update.description"), + }, + }, + } +} + +// Handle handles the functionality of a command +func (cmd Chat) Handle(s *discordgo.Session, i *discordgo.InteractionCreate) { + cmd.InteractionUtil = util.InteractionUtil{Session: s, Interaction: i} + cmd.member = i.Member + cmd.user = i.User + if i.Member != nil { + cmd.user = i.Member.User + } else if i.User != nil { + cmd.member = &discordgo.Member{User: i.User} + } + + switch i.ApplicationCommandData().Options[0].Name { + case lang.GetDefault(tp + "cmd.option.show"): + cmd.handleSubcommandShow() + return + case lang.GetDefault(tp + "cmd.option.update"): + cmd.handleSubcommandUpdate() + return + } + +} + +// SetID sets the registered command ID for internal uses after uploading to discord +func (cmd *Chat) SetID(id string) { + cmd.ID = id +} + +// GetID gets the registered command ID +func (cmd Chat) GetID() string { + return cmd.ID +} diff --git a/modules/secretsanta/handleChatCommandShow.go b/modules/secretsanta/handleChatCommandShow.go new file mode 100644 index 0000000..bd98a94 --- /dev/null +++ b/modules/secretsanta/handleChatCommandShow.go @@ -0,0 +1,19 @@ +package secretsanta + +// handleSubcommandShow handles the functionality of the show subcommand +func (cmd Chat) handleSubcommandShow() { + players, err := cmd.getPlayers() + if err != nil { + cmd.ReplyError() + return + } + + var list string + for _, p := range players { + list += "- " + + p.Mention() + + " - (`" + p.User.Username + "`)" + + "\n" + } + cmd.ReplyHiddenSimpleEmbed(0x690042, list) +} diff --git a/modules/secretsanta/handleChatCommandUpdate.go b/modules/secretsanta/handleChatCommandUpdate.go new file mode 100644 index 0000000..e56ca61 --- /dev/null +++ b/modules/secretsanta/handleChatCommandUpdate.go @@ -0,0 +1,53 @@ +package secretsanta + +import ( + "cake4everybot/data/lang" + "cake4everybot/util" + + "github.com/bwmarrin/discordgo" +) + +// handleSubcommandUpdate handles the functionality of the update subcommand +func (cmd Chat) handleSubcommandUpdate() { + cmd.ReplyDeferedHidden() + players, err := cmd.getPlayers() + if err != nil { + cmd.ReplyError() + return + } + + var failedToSend string + for _, p := range players { + var DMChannel *discordgo.Channel + DMChannel, err = cmd.Session.UserChannelCreate(p.User.ID) + if err != nil { + log.Printf("ERROR: could not create DM channel for user %s: %+v", p.User.ID, err) + failedToSend += "\n- " + p.Mention() + continue + } + + if p.MessageID == "" { + var msg *discordgo.Message + msg, err = cmd.Session.ChannelMessageSendComplex(DMChannel.ID, cmd.inviteMessage(p)) + if err != nil { + log.Printf("ERROR: could not send invite message for %s: %+v", p.DisplayName(), err) + failedToSend += "\n- " + p.Mention() + continue + } + p.MessageID = msg.ID + } else { + _, err = cmd.Session.ChannelMessageEditComplex(util.MessageComplexEdit(cmd.inviteMessage(p), DMChannel.ID, p.MessageID)) + if err != nil { + log.Printf("ERROR: could not update bot message for %s '%s/%s': %+v", p.DisplayName(), cmd.Interaction.ChannelID, p.MessageID, err) + failedToSend += "\n- " + p.Mention() + return + } + } + } + + if failedToSend != "" { + cmd.ReplyHiddenf(lang.GetDefault(tp+"msg.cmd.update.error"), failedToSend) + return + } + cmd.ReplyHiddenf(lang.GetDefault(tp+"msg.cmd.update.success"), len(players)) +} diff --git a/modules/secretsanta/handleComponentSetup.go b/modules/secretsanta/handleComponentSetup.go index b037c81..d78a7c4 100644 --- a/modules/secretsanta/handleComponentSetup.go +++ b/modules/secretsanta/handleComponentSetup.go @@ -3,7 +3,6 @@ package secretsanta import ( "cake4everybot/data/lang" "cake4everybot/util" - "fmt" "github.com/bwmarrin/discordgo" ) @@ -33,26 +32,6 @@ func (c Component) handleSetupInvite() { return } - inviteMessage := &discordgo.MessageSend{ - Embeds: make([]*discordgo.MessageEmbed, 1), - Components: []discordgo.MessageComponent{ - discordgo.ActionsRow{Components: []discordgo.MessageComponent{ - util.CreateButtonComponent( - fmt.Sprintf("secretsanta.invite.show_match.%s", c.Interaction.GuildID), - lang.GetDefault(tp+"msg.invite.button.show_match"), - discordgo.PrimaryButton, - util.GetConfigComponentEmoji("secretsanta.invite.show_match"), - ), - util.CreateButtonComponent( - fmt.Sprintf("secretsanta.invite.set_address.%s", c.Interaction.GuildID), - lang.GetDefault(tp+"msg.invite.button.set_address"), - discordgo.SecondaryButton, - util.GetConfigComponentEmoji("secretsanta.invite.set_address"), - ), - }}, - }, - } - var failedToSend string for _, player := range players { var DMChannel *discordgo.Channel @@ -63,9 +42,8 @@ func (c Component) handleSetupInvite() { continue } - inviteMessage.Embeds[0] = player.InviteEmbed(c.Session) var msg *discordgo.Message - msg, err = c.Session.ChannelMessageSendComplex(DMChannel.ID, inviteMessage) + msg, err = c.Session.ChannelMessageSendComplex(DMChannel.ID, c.inviteMessage(player)) if err != nil { log.Printf("ERROR: could not send invite: %+v", err) failedToSend += "\n- " + player.Mention() diff --git a/modules/secretsanta/secretsantabase.go b/modules/secretsanta/secretsantabase.go index 5f1a25c..7530dac 100644 --- a/modules/secretsanta/secretsantabase.go +++ b/modules/secretsanta/secretsantabase.go @@ -98,6 +98,29 @@ func (ssb secretSantaBase) setPlayers(players map[string]*player) (err error) { return nil } +// inviteMessage returns the message to send to the player to invite them to play. +func (ssb secretSantaBase) inviteMessage(p *player) *discordgo.MessageSend { + return &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{p.InviteEmbed(ssb.Session)}, + Components: []discordgo.MessageComponent{ + discordgo.ActionsRow{Components: []discordgo.MessageComponent{ + util.CreateButtonComponent( + fmt.Sprintf("secretsanta.invite.show_match.%s", ssb.Interaction.GuildID), + lang.GetDefault(tp+"msg.invite.button.show_match"), + discordgo.PrimaryButton, + util.GetConfigComponentEmoji("secretsanta.invite.show_match"), + ), + util.CreateButtonComponent( + fmt.Sprintf("secretsanta.invite.set_address.%s", ssb.Interaction.GuildID), + lang.GetDefault(tp+"msg.invite.button.set_address"), + discordgo.SecondaryButton, + util.GetConfigComponentEmoji("secretsanta.invite.set_address"), + ), + }}, + }, + } +} + // player is a player in the secret santa game type player struct { *discordgo.Member diff --git a/util/discord.go b/util/discord.go index 3fce1f3..9dcd4e9 100644 --- a/util/discord.go +++ b/util/discord.go @@ -194,3 +194,31 @@ func componentEmoji[E *discordgo.Emoji | *discordgo.ComponentEmoji](e E) *discor } panic("Given generic type is not an emoji or component emoji") } + +// MessageComplexEdit converts a [discordgo.MessageSend] to a [discordgo.MessageEdit] +func MessageComplexEdit(src *discordgo.MessageSend, channel, id string) *discordgo.MessageEdit { + return &discordgo.MessageEdit{ + Content: &src.Content, + Components: &src.Components, + Embeds: &src.Embeds, + AllowedMentions: src.AllowedMentions, + Flags: src.Flags, + Files: src.Files, + + Channel: channel, + ID: id, + } +} + +// MessageComplexSend converts a [discordgo.MessageEdit] to a [discordgo.MessageSend] +func MessageComplexSend(src *discordgo.MessageEdit) *discordgo.MessageSend { + return &discordgo.MessageSend{ + Content: *src.Content, + Components: *src.Components, + Embeds: *src.Embeds, + AllowedMentions: src.AllowedMentions, + Flags: src.Flags, + Files: src.Files, + } + +}