diff options
| -rw-r--r-- | .env.example | 4 | ||||
| -rw-r--r-- | config/config.go | 49 | ||||
| -rw-r--r-- | handlers/messageHandlers/poketwoHandler.go | 108 | ||||
| -rw-r--r-- | yuzaki/main.go | 64 |
4 files changed, 164 insertions, 61 deletions
diff --git a/.env.example b/.env.example index 9dc61af..d88b751 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,7 @@ DISCORD_BOT_TOKEN=YOUR_DISCORD_BOT_TOKEN DATABASE_DRIVER=SQLITE # POSTGRES | MYSQL | SQLITE | MSSQL DSN=YOUR_DATABASE_DSN # Example: sqlite://yuzaki.db + + +# Guild Specific Configuration +POKETWO_CHANNELS= # Comma separated list of channels to listen for Poketwo spawns diff --git a/config/config.go b/config/config.go index 4f7a666..1d78fea 100644 --- a/config/config.go +++ b/config/config.go @@ -8,10 +8,15 @@ import ( "github.com/joho/godotenv" ) +var BotConfig *Config + type Config struct { - DiscordToken string - DataSourceName string - DatabaseDriver string + DiscordToken string + DataSourceName string + DatabaseDriver string + ConfiguredChannels struct { + PoketwoSpawns []string + } } var validDBDrivers = map[string]bool{ @@ -21,12 +26,14 @@ var validDBDrivers = map[string]bool{ "mssql": true, } -func Load() (*Config, error) { +func Load() error { if err := godotenv.Load(); err != nil { - return nil, fmt.Errorf("loading env file: %w", err) + return fmt.Errorf("loading env file: %w", err) } config := &Config{} + + // Basic string variables requiredVars := map[string]*string{ "DISCORD_BOT_TOKEN": &config.DiscordToken, "DSN": &config.DataSourceName, @@ -36,16 +43,24 @@ func Load() (*Config, error) { for envKey, configVar := range requiredVars { value, err := getEnv(envKey) if err != nil { - return nil, fmt.Errorf("getting %s: %w", envKey, err) + return fmt.Errorf("getting %s: %w", envKey, err) } *configVar = value } + channels, err := getEnvStringSlice("POKETWO_CHANNELS") + if err != nil { + return fmt.Errorf("getting POKETWO_CHANNELS: %w", err) + } + config.ConfiguredChannels.PoketwoSpawns = channels + fmt.Println(config.ConfiguredChannels.PoketwoSpawns) + if err := validateConfig(config); err != nil { - return nil, fmt.Errorf("validating config: %w", err) + return fmt.Errorf("validating config: %w", err) } - return config, nil + BotConfig = config + return nil } func validateConfig(config *Config) error { @@ -74,6 +89,24 @@ func getEnv(key string) (string, error) { return strings.TrimSpace(value), nil } +func getEnvStringSlice(key string) ([]string, error) { + value, err := getEnv(key) + if err != nil { + return nil, err + } + + if value == "" { + return []string{}, nil + } + + items := strings.Split(value, ",") + // Trim spaces from each item + for i, item := range items { + items[i] = strings.TrimSpace(item) + } + return items, nil +} + // Future implementation for getting other types of environment variables // func getEnvInt(key string) (int, error) { // value, err := getEnv(key) diff --git a/handlers/messageHandlers/poketwoHandler.go b/handlers/messageHandlers/poketwoHandler.go index f124e02..3ceb83b 100644 --- a/handlers/messageHandlers/poketwoHandler.go +++ b/handlers/messageHandlers/poketwoHandler.go @@ -4,14 +4,12 @@ import ( "fmt" "strings" "time" + "yuzaki/config" "github.com/bwmarrin/discordgo" ) -var ( - poketwoID = "716390085896962058" - poketwoChannels = []string{"1307335103508254844", "1307335132046168074"} -) +const poketwoID = "716390085896962058" // Pokétwo's user ID; TODO: Move to config? func PoketwoHandler(s *discordgo.Session, m *discordgo.MessageCreate) { isAllowed := isAllowedChannel(m.ChannelID) @@ -23,61 +21,75 @@ func PoketwoHandler(s *discordgo.Session, m *discordgo.MessageCreate) { return } - isCommand := strings.HasPrefix(strings.ToLower(m.Content), "p!") || + if isPoketwoCommand(m) && !isAllowed { + handleUnauthorizedCommand(s, m) + } +} + +func isPoketwoCommand(m *discordgo.MessageCreate) bool { + return strings.HasPrefix(strings.ToLower(m.Content), "p!") || (len(m.Mentions) > 0 && m.Mentions[0].ID == poketwoID) +} - if isCommand && !isAllowed { - channel, err := s.Channel(m.ChannelID) - if err != nil { - return - } +func handleUnauthorizedCommand(s *discordgo.Session, m *discordgo.MessageCreate) { + channel, err := s.Channel(m.ChannelID) + if err != nil { + return + } - fmt.Printf("%s#%s sent a Poketwo command in #%s - deleting\n", - m.Author.Username, m.Author.Discriminator, channel.Name) + fmt.Printf("%s#%s sent a Poketwo command in #%s - deleting\n", + m.Author.Username, m.Author.Discriminator, channel.Name) - go func() { - time.Sleep(1 * time.Second) - s.ChannelMessageDelete(m.ChannelID, m.ID) - }() - - var channelMentions string - for i, channelID := range poketwoChannels { - if i == len(poketwoChannels)-1 && i > 0 { - channelMentions += "or " - } - channelMentions += fmt.Sprintf("<#%s>", channelID) - if i < len(poketwoChannels)-2 { - channelMentions += ", " - } - } + sendRedirectMessage(s, m.Author.ID, m.ChannelID) - _, err = s.ChannelMessageSend(m.ChannelID, - fmt.Sprintf("<@%s>, please use %s for Pokétwo commands. If you need roles, visit <id:customize> to get them.", - m.Author.ID, channelMentions)) + go deleteMessageWithDelay(s, m.ChannelID, m.ID) + go cleanupPoketwoResponse(s, m.ChannelID) +} - if err != nil { - return - } +func sendRedirectMessage(s *discordgo.Session, authorID, channelID string) { + channelMentions := formatChannelMentions() + message := fmt.Sprintf("<@%s>, please use %s for Pokétwo commands. If you need roles, visit <id:customize> to get them.", + authorID, channelMentions) - go func() { - time.Sleep(1 * time.Second) - messages, err := s.ChannelMessages(m.ChannelID, 5, "", "", "") - if err != nil { - return - } - - for _, msg := range messages { - if msg.Author.ID == poketwoID { - s.ChannelMessageDelete(m.ChannelID, msg.ID) - break - } - } - }() + s.ChannelMessageSend(channelID, message) +} + +func formatChannelMentions() string { + var mentions []string + for _, channelID := range config.BotConfig.ConfiguredChannels.PoketwoSpawns { + mentions = append(mentions, fmt.Sprintf("<#%s>", channelID)) + } + + if len(mentions) > 1 { + lastMention := mentions[len(mentions)-1] + mentions = mentions[:len(mentions)-1] + return strings.Join(mentions, ", ") + " or " + lastMention + } + return mentions[0] +} + +func cleanupPoketwoResponse(s *discordgo.Session, channelID string) { + time.Sleep(1 * time.Second) + messages, err := s.ChannelMessages(channelID, 5, "", "", "") + if err != nil { + return + } + + for _, msg := range messages { + if msg.Author.ID == poketwoID { + s.ChannelMessageDelete(channelID, msg.ID) + break + } } } +func deleteMessageWithDelay(s *discordgo.Session, channelID, messageID string) { + time.Sleep(2 * time.Second) + s.ChannelMessageDelete(channelID, messageID) +} + func isAllowedChannel(channelID string) bool { - for _, channel := range poketwoChannels { + for _, channel := range config.BotConfig.ConfiguredChannels.PoketwoSpawns { if channelID == channel { return true } diff --git a/yuzaki/main.go b/yuzaki/main.go index c54962d..ea548b8 100644 --- a/yuzaki/main.go +++ b/yuzaki/main.go @@ -13,18 +13,16 @@ import ( ) var ( - configuration *config.Config - session *discordgo.Session + session *discordgo.Session ) func init() { var err error - configuration, err = config.Load() - if err != nil { + if err = config.Load(); err != nil { log.Fatalf("loading config: %v", err) } - session, err = discordgo.New("Bot " + configuration.DiscordToken) + session, err = discordgo.New("Bot " + config.BotConfig.DiscordToken) if err != nil { log.Fatalf("creating discord session: %v", err) } @@ -67,4 +65,60 @@ func ready(s *discordgo.Session, event *discordgo.Ready) { 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) } |
