diff --git a/config.yml.example b/config.yml.example index fc5f0b8..199e10d 100644 --- a/config.yml.example +++ b/config.yml.example @@ -48,6 +48,9 @@ moderation: ## Mod role to be pinged in report posts #mod_role_id: "" +## Guild ID to scope bot commands to (optional, needed for prompt updates) + #guild_id: "" + ## Logging settings logging: ## Size of log file (MB) diff --git a/server/config.go b/server/config.go index a8119b3..bc22f98 100644 --- a/server/config.go +++ b/server/config.go @@ -43,6 +43,7 @@ type Config struct { moderation struct { botToken string + guildId string channelId string modRoleId string } @@ -88,6 +89,7 @@ type ConfigFile struct { Moderation *struct { BotToken string `yaml:"bot_token"` ChannelID string `yaml:"channel_id"` + GuildID string `yaml:"guild_id"` ModRoleID string `yaml:"mod_role_id"` } `yaml:"moderation"` @@ -182,6 +184,7 @@ func parseConfigFile(filename string) *Config { config.moderation.botToken = mod.BotToken config.moderation.channelId = mod.ChannelID config.moderation.modRoleId = mod.ModRoleID + config.moderation.guildId = mod.GuildID } if ipc := configFile.Ipc; ipc != nil { diff --git a/server/report.go b/server/report.go index 77d2262..a841ffb 100644 --- a/server/report.go +++ b/server/report.go @@ -102,6 +102,9 @@ func initModBot() { case discordgo.InteractionModalSubmit: botHandleModalResponse(&resp, action.ModalSubmitData(), action.Interaction) return + case discordgo.InteractionApplicationCommand: + botHandleCommandResponse(&resp, action.ApplicationCommandData()) + return } if action.Type != discordgo.InteractionMessageComponent { @@ -255,10 +258,17 @@ func initModBot() { } }) + bot.Identify.Intents = discordgo.IntentsGuilds if err = bot.Open(); err != nil { log.Printf("bot/open: %s", err) return } + + if err = registerBotCommands(); err != nil { + log.Printf("bot/registerBotCommands: %s", err) + return + } + } func parseMsgIdFromComponent(msgObj *discordgo.Message) string { @@ -335,6 +345,90 @@ func botHandleModalResponse(resp *discordgo.InteractionResponse, data discordgo. } } +func botHandleCommandResponse(resp *discordgo.InteractionResponse, data discordgo.ApplicationCommandInteractionData) { + args := data.Options + switch data.Name { + case "pinfo": + if len(args) != 1 { + setResponse(resp, "Usage: /pinfo ") + return + } + playerid := args[0].StringValue() + var ( + onlineGames []string + name, uuid string + banned, muted bool + err error + ) + rows, err := db.Query(` +SELECT + pgd.name, pgd.uuid, pgd.game, pgd.online, players.banned, players.muted +FROM playerGameData pgd +JOIN players ON players.uuid = pgd.uuid +WHERE pgd.name = ? OR pgd.uuid = ?`, playerid, playerid) + if err != nil { + setResponse(resp, fmt.Sprintf("pinfo: sql error: %s", err)) + return + } + + defer rows.Close() + for rows.Next() { + var ( + game string + online bool + ) + err = rows.Scan(&name, &uuid, &game, &online, &banned, &muted) + if err != nil { + setResponse(resp, fmt.Sprintf("pinfo: sql error: %s", err)) + return + } + if online { + onlineGames = append(onlineGames, game) + } + } + msg := fmt.Sprintf(`##### Player Info +name=%s uuid=%s +banned=%t muted=%t +online in: %s`, name, uuid, banned, muted, strings.Join(onlineGames, ", ")) + setResponse(resp, msg) + default: + setResponse(resp, "Unknown command") + } +} + +func registerBotCommands() (err error) { + if bot == nil { + return + } + + _, err = bot.ApplicationCommandCreate( + bot.State.User.ID, + config.moderation.guildId, + &discordgo.ApplicationCommand{ + Name: "pinfo", + Description: "Show player info", + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionString, + Name: "name", + Description: "player name or uuid", + Required: true, + }, + }, + }, + ) + + return +} + +func setResponse(resp *discordgo.InteractionResponse, err string) { + resp.Type = discordgo.InteractionResponseChannelMessageWithSource + resp.Data = &discordgo.InteractionResponseData{ + Flags: discordgo.MessageFlagsEphemeral, + Content: err, + } +} + func initModActionExpirations() { modActionExpirations = make(map[ModAction]oneshotJob)