diff options
| -rw-r--r-- | commands/admin/purge.go | 100 | ||||
| -rw-r--r-- | commands/commands.go | 27 | ||||
| -rw-r--r-- | config/config.go | 1 | ||||
| -rw-r--r-- | handlers/interactionCreateHandler.go | 33 | ||||
| -rw-r--r-- | utils/responder.go | 35 | ||||
| -rw-r--r-- | yuzaki/main.go | 75 |
6 files changed, 214 insertions, 57 deletions
diff --git a/commands/admin/purge.go b/commands/admin/purge.go new file mode 100644 index 0000000..46b6068 --- /dev/null +++ b/commands/admin/purge.go @@ -0,0 +1,100 @@ +package admin + +import ( + "fmt" + "log" + "time" + + "yuzaki/utils" + + "github.com/bwmarrin/discordgo" +) + +func PurgeChat(s *discordgo.Session, i *discordgo.InteractionCreate) { + err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseDeferredChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + if err != nil { + log.Printf("Error responding to interaction: %s. Interaction: purge. Interaction By: %s\n", err, i.Member.DisplayName()) + return + } + + options := i.ApplicationCommandData().Options + optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options)) + for _, option := range options { + optionMap[option.Name] = option + } + + option, ok := optionMap["amount"] + if !ok { + utils.SendFollowUpMessage(s, i, "You must provide an amount to purge", true) + return + } + + amount := option.IntValue() + if amount < 1 { + utils.SendFollowUpMessage(s, i, "Amount must be greater than 0", true) + return + } + + channel := i.ChannelID + remaining := amount + deletedCount := int64(0) + + for remaining > 0 { + batchSize := int64(100) + if remaining < 100 { + batchSize = remaining + } + + messages, err := s.ChannelMessages(channel, int(batchSize), "", "", "") + if err != nil { + utils.SendFollowUpMessage(s, i, "Failed to fetch messages", true) + return + } + + if len(messages) == 0 { + break + } + + messageIDs := make([]string, len(messages)) + for i, message := range messages { + messageIDs[i] = message.ID + } + + if len(messageIDs) > 1 { + err = s.ChannelMessagesBulkDelete(channel, messageIDs) + if err != nil { + for _, msgID := range messageIDs { + err = s.ChannelMessageDelete(channel, msgID) + if err != nil { + continue + } + deletedCount++ + time.Sleep(time.Millisecond * 100) + } + } else { + deletedCount += int64(len(messageIDs)) + } + } else if len(messageIDs) == 1 { + err = s.ChannelMessageDelete(channel, messageIDs[0]) + if err == nil { + deletedCount++ + } + time.Sleep(time.Millisecond * 100) + } + + remaining -= batchSize + } + + utils.SendFollowUpMessage(s, i, fmt.Sprintf("Successfully purged %d messages!", deletedCount), false) + _, err = s.ChannelMessageSend(channel, fmt.Sprintf("<@%s> has purged %d messages from this channel", i.Member.User.ID, deletedCount)) + if err != nil { + log.Printf("Failed to send message after purging messages. Successfully purged %d messages from channel %s. Purged By: %s\n", deletedCount, channel, i.Member.DisplayName()) + } else { + log.Printf("Successfully purged %d messages from channel %s. Purged By: %s\n", deletedCount, channel, i.Member.DisplayName()) + } +} diff --git a/commands/commands.go b/commands/commands.go new file mode 100644 index 0000000..629999f --- /dev/null +++ b/commands/commands.go @@ -0,0 +1,27 @@ +package commands + +import ( + "github.com/bwmarrin/discordgo" +) + +var ( + manageMessagesPermissions int64 = discordgo.PermissionManageMessages +) + +var ( + Commands = []*discordgo.ApplicationCommand{ + { + Name: "purge", + Description: "Purge messages from the current channel", + DefaultMemberPermissions: &manageMessagesPermissions, + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "amount", + Description: "The amount of messages to purge", + Required: true, + }, + }, + }, + } +) diff --git a/config/config.go b/config/config.go index 1d78fea..44155ad 100644 --- a/config/config.go +++ b/config/config.go @@ -53,7 +53,6 @@ func Load() error { return fmt.Errorf("getting POKETWO_CHANNELS: %w", err) } config.ConfiguredChannels.PoketwoSpawns = channels - fmt.Println(config.ConfiguredChannels.PoketwoSpawns) if err := validateConfig(config); err != nil { return fmt.Errorf("validating config: %w", err) diff --git a/handlers/interactionCreateHandler.go b/handlers/interactionCreateHandler.go new file mode 100644 index 0000000..2d9e0e7 --- /dev/null +++ b/handlers/interactionCreateHandler.go @@ -0,0 +1,33 @@ +package handlers + +import ( + "fmt" + "yuzaki/commands/admin" + + "github.com/bwmarrin/discordgo" +) + +var ( + SlashCommandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ + "purge": admin.PurgeChat, + } +) + +func InteractionCreateHandler(s *discordgo.Session, interaction *discordgo.InteractionCreate) { + switch interaction.Type { + case discordgo.InteractionApplicationCommand: + if handler, ok := SlashCommandHandlers[interaction.ApplicationCommandData().Name]; ok { + handler(s, interaction) + } + case discordgo.InteractionMessageComponent: + // Detect what type of message component interaction it is. + switch interaction.MessageComponentData().ComponentType { + case discordgo.ButtonComponent: + fmt.Println("Button interaction detected.") + case discordgo.SelectMenuComponent: + fmt.Println("Select menu interaction detected.") + default: + fmt.Println("Unknown message component interaction detected.") + } + } +} diff --git a/utils/responder.go b/utils/responder.go new file mode 100644 index 0000000..5289737 --- /dev/null +++ b/utils/responder.go @@ -0,0 +1,35 @@ +package utils + +import ( + "log" + + "github.com/bwmarrin/discordgo" +) + +func SendEphemeralResponse(s *discordgo.Session, i *discordgo.InteractionCreate, message string) { + err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: message, + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + if err != nil { + log.Printf("Error sending error response: %s", err) + } +} + +func SendFollowUpMessage(s *discordgo.Session, i *discordgo.InteractionCreate, content string, ephemeral bool) { + var flags discordgo.MessageFlags + if ephemeral { + flags = discordgo.MessageFlagsEphemeral + } + + _, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{ + Content: content, + Flags: flags, + }) + if err != nil { + log.Printf("Error sending followup message: %s", err) + } +} diff --git a/yuzaki/main.go b/yuzaki/main.go index ea548b8..11e1aa3 100644 --- a/yuzaki/main.go +++ b/yuzaki/main.go @@ -6,6 +6,7 @@ import ( "os" "os/signal" "syscall" + "yuzaki/commands" "yuzaki/config" "yuzaki/handlers" @@ -30,6 +31,7 @@ func init() { session.Identify.Intents = discordgo.IntentsAll session.AddHandler(ready) session.AddHandler(handlers.MessageGatewayHandler) + session.AddHandler(handlers.InteractionCreateHandler) } func main() { @@ -47,6 +49,9 @@ func setupAndRun(ctx context.Context) error { } defer session.Close() + log.Printf("Adding commands to %d guilds", len(session.State.Guilds)) + addApplicationCommands(session) + shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) @@ -59,66 +64,24 @@ func setupAndRun(ctx context.Context) error { } } +func addApplicationCommands(s *discordgo.Session) { + for _, guild := range s.State.Guilds { + registeredCommands, err := session.ApplicationCommandBulkOverwrite(session.State.User.ID, guild.ID, commands.Commands) + if err != nil { + log.Printf("error adding commands to guild %s: %v", guild.ID, err) + continue + } + log.Printf("added %d commands to guild %s", len(registeredCommands), guild.ID) + for _, command := range registeredCommands { + log.Printf("registered command %s", command.Name) + } + } +} + func ready(s *discordgo.Session, event *discordgo.Ready) { log.Printf("Logged in as %s on %d guilds", event.User.String(), len(event.Guilds)) if err := s.UpdateWatchStatus(0, "all users in Yuzaki's Canyon!"); err != nil { log.Printf("error setting status: %v", err) } log.Println("Bot is now running. Press CTRL-C to exit.") - - // On guild 1009009522767052860, assign all users a role with role id 1307471288415162428 - // var rolesAssigned, rolesSkipped int - // guild, err := s.Guild("1009009522767052860") - // if err != nil { - // log.Printf("error getting guild: %v", err) - // return - // } - - // var lastMemberID string - // for { - // members, err := s.GuildMembers(guild.ID, lastMemberID, 1000) - // if err != nil { - // log.Printf("error getting guild members: %v", err) - // return - // } - // if len(members) == 0 { - // break - // } - - // for _, member := range members { - // // skip if bot - // if member.User.Bot { - // continue - // } - - // // Check if member already has the role - // hasRole := false - // for _, roleID := range member.Roles { - // if roleID == "1307471288415162428" { - // hasRole = true - // break - // } - // } - - // if hasRole { - // log.Printf("Skipping role assignment for %s (%s) - already has role", member.User.Username, member.User.ID) - // rolesSkipped++ - // continue - // } - - // if err := s.GuildMemberRoleAdd(guild.ID, member.User.ID, "1307471288415162428"); err != nil { - // log.Printf("error adding role to %s (%s): %v", member.User.Username, member.User.ID, err) - // continue - // } - // log.Printf("Assigned role to %s (%s)", member.User.Username, member.User.ID) - // rolesAssigned++ - // } - - // if len(members) < 1000 { - // break - // } - // lastMemberID = members[len(members)-1].User.ID - // } - - // log.Printf("Operation complete: Assigned roles to %d members, skipped %d members", rolesAssigned, rolesSkipped) } |
