diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index a252660..f23528e 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -44,6 +44,7 @@ en:
#######################################
chat_integration_mattermost_enabled: "Enable the Mattermost chat-integration provider"
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_excerpt_length: "Mattermost post excerpt length"
@@ -144,3 +145,39 @@ en:
#######################################
hipchat:
message: %{user} posted in %{title}
+
+ #######################################
+ ######## 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`
diff --git a/config/settings.yml b/config/settings.yml
index 20a09f1..9ebffb2 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -66,6 +66,8 @@ plugins:
default: false
chat_integration_mattermost_webhook_url:
default: ''
+ chat_integration_mattermost_incoming_webhook_token:
+ default: ''
chat_integration_mattermost_icon_url:
default: ''
chat_integration_mattermost_excerpt_length:
diff --git a/lib/discourse_chat/provider/mattermost/mattermost_command_controller.rb b/lib/discourse_chat/provider/mattermost/mattermost_command_controller.rb
new file mode 100644
index 0000000..b03390b
--- /dev/null
+++ b/lib/discourse_chat/provider/mattermost/mattermost_command_controller.rb
@@ -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
+
+
+
diff --git a/lib/discourse_chat/provider/mattermost/mattermost_provider.rb b/lib/discourse_chat/provider/mattermost/mattermost_provider.rb
index 9806349..c3d5292 100644
--- a/lib/discourse_chat/provider/mattermost/mattermost_provider.rb
+++ b/lib/discourse_chat/provider/mattermost/mattermost_provider.rb
@@ -81,4 +81,6 @@ module DiscourseChat
end
end
-end
\ No newline at end of file
+end
+
+require_relative "mattermost_command_controller.rb"
\ No newline at end of file
diff --git a/lib/discourse_chat/provider/slack/slack_provider.rb b/lib/discourse_chat/provider/slack/slack_provider.rb
index 3146b1f..23405a6 100644
--- a/lib/discourse_chat/provider/slack/slack_provider.rb
+++ b/lib/discourse_chat/provider/slack/slack_provider.rb
@@ -152,4 +152,4 @@ module DiscourseChat::Provider::SlackProvider
end
require_relative "slack_message_formatter.rb"
-require_relative "slack_command_controller.rb"
\ No newline at end of file
+require_relative "slack_command_controller.rb"
diff --git a/spec/lib/discourse_chat/provider/mattermost/mattermost_command_controller_spec.rb b/spec/lib/discourse_chat/provider/mattermost/mattermost_command_controller_spec.rb
new file mode 100644
index 0000000..f069c16
--- /dev/null
+++ b/spec/lib/discourse_chat/provider/mattermost/mattermost_command_controller_spec.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