package level import ( "context" "strconv" "velox-bot/internal/db/services" "github.com/bwmarrin/discordgo" ) var LevelConfigCommand = &discordgo.ApplicationCommand{ Name: "slvl", Description: "Leveling System", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "toggle", Description: "Toggle the leveling system", }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "set", Description: "Set the level of a user", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionUser, Name: "user", Description: "The user to set the level of", Required: true, }, { Type: discordgo.ApplicationCommandOptionInteger, Name: "level", Description: "The level to set the user to", Required: true, }, }, }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "set-channel", Description: "Set the level up channel", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionChannel, Name: "channel", Description: "The channel to set the level up channel to. If not provided, the current channel will be used.", Required: true, }, }, }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "set-message", Description: "Set the level up message", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionString, Name: "message", Description: "Level-up message. Variables: {user}, {level}", Required: true, }, }, }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "set-reward", Description: "Set role reward for a level", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionInteger, Name: "level", Description: "Level to reward", Required: true, }, { Type: discordgo.ApplicationCommandOptionRole, Name: "role", Description: "Role to grant", Required: true, }, }, }, }, } func HandleLevelConfig(s *discordgo.Session, i *discordgo.InteractionCreate) { data := i.ApplicationCommandData() subCommand := data.Options[0].Name switch subCommand { case "toggle": HandleLevelToggle(s, i) case "set": HandleLevelSet(s, i) case "set-channel": HandleLevelSetChannel(s, i) case "set-message": HandleLevelSetMessage(s, i) case "set-reward": HandleLevelSetReward(s, i) default: s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid subcommand.", Flags: discordgo.MessageFlagsEphemeral, }, }) } } func HandleLevelToggle(s *discordgo.Session, i *discordgo.InteractionCreate) { // Basic permission check: require Manage Guild permission if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You don't have permission to manage leveling settings.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } if services.Global == nil || services.Global.LevelSettings == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling service is not available.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } ctx := context.Background() guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid guild ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } enabled, err := services.Global.LevelSettings.ToggleLevelSystem(ctx, guildID) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Failed to toggle leveling system.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } status := "disabled" if enabled { status = "enabled" } s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling system " + status + " for this server.", Flags: discordgo.MessageFlagsEphemeral, }, }) } func HandleLevelSet(s *discordgo.Session, i *discordgo.InteractionCreate) { // Basic permission check: require Manage Guild permission if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You don't have permission to manage leveling settings.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } // check if the leveling service is available if services.Global == nil || services.Global.Level == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling service is not available.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } data := i.ApplicationCommandData() optMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(data.Options[0].Options)) for _, opt := range data.Options[0].Options { optMap[opt.Name] = opt } userOpt, ok := optMap["user"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing user option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } levelOpt, ok := optMap["level"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing level option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } targetUser := userOpt.UserValue(s) if targetUser == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid user.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } // prevent setting bots (including ourselves) if targetUser.Bot { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You can't set a bot's level.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } newLevel := int(levelOpt.IntValue()) ctx := context.Background() guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid guild ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } userID, err := strconv.ParseInt(targetUser.ID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid user ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } err = services.Global.Level.SetLevel(ctx, guildID, userID, newLevel) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Failed to set level.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Level set to " + strconv.Itoa(newLevel) + " for " + targetUser.Mention() + ".", Flags: discordgo.MessageFlagsEphemeral, }, }) } func HandleLevelSetChannel(s *discordgo.Session, i *discordgo.InteractionCreate) { // Basic permission check: require Manage Guild permission if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You don't have permission to manage leveling settings.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } // check if the leveling service is available if services.Global == nil || services.Global.Level == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling service is not available.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid guild ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } data := i.ApplicationCommandData() optMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(data.Options[0].Options)) for _, opt := range data.Options[0].Options { optMap[opt.Name] = opt } channelOpt, ok := optMap["channel"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing channel option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } channelID := channelOpt.ChannelValue(s) if channelID == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid channel.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } ctx := context.Background() channelIDInt, err := strconv.ParseInt(channelID.ID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid channel ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } err = services.Global.LevelSettings.SetLevelUpChannel(ctx, guildID, channelIDInt) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Failed to set level up channel.", Flags: discordgo.MessageFlagsEphemeral, }, }) } s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Level up channel set to " + channelID.Mention() + ".", Flags: discordgo.MessageFlagsEphemeral, }, }) } func HandleLevelSetMessage(s *discordgo.Session, i *discordgo.InteractionCreate) { // Basic permission check: require Manage Guild permission if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You don't have permission to manage leveling settings.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } // check if the leveling service is available if services.Global == nil || services.Global.Level == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling service is not available.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid guild ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } data := i.ApplicationCommandData() optMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(data.Options[0].Options)) for _, opt := range data.Options[0].Options { optMap[opt.Name] = opt } messageOpt, ok := optMap["message"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing message option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } message := messageOpt.StringValue() if message == "" { message = "GG {user}, you reached level {level}!" } ctx := context.Background() err = services.Global.LevelSettings.SetLevelUpMessage(ctx, guildID, message) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Failed to set level up channel.", Flags: discordgo.MessageFlagsEphemeral, }, }) } s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Level up message set to " + message + ".", Flags: discordgo.MessageFlagsEphemeral, }, }) } func HandleLevelSetReward(s *discordgo.Session, i *discordgo.InteractionCreate) { // Basic permission check: require Manage Guild permission if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "You don't have permission to manage leveling settings.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } // check if the leveling service is available if services.Global == nil || services.Global.LevelSettings == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Leveling service is not available.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid guild ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } data := i.ApplicationCommandData() optMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(data.Options[0].Options)) for _, opt := range data.Options[0].Options { optMap[opt.Name] = opt } levelOpt, ok := optMap["level"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing level option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } roleOpt, ok := optMap["role"] if !ok { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Missing role option.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } level := int(levelOpt.IntValue()) role := roleOpt.RoleValue(s, i.GuildID) if role == nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid role.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } roleID, err := strconv.ParseInt(role.ID, 10, 64) if err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Invalid role ID.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } ctx := context.Background() if err := services.Global.LevelSettings.SetRoleRewardForLevel(ctx, guildID, level, roleID); err != nil { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Failed to set reward.", Flags: discordgo.MessageFlagsEphemeral, }, }) return } s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Reward set: level " + strconv.Itoa(level) + " -> " + role.Mention(), Flags: discordgo.MessageFlagsEphemeral, }, }) }