discord: add function to register all commands.

* Add a `DiscordSlashCommand.register_slash_commands!` method to register
  all slash commands with the Discord API.
* Allow registering global commands.
* Refactor slash commands to use class attributes for the command
  name, description, and options.
This commit is contained in:
evazion
2021-03-18 22:50:44 -05:00
parent f75b1ddb4a
commit d5903b61c4
7 changed files with 94 additions and 127 deletions

View File

@@ -3,23 +3,26 @@ class DiscordApiClient
BASE_URL = "https://discord.com/api/v8"
attr_reader :application_id, :guild_id, :bot_token, :http
attr_reader :application_id, :bot_token, :http
def initialize(application_id: Danbooru.config.discord_application_client_id, guild_id: Danbooru.config.discord_guild_id, bot_token: Danbooru.config.discord_bot_token, http: Danbooru::Http.new)
def initialize(application_id: Danbooru.config.discord_application_client_id, bot_token: Danbooru.config.discord_bot_token, http: Danbooru::Http.new)
@application_id = application_id
@guild_id = guild_id
@bot_token = bot_token
@http = http
end
def register_slash_command(name:, description:, options: [])
def register_slash_command(name:, description:, options: [], guild_id: nil)
json = {
name: name,
description: description,
options: options
}
post("/applications/#{application_id}/guilds/#{guild_id}/commands", json)
if guild_id.present?
post("/applications/#{application_id}/guilds/#{guild_id}/commands", json)
else
post("/applications/#{application_id}/commands", json)
end
end
def get_channel(channel_id, **options)

View File

@@ -1,14 +1,6 @@
class DiscordSlashCommand
class WebhookVerificationError < StandardError; end
COMMANDS = {
count: DiscordSlashCommand::CountCommand,
posts: DiscordSlashCommand::PostsCommand,
random: DiscordSlashCommand::RandomCommand,
time: DiscordSlashCommand::TimeCommand,
wiki: DiscordSlashCommand::WikiCommand,
}
# https://discord.com/developers/docs/interactions/slash-commands#interaction-interactiontype
module InteractionType
Ping = 1
@@ -21,6 +13,16 @@ class DiscordSlashCommand
Integer = 4
end
# The name of the slash command.
class_attribute :name
# A description of the slash command.
class_attribute :description
# The parameters of the slash command.
# https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoption
class_attribute :options, default: []
attr_reader :data, :discord
# `data` is the the interaction data sent to us by Discord for the command.
@@ -30,22 +32,6 @@ class DiscordSlashCommand
@discord = discord
end
# The name of the slash command.
def name
raise NotImplementedError
end
# A description of the slash command.
def description
raise NotImplementedError
end
# The parameters of the slash command.
# https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoption
def options
[]
end
# Should return the response to the command.
def call
# respond_with("message")
@@ -81,10 +67,27 @@ class DiscordSlashCommand
discord.get_channel(data[:channel_id], cache: 1.minute)
end
# Register the command with the Discord API (replacing it if it already exists).
# https://discord.com/developers/docs/interactions/slash-commands#registering-a-command
def register_slash_command
discord.register_slash_command(name: name, description: description, options: options)
class_methods do
# Register all commands with Discord.
def register_slash_commands!
slash_commands.values.each(&:register_slash_command!)
end
# Register the command with Discord (replacing it if it already exists).
# https://discord.com/developers/docs/interactions/slash-commands#registering-a-command
def register_slash_command!(discord: DiscordApiClient.new, guild_id: Danbooru.config.discord_guild_id)
discord.register_slash_command(name: name, description: description, options: options, guild_id: guild_id)
end
def slash_commands
{
count: DiscordSlashCommand::CountCommand,
posts: DiscordSlashCommand::PostsCommand,
random: DiscordSlashCommand::RandomCommand,
time: DiscordSlashCommand::TimeCommand,
wiki: DiscordSlashCommand::WikiCommand,
}
end
end
end
@@ -101,7 +104,7 @@ class DiscordSlashCommand
{ type: InteractionType::Ping }
when InteractionType::ApplicationCommand
name = data.dig(:data, :name)
klass = COMMANDS.fetch(name&.to_sym)
klass = slash_commands.fetch(name&.to_sym)
klass.new(data: data).call
else
raise NotImplementedError, "unknown Discord interaction type #{data[:type]}"

View File

@@ -1,21 +1,13 @@
class DiscordSlashCommand
class CountCommand < DiscordSlashCommand
def name
"count"
end
def description
"Do a tag search and return the number of results"
end
def options
[{
name: "tags",
description: "The tags to search",
required: true,
type: ApplicationCommandOptionType::String
}]
end
self.name = "count"
self.description = "Do a tag search and return the number of results"
self.options = [{
name: "tags",
description: "The tags to search",
required: true,
type: ApplicationCommandOptionType::String
}]
def call
tags = params[:tags]

View File

@@ -2,28 +2,21 @@ class DiscordSlashCommand
class PostsCommand < DiscordSlashCommand
extend Memoist
def name
"posts"
end
self.name = "posts"
self.description = "Do a tag search"
def description
"Do a tag search"
end
def options
[
{
name: "tags",
description: "The tags to search",
type: ApplicationCommandOptionType::String
},
{
name: "limit",
description: "The number of posts to show (max 10)",
type: ApplicationCommandOptionType::Integer
}
]
end
self.options = [
{
name: "tags",
description: "The tags to search",
type: ApplicationCommandOptionType::String
},
{
name: "limit",
description: "The number of posts to show (max 10)",
type: ApplicationCommandOptionType::Integer
}
]
def call
tags = params[:tags]

View File

@@ -1,27 +1,19 @@
class DiscordSlashCommand
class RandomCommand < DiscordSlashCommand
def name
"random"
end
def description
"Show a random post"
end
def options
[
{
name: "tags",
description: "The tags to search",
type: ApplicationCommandOptionType::String
},
{
name: "limit",
description: "The number of posts to show (max 10)",
type: ApplicationCommandOptionType::Integer
}
]
end
self.name = "random"
self.description = "Show a random post"
self.options = [
{
name: "tags",
description: "The tags to search",
type: ApplicationCommandOptionType::String
},
{
name: "limit",
description: "The number of posts to show (max 10)",
type: ApplicationCommandOptionType::Integer
}
]
def call
tags = params[:tags]

View File

@@ -1,21 +1,13 @@
class DiscordSlashCommand
class TimeCommand < DiscordSlashCommand
def name
"time"
end
def description
"Show the current time around the world"
end
def options
[{
name: "name",
description: "The name of the country to show",
required: false,
type: ApplicationCommandOptionType::String
}]
end
self.name = "time"
self.description = "Show the current time around the world"
self.options = [{
name: "name",
description: "The name of the country to show",
required: false,
type: ApplicationCommandOptionType::String
}]
def call
name = params[:name]

View File

@@ -2,24 +2,16 @@ class DiscordSlashCommand
class WikiCommand < DiscordSlashCommand
extend Memoist
def name
"wiki"
end
def description
"Show a wiki page"
end
def options
[
{
name: "name",
description: "The name of the wiki page",
required: true,
type: ApplicationCommandOptionType::String
},
]
end
self.name = "wiki"
self.description = "Show a wiki page"
self.options = [
{
name: "name",
description: "The name of the wiki page",
required: true,
type: ApplicationCommandOptionType::String
},
]
def call
if wiki_page.nil?