From 0c0e86b7720531409f4d98135c6c41b87cec97bc Mon Sep 17 00:00:00 2001 From: Mathieu Trudel-Lapierre Date: Fri, 11 Dec 2020 04:43:03 -0500 Subject: [PATCH] FEATURE: Add support for Webex Teams (#49) --- config/locales/client.en.yml | 11 ++++ config/locales/server.en.yml | 8 ++- config/settings.yml | 9 ++- lib/discourse_chat/provider.rb | 1 + .../provider/webex/webex_provider.rb | 65 +++++++++++++++++++ .../provider/webex/webex_provider_spec.rb | 30 +++++++++ 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 lib/discourse_chat/provider/webex/webex_provider.rb create mode 100644 spec/lib/discourse_chat/provider/webex/webex_provider_spec.rb diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3a2e426..4d9d50f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -216,3 +216,14 @@ en: help: "The URL provided when you create a new incomming webhook" errors: invalid_channel: "That channel does not exist on Microsoft Teams" + webex: + title: "Webex Teams" + param: + name: + title: "Name" + help: "A Webex space name e.g. discourse" + webhook_url: + title: "Webhook URL" + help: "The URL provided when you create a new incomming webhook" + errors: + invalid_channel: "That channel does not exist on Webex" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 373a8b5..f618431 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -92,6 +92,12 @@ en: chat_integration_teams_enabled: "Enable the Microsoft Teams chat integration provider" chat_integration_teams_excerpt_length: "Microsoft Team post excerpt length" + ########################################### + ######## WEBEX TEAMS SETTINGS ######### + ########################################### + chat_integration_webex_enabled: "Enable the Webex Teams chat integration provider" + chat_integration_webex_excerpt_length: "Webex Team post excerpt length" + chat_integration: all_categories: "(all categories)" @@ -273,4 +279,4 @@ en: ########### GROUPME STRINGS ########## ####################################### groupme: - message_title: "posted" \ No newline at end of file + message_title: "posted" diff --git a/config/settings.yml b/config/settings.yml index 98ccac5..8563995 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -136,4 +136,11 @@ chat_integration: chat_integration_teams_enabled: default: false chat_integration_teams_excerpt_length: - default: 400 \ No newline at end of file + default: 400 +########################################### +######## WEBEX TEAMS SETTINGS ######### +########################################### + chat_integration_webex_enabled: + default: false + chat_integration_webex_excerpt_length: + default: 400 diff --git a/lib/discourse_chat/provider.rb b/lib/discourse_chat/provider.rb index 87c4a21..4d1a395 100644 --- a/lib/discourse_chat/provider.rb +++ b/lib/discourse_chat/provider.rb @@ -102,3 +102,4 @@ require_relative "provider/gitter/gitter_provider" require_relative "provider/flowdock/flowdock_provider" require_relative "provider/groupme/groupme_provider" require_relative "provider/teams/teams_provider" +require_relative "provider/webex/webex_provider" diff --git a/lib/discourse_chat/provider/webex/webex_provider.rb b/lib/discourse_chat/provider/webex/webex_provider.rb new file mode 100644 index 0000000..cdd36b1 --- /dev/null +++ b/lib/discourse_chat/provider/webex/webex_provider.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module DiscourseChat::Provider::WebexProvider + PROVIDER_NAME = "webex".freeze + PROVIDER_ENABLED_SETTING = :chat_integration_webex_enabled + CHANNEL_PARAMETERS = [ + { key: "name", regex: '^\S+$', unique: true }, + { key: "webhook_url", + regex: '^https:\/\/webexapis\.com\/v1\/webhooks\/incoming\/[A-Za-z0-9\-@\/]+\S+$', + unique: true, + hidden: true } + ] + + def self.trigger_notification(post, channel, rule) + message = get_message(post) + uri = URI(channel.data['webhook_url']) + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == 'https') + + req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') + req.body = message.to_json + response = http.request(req) + + unless response.kind_of? Net::HTTPSuccess + if response.body.include?('Invalid webhook URL') + error_key = 'chat_integration.provider.webex.errors.invalid_channel' + else + error_key = nil + end + raise ::DiscourseChat::ProviderError.new info: { error_key: error_key, + request: req.body, + response_code: response.code, + response_body: response.body } + end + + end + + def self.get_message(post) + display_name = "@#{post.user.username}" + full_name = post.user.name || "" + + topic = post.topic + + category = '' + if topic.category&.uncategorized? + category = "[#{I18n.t('uncategorized_category_name')}]" + elsif topic.category + category = (topic.category.parent_category) ? + "[#{topic.category.parent_category.name}/#{topic.category.name}]" : "[#{topic.category.name}]" + end + + markdown = "**#{topic.title}**: #{category}" + markdown += " #{topic.tags.map(&:name).join(', ')} " if topic.tags.present? + markdown += "(#{post.full_url}) from #{full_name} (#{display_name}):\n" + markdown += post.excerpt(SiteSetting.chat_integration_webex_excerpt_length, + text_entities: true, + strip_links: true, + remap_emoji: true + ) + + { "markdown": markdown } + end + +end diff --git a/spec/lib/discourse_chat/provider/webex/webex_provider_spec.rb b/spec/lib/discourse_chat/provider/webex/webex_provider_spec.rb new file mode 100644 index 0000000..682348a --- /dev/null +++ b/spec/lib/discourse_chat/provider/webex/webex_provider_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe DiscourseChat::Provider::WebexProvider do + let(:post) { Fabricate(:post) } + + describe '.trigger_notifications' do + before do + SiteSetting.chat_integration_webex_enabled = true + end + + let(:chan1) { DiscourseChat::Channel.create!(provider: 'webex', data: { name: 'discourse', webhook_url: 'https://webexapis.com/v1/webhooks/incoming/jAHJjVVQ1cgEwb4ikQQawIrGdUtlocKA9fSNvIyADQoYo0mI70pztWUDOu22gDRPJOEJtCsc688zi1RMa' }) } + + it 'sends a webhook request' do + stub1 = stub_request(:post, chan1.data['webhook_url']).to_return(body: "1") + described_class.trigger_notification(post, chan1, nil) + expect(stub1).to have_been_requested.once + end + + it 'handles errors correctly' do + stub1 = stub_request(:post, chan1.data['webhook_url']).to_return(status: 400, body: "{}") + expect(stub1).to have_been_requested.times(0) + expect { described_class.trigger_notification(post, chan1, nil) }.to raise_exception(::DiscourseChat::ProviderError) + expect(stub1).to have_been_requested.once + end + + end + +end