GroupMe added as Provider (#36)
* adds groupme configuration and relative * first pass at groupme provider * add group id site setting w/ english translation * rework to use bots groupme api intstead of developer, no access tokens reqd also should catch 404 response codes * add strings to locale yml files for i18n * better error handling for multi-bot case * add channel param for separate Groupme instances, include name in errorbody * bugfix for multi bot msg forwarding this gives us the ability to treat diff groupme instances like slack channels, lots of people use them this way for better or worse. use case is certain category posts only go to a particular GM instance * add spec for groupme provider * fix channel param constraint * specify channels by groupme name, not bot api token * fix some linting issues w/ spacing * newline and trailing space lint fixes
This commit is contained in:
parent
ad3e73c964
commit
ccbc41428b
|
@ -189,3 +189,15 @@ en:
|
||||||
flow_token:
|
flow_token:
|
||||||
title: "Flow Token"
|
title: "Flow Token"
|
||||||
help: "The flow token provided after creating a source for a flow into which you want to send messages."
|
help: "The flow token provided after creating a source for a flow into which you want to send messages."
|
||||||
|
#######################################
|
||||||
|
########## GROUPME STRINGS ###########
|
||||||
|
#######################################
|
||||||
|
groupme:
|
||||||
|
title: "GroupMe"
|
||||||
|
param:
|
||||||
|
groupme_instance_name:
|
||||||
|
title: "GroupMe Instance Name"
|
||||||
|
help: "name of the Groupme instance as listed in Site Settings. use 'all' to send to all instances"
|
||||||
|
errors:
|
||||||
|
not_found: "The path you attempted to post your message to was not found. Check the Bot ID in Site Settings."
|
||||||
|
instance_names_issue: "instance names incorrectly formatted or not provided"
|
||||||
|
|
|
@ -78,6 +78,14 @@ en:
|
||||||
chat_integration_flowdock_enabled: "Enable the Flowdock chat integration provider"
|
chat_integration_flowdock_enabled: "Enable the Flowdock chat integration provider"
|
||||||
chat_integration_flowdock_excerpt_length: "Flowdock post excerpt length"
|
chat_integration_flowdock_excerpt_length: "Flowdock post excerpt length"
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
########## GROUPME SETTINGS ##########
|
||||||
|
#######################################
|
||||||
|
chat_integration_groupme_enabled: "Enable the Groupme chat integration provider"
|
||||||
|
chat_integration_groupme_excerpt_length: "Groupme post excerpt length"
|
||||||
|
chat_integration_groupme_bot_ids: "*required* Bot IDs, seperated by ',' if there are multiple"
|
||||||
|
chat_integration_groupme_instance_names: " *required* Name of the GroupMe chat, seperated by ',' if there are multiple (same order as Bot IDs)"
|
||||||
|
|
||||||
chat_integration:
|
chat_integration:
|
||||||
|
|
||||||
all_categories: "(all categories)"
|
all_categories: "(all categories)"
|
||||||
|
@ -252,3 +260,10 @@ en:
|
||||||
#######################################
|
#######################################
|
||||||
flowdock:
|
flowdock:
|
||||||
message_title: "posted"
|
message_title: "posted"
|
||||||
|
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
########### GROUPME STRINGS ##########
|
||||||
|
#######################################
|
||||||
|
groupme:
|
||||||
|
message_title: "posted"
|
|
@ -117,3 +117,16 @@ chat_integration:
|
||||||
default: false
|
default: false
|
||||||
chat_integration_flowdock_excerpt_length:
|
chat_integration_flowdock_excerpt_length:
|
||||||
default: 400
|
default: 400
|
||||||
|
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
########## GROUPME SETTINGS ##########
|
||||||
|
#######################################
|
||||||
|
chat_integration_groupme_enabled:
|
||||||
|
default: false
|
||||||
|
chat_integration_groupme_excerpt_length:
|
||||||
|
default: 400
|
||||||
|
chat_integration_groupme_bot_ids:
|
||||||
|
default: ''
|
||||||
|
chat_integration_groupme_instance_names:
|
||||||
|
default: ''
|
|
@ -100,3 +100,4 @@ require_relative "provider/zulip/zulip_provider"
|
||||||
require_relative "provider/rocketchat/rocketchat_provider"
|
require_relative "provider/rocketchat/rocketchat_provider"
|
||||||
require_relative "provider/gitter/gitter_provider"
|
require_relative "provider/gitter/gitter_provider"
|
||||||
require_relative "provider/flowdock/flowdock_provider"
|
require_relative "provider/flowdock/flowdock_provider"
|
||||||
|
require_relative "provider/groupme/groupme_provider"
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module DiscourseChat::Provider::GroupmeProvider
|
||||||
|
PROVIDER_NAME = "groupme".freeze
|
||||||
|
PROVIDER_ENABLED_SETTING = :chat_integration_groupme_enabled
|
||||||
|
CHANNEL_PARAMETERS = [
|
||||||
|
{ key: "groupme_instance_name", regex: '[\s\S]*', unique: true }
|
||||||
|
]
|
||||||
|
|
||||||
|
def self.generate_groupme_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
|
||||||
|
|
||||||
|
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
|
||||||
|
pre_post_text = "#{display_name}: #{topic.title}(#{post.full_url}) #{category} #{topic.tags.present? ? topic.tags.map(&:name).join(', ') : ''}"
|
||||||
|
data = {
|
||||||
|
text: "#{pre_post_text} - #{post.excerpt(SiteSetting.chat_integration_groupme_excerpt_length, text_entities: true, strip_links: true, remap_emoji: true)}"
|
||||||
|
}
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_via_webhook(message, channel)
|
||||||
|
# loop through all the bot IDs
|
||||||
|
last_error_raised = nil
|
||||||
|
num_errors = 0
|
||||||
|
# split on commas, but remove leading/trailing spaces
|
||||||
|
bot_ids = SiteSetting.chat_integration_groupme_bot_ids.split(/\s*,\s*/)
|
||||||
|
instance_names = SiteSetting.chat_integration_groupme_instance_names.split(/\s*,\s*/)
|
||||||
|
|
||||||
|
unless instance_names.length() == bot_ids.length()
|
||||||
|
instance_names = [I18n.t('chat_integration.provider.groupme.errors.instance_names_issue')] * bot_ids.length()
|
||||||
|
end
|
||||||
|
|
||||||
|
name_to_id = Hash[instance_names.zip(bot_ids)]
|
||||||
|
user_input_channel = channel.data['groupme_instance_name'].strip
|
||||||
|
unless user_input_channel.eql? 'all'
|
||||||
|
instance_names = [user_input_channel]
|
||||||
|
end
|
||||||
|
instance_names.each { |instance_name|
|
||||||
|
bot_id = name_to_id["#{instance_name}"]
|
||||||
|
uri = URI("https://api.groupme.com/v3/bots/post")
|
||||||
|
http = Net::HTTP.new(uri.host, uri.port)
|
||||||
|
http.use_ssl = (uri.scheme == 'https')
|
||||||
|
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
|
||||||
|
message[:bot_id] = bot_id
|
||||||
|
req.body = message.to_json
|
||||||
|
response = http.request(req)
|
||||||
|
unless response.kind_of? Net::HTTPSuccess
|
||||||
|
num_errors += 1
|
||||||
|
if response.code.to_s == '404'
|
||||||
|
error_key = 'chat_integration.provider.groupme.errors.not_found'
|
||||||
|
else
|
||||||
|
error_key = nil
|
||||||
|
end
|
||||||
|
last_error_raised = { error_key: error_key, groupme_name: instance_name, bot_id: bot_id, request: req.body, response_code: response.code, response_body: response.body }
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if last_error_raised
|
||||||
|
successfully_sent = instance_names.length() - num_errors
|
||||||
|
last_error_raised[:success_rate] = "#{successfully_sent}/#{instance_names.length()}"
|
||||||
|
raise ::DiscourseChat::ProviderError.new info: last_error_raised
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.trigger_notification(post, channel)
|
||||||
|
data_package = generate_groupme_message(post)
|
||||||
|
self.send_via_webhook(data_package, channel)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe DiscourseChat::Provider::GroupmeProvider do
|
||||||
|
let(:post) { Fabricate(:post) }
|
||||||
|
|
||||||
|
describe '.trigger_notifications' do
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_groupme_enabled = true
|
||||||
|
SiteSetting.chat_integration_groupme_bot_ids = '1a2b3c4d5e6f7g'
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:chan1) { DiscourseChat::Channel.create!(provider: 'groupme', data: { groupme_bot_id: '1a2b3c4d5e6f7g' }) }
|
||||||
|
|
||||||
|
it 'sends a request' do
|
||||||
|
stub1 = stub_request(:post, "https://api.groupme.com/v3/bots/post").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://api.groupme.com/v3/bots/post").to_return(status: 404, body: "{ \"error\": \"Not Found\"}")
|
||||||
|
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
|
Loading…
Reference in New Issue