From d5903b61c41aae1952cea64d085d9447c71f69b0 Mon Sep 17 00:00:00 2001 From: evazion Date: Thu, 18 Mar 2021 22:50:44 -0500 Subject: [PATCH] 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. --- app/logical/discord_api_client.rb | 13 ++-- app/logical/discord_slash_command.rb | 61 ++++++++++--------- .../discord_slash_command/count_command.rb | 24 +++----- .../discord_slash_command/posts_command.rb | 35 +++++------ .../discord_slash_command/random_command.rb | 36 +++++------ .../discord_slash_command/time_command.rb | 24 +++----- .../discord_slash_command/wiki_command.rb | 28 +++------ 7 files changed, 94 insertions(+), 127 deletions(-) diff --git a/app/logical/discord_api_client.rb b/app/logical/discord_api_client.rb index db8bd7b9c..6b4035031 100644 --- a/app/logical/discord_api_client.rb +++ b/app/logical/discord_api_client.rb @@ -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) diff --git a/app/logical/discord_slash_command.rb b/app/logical/discord_slash_command.rb index 1d064b921..589174b47 100644 --- a/app/logical/discord_slash_command.rb +++ b/app/logical/discord_slash_command.rb @@ -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]}" diff --git a/app/logical/discord_slash_command/count_command.rb b/app/logical/discord_slash_command/count_command.rb index dce71ccf3..062fbce3d 100644 --- a/app/logical/discord_slash_command/count_command.rb +++ b/app/logical/discord_slash_command/count_command.rb @@ -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] diff --git a/app/logical/discord_slash_command/posts_command.rb b/app/logical/discord_slash_command/posts_command.rb index 68a8bd602..ae604efe4 100644 --- a/app/logical/discord_slash_command/posts_command.rb +++ b/app/logical/discord_slash_command/posts_command.rb @@ -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] diff --git a/app/logical/discord_slash_command/random_command.rb b/app/logical/discord_slash_command/random_command.rb index ea8537a39..be8931039 100644 --- a/app/logical/discord_slash_command/random_command.rb +++ b/app/logical/discord_slash_command/random_command.rb @@ -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] diff --git a/app/logical/discord_slash_command/time_command.rb b/app/logical/discord_slash_command/time_command.rb index e8089ef99..e96b2bc32 100644 --- a/app/logical/discord_slash_command/time_command.rb +++ b/app/logical/discord_slash_command/time_command.rb @@ -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] diff --git a/app/logical/discord_slash_command/wiki_command.rb b/app/logical/discord_slash_command/wiki_command.rb index 5c52dc161..a7acacac1 100644 --- a/app/logical/discord_slash_command/wiki_command.rb +++ b/app/logical/discord_slash_command/wiki_command.rb @@ -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?