Add mattermost slash command support
This commit is contained in:
parent
61a4fd2c23
commit
e733c2564f
|
@ -44,6 +44,7 @@ en:
|
||||||
#######################################
|
#######################################
|
||||||
chat_integration_mattermost_enabled: "Enable the Mattermost chat-integration provider"
|
chat_integration_mattermost_enabled: "Enable the Mattermost chat-integration provider"
|
||||||
chat_integration_mattermost_webhook_url: 'URL for the Mattermost webhook'
|
chat_integration_mattermost_webhook_url: 'URL for the Mattermost webhook'
|
||||||
|
chat_integration_mattermost_incoming_webhook_token: 'The verification token used to authenticate incoming requests'
|
||||||
chat_integration_mattermost_icon_url: "Icon for posts to mattermost (defaults to forum logo)"
|
chat_integration_mattermost_icon_url: "Icon for posts to mattermost (defaults to forum logo)"
|
||||||
chat_integration_mattermost_excerpt_length: "Mattermost post excerpt length"
|
chat_integration_mattermost_excerpt_length: "Mattermost post excerpt length"
|
||||||
|
|
||||||
|
@ -144,3 +145,39 @@ en:
|
||||||
#######################################
|
#######################################
|
||||||
hipchat:
|
hipchat:
|
||||||
message: <b>%{user}</b> posted in <a href="%{post_url}">%{title}</a>
|
message: <b>%{user}</b> posted in <a href="%{post_url}">%{title}</a>
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
######## MATTERMOST STRINGS ###########
|
||||||
|
#######################################
|
||||||
|
mattermost:
|
||||||
|
status:
|
||||||
|
header: |
|
||||||
|
*Rules for this channel*
|
||||||
|
(if multiple rules match a post, the topmost rule is executed)
|
||||||
|
no_rules: "There are no rules set up for this channel. Run `/discourse help` for instructions."
|
||||||
|
rule_string: "*%{index})* *%{filter}* posts in *%{category}*"
|
||||||
|
rule_string_tags_suffix: " with tags: *%{tags}*"
|
||||||
|
parse_error: "Sorry, I didn't understand that. Run `/discourse help` for instructions."
|
||||||
|
create:
|
||||||
|
created: "Rule created successfully"
|
||||||
|
updated: "Rule updated successfully"
|
||||||
|
error: "Sorry, an error occured while creating that rule."
|
||||||
|
delete:
|
||||||
|
success: "Rule deleted successfully"
|
||||||
|
error: "Sorry, an error occured while deleting that rule. Run `/discourse status` for a list of rules."
|
||||||
|
not_found:
|
||||||
|
tag: "The *%{name}* tag cannot be found."
|
||||||
|
category: "The *%{name}* category cannot be found. Available categories: *%{list}*"
|
||||||
|
help: |
|
||||||
|
*New rule:* `/discourse [watch|follow|mute] [category] [tag:name]`
|
||||||
|
(you must specify a rule type and at least one category or tag)
|
||||||
|
- *watch* – notify this channel for new topics and new replies
|
||||||
|
- *follow* – notify this channel for new topics
|
||||||
|
- *mute* – block notifications to this channel
|
||||||
|
|
||||||
|
*Remove rule:* `/discourse remove [rule number]`
|
||||||
|
(`[rule number]` can be found by running `/discourse status`)
|
||||||
|
|
||||||
|
*List rules:* `/discourse status`
|
||||||
|
|
||||||
|
*Help:* `/discourse help`
|
||||||
|
|
|
@ -66,6 +66,8 @@ plugins:
|
||||||
default: false
|
default: false
|
||||||
chat_integration_mattermost_webhook_url:
|
chat_integration_mattermost_webhook_url:
|
||||||
default: ''
|
default: ''
|
||||||
|
chat_integration_mattermost_incoming_webhook_token:
|
||||||
|
default: ''
|
||||||
chat_integration_mattermost_icon_url:
|
chat_integration_mattermost_icon_url:
|
||||||
default: ''
|
default: ''
|
||||||
chat_integration_mattermost_excerpt_length:
|
chat_integration_mattermost_excerpt_length:
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
module DiscourseChat::Provider::MattermostProvider
|
||||||
|
class MattermostCommandController < DiscourseChat::Provider::HookController
|
||||||
|
requires_provider ::DiscourseChat::Provider::MattermostProvider::PROVIDER_NAME
|
||||||
|
|
||||||
|
before_filter :mattermost_token_valid?, only: :command
|
||||||
|
|
||||||
|
skip_before_filter :check_xhr,
|
||||||
|
:preload_json,
|
||||||
|
:verify_authenticity_token,
|
||||||
|
:redirect_to_login_if_required,
|
||||||
|
only: :command
|
||||||
|
|
||||||
|
def command
|
||||||
|
text = process_command(params)
|
||||||
|
|
||||||
|
render json: {
|
||||||
|
response_type: 'ephemeral',
|
||||||
|
text: text
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_command(params)
|
||||||
|
|
||||||
|
tokens = params[:text].split(" ")
|
||||||
|
|
||||||
|
# channel name fix
|
||||||
|
channel_id =
|
||||||
|
case params[:channel_name]
|
||||||
|
when 'directmessage'
|
||||||
|
"@#{params[:user_name]}"
|
||||||
|
when 'privategroup'
|
||||||
|
params[:channel_id]
|
||||||
|
else
|
||||||
|
"##{params[:channel_name]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
provider = DiscourseChat::Provider::MattermostProvider::PROVIDER_NAME
|
||||||
|
|
||||||
|
channel = DiscourseChat::Channel.with_provider(provider).with_data_value('identifier',channel_id).first
|
||||||
|
|
||||||
|
# Create channel if doesn't exist
|
||||||
|
channel ||= DiscourseChat::Channel.create!(provider:provider, data:{identifier: channel_id})
|
||||||
|
|
||||||
|
return ::DiscourseChat::Helper.process_command(channel, tokens)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def mattermost_token_valid?
|
||||||
|
params.require(:token)
|
||||||
|
|
||||||
|
if SiteSetting.chat_integration_mattermost_incoming_webhook_token.blank? ||
|
||||||
|
SiteSetting.chat_integration_mattermost_incoming_webhook_token != params[:token]
|
||||||
|
|
||||||
|
raise Discourse::InvalidAccess.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MattermostEngine < ::Rails::Engine
|
||||||
|
engine_name DiscourseChat::PLUGIN_NAME+"-mattermost"
|
||||||
|
isolate_namespace DiscourseChat::Provider::MattermostProvider
|
||||||
|
end
|
||||||
|
|
||||||
|
MattermostEngine.routes.draw do
|
||||||
|
post "command" => "mattermost_command#command"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,4 +81,6 @@ module DiscourseChat
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require_relative "mattermost_command_controller.rb"
|
|
@ -152,4 +152,4 @@ module DiscourseChat::Provider::SlackProvider
|
||||||
end
|
end
|
||||||
|
|
||||||
require_relative "slack_message_formatter.rb"
|
require_relative "slack_message_formatter.rb"
|
||||||
require_relative "slack_command_controller.rb"
|
require_relative "slack_command_controller.rb"
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'Mattermost Command Controller', type: :request do
|
||||||
|
let(:category) { Fabricate(:category) }
|
||||||
|
let(:tag) { Fabricate(:tag) }
|
||||||
|
let(:tag2) { Fabricate(:tag) }
|
||||||
|
let!(:chan1){DiscourseChat::Channel.create!(provider:'mattermost', data:{identifier: '#welcome'})}
|
||||||
|
|
||||||
|
describe 'with plugin disabled' do
|
||||||
|
it 'should return a 404' do
|
||||||
|
post '/chat-integration/mattermost/command.json'
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with plugin enabled and provider disabled' do
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_enabled = true
|
||||||
|
SiteSetting.chat_integration_mattermost_enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return a 404' do
|
||||||
|
post '/chat-integration/mattermost/command.json'
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'slash commands endpoint' do
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_enabled = true
|
||||||
|
SiteSetting.chat_integration_mattermost_webhook_url = "https://hooks.mattermost.com/services/abcde"
|
||||||
|
SiteSetting.chat_integration_mattermost_enabled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when forum is private' do
|
||||||
|
it 'should not redirect to login page' do
|
||||||
|
SiteSetting.login_required = true
|
||||||
|
token = 'sometoken'
|
||||||
|
SiteSetting.chat_integration_mattermost_incoming_webhook_token = token
|
||||||
|
|
||||||
|
post '/chat-integration/mattermost/command.json', text: 'help', token: token
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when the token is invalid' do
|
||||||
|
it 'should raise the right error' do
|
||||||
|
expect { post '/chat-integration/mattermost/command.json', text: 'help' }
|
||||||
|
.to raise_error(ActionController::ParameterMissing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when incoming webhook token has not been set' do
|
||||||
|
it 'should raise the right error' do
|
||||||
|
post '/chat-integration/mattermost/command.json', text: 'help', token: 'some token'
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when token is valid' do
|
||||||
|
let(:token) { "Secret Sauce" }
|
||||||
|
|
||||||
|
# No need to test every single command here, that's tested
|
||||||
|
# by helper_spec upstream
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_mattermost_incoming_webhook_token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'add new rule' do
|
||||||
|
|
||||||
|
it 'should add a new rule correctly' do
|
||||||
|
post "/chat-integration/mattermost/command.json",
|
||||||
|
text: "watch #{category.slug}",
|
||||||
|
channel_name: 'welcome',
|
||||||
|
token: token
|
||||||
|
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(json["text"]).to eq(I18n.t("chat_integration.provider.mattermost.create.created"))
|
||||||
|
|
||||||
|
rule = DiscourseChat::Rule.all.first
|
||||||
|
expect(rule.channel).to eq(chan1)
|
||||||
|
expect(rule.filter).to eq('watch')
|
||||||
|
expect(rule.category_id).to eq(category.id)
|
||||||
|
expect(rule.tags).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'from an unknown channel' do
|
||||||
|
it 'creates the channel' do
|
||||||
|
post "/chat-integration/mattermost/command.json",
|
||||||
|
text: "watch #{category.slug}",
|
||||||
|
channel_name: 'general',
|
||||||
|
token: token
|
||||||
|
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(json["text"]).to eq(I18n.t("chat_integration.provider.mattermost.create.created"))
|
||||||
|
|
||||||
|
chan = DiscourseChat::Channel.with_provider('mattermost').with_data_value('identifier','#general').first
|
||||||
|
expect(chan.provider).to eq('mattermost')
|
||||||
|
|
||||||
|
rule = chan.rules.first
|
||||||
|
expect(rule.filter).to eq('watch')
|
||||||
|
expect(rule.category_id).to eq(category.id)
|
||||||
|
expect(rule.tags).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue