From b5e27412147ae25a07cf66cfab193f27c6c7ffe4 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 21 Jul 2017 15:48:57 +0100 Subject: [PATCH] Add discord support --- config/locales/client.en.yml | 17 ++++- config/locales/server.en.yml | 6 ++ config/settings.yml | 10 ++- lib/discourse_chat/provider.rb | 3 +- .../provider/discord/discord_provider.rb | 65 +++++++++++++++++++ .../provider/discord/discord_provider_spec.rb | 28 ++++++++ 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 lib/discourse_chat/provider/discord/discord_provider.rb create mode 100644 spec/lib/discourse_chat/provider/discord/discord_provider_spec.rb diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 4a92958..f53c5c3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -63,10 +63,23 @@ en: param: name: title: "Name" - help: "A name to describe the channel. It is not used for the connection for telegram." + help: "A name to describe the channel. It is not used for the connection to Telegram." chat_id: title: Chat ID help: A number given to you by the bot, or a broadcast channel identifier in the form @channelname errors: channel_not_found: "The specified channel does not exist on Telegram" - forbidden: "The bot does not have permission to post to this channel" \ No newline at end of file + forbidden: "The bot does not have permission to post to this channel" + + ####################################### + ########### DISCORD STRINGS ########### + ####################################### + discord: + title: "Discord" + param: + name: + title: "Name" + help: "A name to describe the channel. It is not used for the connection to Discord." + webhook_url: + title: Webhook URL + help: The webhook URL created in your Discord server settings \ No newline at end of file diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index d196d12..59b3a09 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -25,6 +25,12 @@ en: chat_integration_telegram_access_token: "Your bot's access token from the Telegram botfather" chat_integration_telegram_excerpt_length: "Telegram post excerpt length" chat_integration_telegram_enable_slash_commands: "Allow telegram subscriptions to be managed using 'slash commands'" + + ####################################### + ########## DISCORD SETTINGS ########### + ####################################### + chat_integration_discord_enabled: "Enable the Discord chat-integration provider" + chat_integration_discord_excerpt_length: "Discord post excerpt length" chat_integration: diff --git a/config/settings.yml b/config/settings.yml index 07b2cbd..16dd6d8 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -37,4 +37,12 @@ plugins: chat_integration_telegram_enable_slash_commands: default: true chat_integration_telegram_secret: - hidden: true \ No newline at end of file + hidden: true + +####################################### +########## DISCORD SETTINGS ########### +####################################### + chat_integration_discord_enabled: + default: false + chat_integration_discord_excerpt_length: + default: 400 \ No newline at end of file diff --git a/lib/discourse_chat/provider.rb b/lib/discourse_chat/provider.rb index 2e42c86..8c7b920 100644 --- a/lib/discourse_chat/provider.rb +++ b/lib/discourse_chat/provider.rb @@ -90,4 +90,5 @@ module DiscourseChat end require_relative "provider/slack/slack_provider.rb" -require_relative "provider/telegram/telegram_provider.rb" \ No newline at end of file +require_relative "provider/telegram/telegram_provider.rb" +require_relative "provider/discord/discord_provider.rb" \ No newline at end of file diff --git a/lib/discourse_chat/provider/discord/discord_provider.rb b/lib/discourse_chat/provider/discord/discord_provider.rb new file mode 100644 index 0000000..3d48270 --- /dev/null +++ b/lib/discourse_chat/provider/discord/discord_provider.rb @@ -0,0 +1,65 @@ +module DiscourseChat + module Provider + module DiscordProvider + PROVIDER_NAME = "discord".freeze + PROVIDER_ENABLED_SETTING = :chat_integration_discord_enabled + CHANNEL_PARAMETERS = [ + {key: "name", regex: '^\S+'}, + {key: "webhook_url", regex: '^https:\/\/discordapp\.com\/api\/webhooks\/'} + ] + + def self.send_message(url, message) + http = Net::HTTP.new("discordapp.com", 443) + http.use_ssl = true + + uri = URI(url) + + req = Net::HTTP::Post.new(uri, 'Content-Type' =>'application/json') + req.body = message.to_json + response = http.request(req) + + return response + end + + def self.generate_discord_message(post) + + display_name = "@#{post.user.username}" + full_name = post.user.name || "" + + if !(full_name.strip.empty?) && (full_name.strip.gsub(' ', '_').casecmp(post.user.username) != 0) && (full_name.strip.gsub(' ', '').casecmp(post.user.username) != 0) + display_name = "#{full_name} @#{post.user.username}" + end + + message = { + embeds:[{ + title: post.topic.title, + description: post.excerpt(SiteSetting.chat_integration_discord_excerpt_length, text_entities: true, strip_links: true, remap_emoji: true), + url: post.full_url, + author:{ + name: display_name, + url: Discourse.base_url+"/u/"+post.user.username, + icon_url: post.user.small_avatar_url + } + }] + } + + return message + end + + def self.trigger_notification(post, channel) + webhook_url = channel.data['webhook_url']+'?wait=true' + + message = generate_discord_message(post) + + response = send_message(webhook_url, message) + + if not response.kind_of? Net::HTTPSuccess + error_key = nil + raise ::DiscourseChat::ProviderError.new info: {error_key: error_key, message: message, response_body:response.body} + end + + end + + end + end +end \ No newline at end of file diff --git a/spec/lib/discourse_chat/provider/discord/discord_provider_spec.rb b/spec/lib/discourse_chat/provider/discord/discord_provider_spec.rb new file mode 100644 index 0000000..5b719ac --- /dev/null +++ b/spec/lib/discourse_chat/provider/discord/discord_provider_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe DiscourseChat::Provider::DiscordProvider do + let(:post) { Fabricate(:post) } + + describe '.trigger_notifications' do + before do + SiteSetting.chat_integration_discord_enabled = true + end + + let(:chan1){DiscourseChat::Channel.create!(provider:'discord', data:{name: "Awesome Channel", webhook_url: 'https://discordapp.com/api/webhooks/1234/abcd'})} + + it 'sends a webhook request' do + stub1 = stub_request(:post, 'https://discordapp.com/api/webhooks/1234/abcd?wait=true').to_return(status: 200) + described_class.trigger_notification(post, chan1) + expect(stub1).to have_been_requested.once + end + + it 'handles errors correctly' do + stub1 = stub_request(:post, "https://discordapp.com/api/webhooks/1234/abcd?wait=true").to_return(status: 400) + expect(stub1).to have_been_requested.times(0) + expect{described_class.trigger_notification(post, chan1)}.to raise_exception(::DiscourseChat::ProviderError) + expect(stub1).to have_been_requested.once + end + + end + +end