Commit d4def9cb authored by Z.J. van de Weg's avatar Z.J. van de Weg

Incorporate feedback, improve presenter class

[ci skip]
parent 1b4fdb98
...@@ -18,8 +18,4 @@ class ChatService < Service ...@@ -18,8 +18,4 @@ class ChatService < Service
def trigger(params) def trigger(params)
raise NotImplementedError raise NotImplementedError
end end
def chat_user_params(params)
params.permit()
end
end end
class MattermostChatService < ChatService class MattermostCommandService < ChatService
include TriggersHelper include TriggersHelper
prop_accessor :token prop_accessor :token
...@@ -8,7 +8,7 @@ class MattermostChatService < ChatService ...@@ -8,7 +8,7 @@ class MattermostChatService < ChatService
end end
def title def title
'Mattermost' 'Mattermost Command'
end end
def description def description
...@@ -16,7 +16,7 @@ class MattermostChatService < ChatService ...@@ -16,7 +16,7 @@ class MattermostChatService < ChatService
end end
def to_param def to_param
'mattermost' 'mattermost_command'
end end
def help def help
...@@ -33,10 +33,24 @@ class MattermostChatService < ChatService ...@@ -33,10 +33,24 @@ class MattermostChatService < ChatService
end end
def trigger(params) def trigger(params)
user = ChatNames::FindUserService.new(chat_names, params).execute return nil unless valid_token?(params[:token])
return Mattermost::Presenter.authorize_chat_name(params) unless user
Mattermost::CommandService.new(project, user, params.slice(:command, :text)). user = find_chat_user(params)
execute unless user
url = authorize_chat_name_url(params)
return Mattermost::Presenter.authorize_user(url)
end
Mattermost::CommandService.new(project, user, params).execute
end
private
def find_chat_user(params)
ChatNames::FindUserService.new(chat_names, params).execute
end
def authorize_chat_name_url(params)
ChatNames::RequestService.new(self, params).execute
end end
end end
...@@ -202,7 +202,6 @@ class Service < ActiveRecord::Base ...@@ -202,7 +202,6 @@ class Service < ActiveRecord::Base
bamboo bamboo
buildkite buildkite
builds_email builds_email
pipelines_email
bugzilla bugzilla
campfire campfire
custom_issue_tracker custom_issue_tracker
...@@ -214,7 +213,8 @@ class Service < ActiveRecord::Base ...@@ -214,7 +213,8 @@ class Service < ActiveRecord::Base
hipchat hipchat
irker irker
jira jira
mattermost_chat mattermost_command
pipelines_email
pivotaltracker pivotaltracker
pushover pushover
redmine redmine
......
...@@ -45,7 +45,4 @@ Rails.application.configure do ...@@ -45,7 +45,4 @@ Rails.application.configure do
# Do not log asset requests # Do not log asset requests
config.assets.quiet = true config.assets.quiet = true
# Make hot reloading to work with Grape API
ActiveSupport::Dependencies.explicitly_unloadable_constants << "API"
end end
...@@ -61,6 +61,10 @@ module API ...@@ -61,6 +61,10 @@ module API
end end
resource :projects do resource :projects do
desc 'Trigger a slash command' do
detail 'Added in GitLab 8.13'
end
post ':id/services/:service_slug/trigger' do post ':id/services/:service_slug/trigger' do
project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id]) project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id])
...@@ -71,9 +75,7 @@ module API ...@@ -71,9 +75,7 @@ module API
service = project.public_send(service_method) service = project.public_send(service_method)
result = if service.try(:active?) && service.respond_to?(:trigger) result = service.try(:active?) && service.try(:trigger, params)
service.trigger(params)
end
if result if result
present result, status: result[:status] || 200 present result, status: result[:status] || 200
......
...@@ -39,6 +39,10 @@ module Gitlab ...@@ -39,6 +39,10 @@ module Gitlab
Mattermost::Presenter.present(resource) Mattermost::Presenter.present(resource)
end end
def help(messages)
Mattermost::Presenter.help(messages)
end
def find_by_iid(iid) def find_by_iid(iid)
resource = collection.find_by(iid: iid) resource = collection.find_by(iid: iid)
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
def execute def execute
klass, match = fetch_klass klass, match = fetch_klass
return help(help_messages) unless klass.try(:available?, project) return help(help_messages, params[:command]) unless klass.try(:available?, project)
klass.new(project, current_user, params).execute(match) klass.new(project, current_user, params).execute(match)
end end
...@@ -22,23 +22,23 @@ module Gitlab ...@@ -22,23 +22,23 @@ module Gitlab
def fetch_klass def fetch_klass
match = nil match = nil
service = COMMANDS.find do |klass| service = available_commands.find do |klass|
if klass.available?(project)
false
else
match = klass.match(command) match = klass.match(command)
end end
end
[service, match] [service, match]
end end
def help_messages def help_messages
COMMANDS.map do |klass| available_commands.map do |klass|
next unless klass.available?(project)
klass.help_message klass.help_message
end.compact end
end
def available_commands
COMMANDS.select do |klass|
klass.available?(project)
end
end end
def command def command
......
...@@ -6,6 +6,8 @@ module Gitlab ...@@ -6,6 +6,8 @@ module Gitlab
end end
def execute(match) def execute(match)
present nil unless can?(current_user, :create_issue, project)
title = match[:title] title = match[:title]
description = match[:description] description = match[:description]
......
...@@ -2,7 +2,7 @@ module Gitlab ...@@ -2,7 +2,7 @@ module Gitlab
module ChatCommands module ChatCommands
class IssueSearch < IssueCommand class IssueSearch < IssueCommand
def self.match(text) def self.match(text)
/\Aissue\s+search\s+(?<query>.*)/.match(text) /\Aissue\s+search\s+(?<query>.*)\s*/.match(text)
end end
def self.help_message def self.help_message
......
...@@ -9,8 +9,8 @@ module Gitlab ...@@ -9,8 +9,8 @@ module Gitlab
project.merge_requests project.merge_requests
end end
def readable?(_) def readable?(merge_request)
can?(current_user, :read_merge_request, project) can?(current_user, :read_merge_request, merge_request)
end end
end end
end end
......
...@@ -2,7 +2,7 @@ module Gitlab ...@@ -2,7 +2,7 @@ module Gitlab
module ChatCommands module ChatCommands
class MergeRequestSearch < MergeRequestCommand class MergeRequestSearch < MergeRequestCommand
def self.match(text) def self.match(text)
/\Amergerequest\s+search\s+(?<query>.*)/.match(text) /\Amergerequest\s+search\s+(?<query>.*)\s*/.match(text)
end end
def self.help_message def self.help_message
......
module Mattermost module Mattermost
class Presenter class Presenter
class << self class << self
COMMAND_PREFIX = '/gitlab'.freeze def authorize_chat_name(url)
message = "Hi there! We've yet to get acquainted! Please [introduce yourself](#{url})!"
def authorize_chat_name(params) ephemeral_response(message)
url = ChatNames::RequestService.new(service, params).execute
{
response_type: :ephemeral,
message: "You are not authorized. Click this [link](#{url}) to authorize."
}
end end
def help(messages) def help(messages, command)
messages = ["Available commands:"] message = ["Available commands:"]
messages.each do |messsage| messages.each do |messsage|
messages << "- #{message}" message << "- #{command} #{message}"
end end
{ ephemeral_response(messages.join("\n"))
response_type: :ephemeral,
text: messages.join("\n")
}
end end
def not_found def not_found
{ ephemeral_response("404 not found! GitLab couldn't find what your were looking for! :boom:")
response_type: :ephemeral,
text: "404 not found! GitLab couldn't find what your were looking for! :boom:",
}
end end
def present(resource) def present(resource)
...@@ -51,38 +40,56 @@ module Mattermost ...@@ -51,38 +40,56 @@ module Mattermost
private private
def single_resource(resource) def single_resource(resource)
message = title(resource) return error(resource) if resource.errors.any?
message = "### #{title(resource)}"
message << "\n\n#{resource.description}" if resource.description message << "\n\n#{resource.description}" if resource.description
{ in_channel_response(message)
response_type: :in_channel,
text: message
}
end end
def multiple_resources(resources) def multiple_resources(resources)
message = "Multiple results were found:\n" message = "Multiple results were found:\n"
message << resources.map { |resource| " #{title(resource)}" }.join("\n") message << resources.map { |resource| "- #{title(resource)}" }.join("\n")
{ ephemeral_response(message)
response_type: :ephemeral, end
text: message
} def error(resource)
message = "The action was not succesfull because:\n"
message << resource.errors.messages.map { |message| "- #{message}" }.join("\n")
ephemeral_response(resource.errors.messages.join("\n")
end end
def title(resource) def title(resource)
"### [#{resource.to_reference} #{resource.title}](#{url(resource)})" "[#{resource.to_reference} #{resource.title}](#{url(resource)})"
end end
def url(resource) def url(resource)
helper = Rails.application.routes.url_helpers polymorphic_url(
[
resource.project.namespace.becomes(Namespace),
resource.project,
resource
],
id: resource_id,
routing_type: :url
)
end
case resource def ephemeral_response(message)
when Issue {
helper.namespace_project_issue_url(resource.project.namespace.becomes(Namespace), resource.project, resource) response_type: :ephemeral,
when MergeRequest text: message
helper.namespace_project_merge_request_url(resource.project.namespace.becomes(Namespace), resource.project, resource) }
end end
def in_channel_response(message)
{
response_type: :in_channel,
text: message
}
end end
end end
end end
......
...@@ -6,9 +6,13 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do ...@@ -6,9 +6,13 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:regex_match) { described_class.match("issue create bird is the word") } let(:regex_match) { described_class.match("issue create bird is the word") }
before { project.team << [user, :master] } before do
project.team << [user, :master]
end
subject { described_class.new(project, user).execute(regex_match) } subject do
described_class.new(project, user).execute(regex_match)
end
context 'without description' do context 'without description' do
it 'creates the issue' do it 'creates the issue' do
...@@ -17,7 +21,7 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do ...@@ -17,7 +21,7 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
end.to change { project.issues.count }.by(1) end.to change { project.issues.count }.by(1)
expect(subject[:response_type]).to be :in_channel expect(subject[:response_type]).to be :in_channel
expect(subject[:text]).to match 'bird is the word' expect(subject[:text]).to match('bird is the word')
end end
end end
...@@ -25,11 +29,29 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do ...@@ -25,11 +29,29 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
let(:description) { "Surfin bird" } let(:description) { "Surfin bird" }
let(:regex_match) { described_class.match("issue create bird is the word\n#{description}") } let(:regex_match) { described_class.match("issue create bird is the word\n#{description}") }
before { subject } before do
subject
end
it 'creates the issue with description' do it 'creates the issue with description' do
expect(Issue.last.description).to eq description expect(Issue.last.description).to eq(description)
end
end
end end
describe 'self.match' do
it 'matches the title without description' do
match = described_class.match("issue create my title")
expect(match[:title]).to eq('my title')
expect(match[:description]).to eq("")
end
it 'matches the title with description' do
match = described_class.match("issue create my title\n\ndescription")
expect(match[:title]).to eq('my title')
expect(match[:description]).to eq('description')
end end
end end
end end
...@@ -7,14 +7,18 @@ describe Gitlab::ChatCommands::IssueShow, service: true do ...@@ -7,14 +7,18 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
let(:user) { issue.author } let(:user) { issue.author }
let(:regex_match) { described_class.match("issue show #{issue.iid}") } let(:regex_match) { described_class.match("issue show #{issue.iid}") }
before { project.team << [user, :master] } before do
project.team << [user, :master]
end
subject { described_class.new(project, user).execute(regex_match) } subject do
described_class.new(project, user).execute(regex_match)
end
context 'the issue exists' do context 'the issue exists' do
it 'returns the issue' do it 'returns the issue' do
expect(subject[:response_type]).to be :in_channel expect(subject[:response_type]).to be(:in_channel)
expect(subject[:text]).to match issue.title expect(subject[:text]).to match(issue.title)
end end
end end
...@@ -22,9 +26,17 @@ describe Gitlab::ChatCommands::IssueShow, service: true do ...@@ -22,9 +26,17 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
let(:regex_match) { described_class.match("issue show 1234") } let(:regex_match) { described_class.match("issue show 1234") }
it "returns nil" do it "returns nil" do
expect(subject[:response_type]).to be :ephemeral expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to start_with '404 not found!' expect(subject[:text]).to start_with('404 not found!')
end
end end
end end
describe 'self.match' do
it 'matches the iid' do
match = described_class.match("issue show 123")
expect(match[:iid]).to eq("123")
end
end end
end end
...@@ -7,14 +7,18 @@ describe Gitlab::ChatCommands::MergeRequestSearch, service: true do ...@@ -7,14 +7,18 @@ describe Gitlab::ChatCommands::MergeRequestSearch, service: true do
let(:user) { merge_request.author } let(:user) { merge_request.author }
let(:regex_match) { described_class.match("mergerequest search #{merge_request.title}") } let(:regex_match) { described_class.match("mergerequest search #{merge_request.title}") }
before { project.team << [user, :master] } before do
project.team << [user, :master]
end
subject { described_class.new(project, user, {}).execute(regex_match) } subject do
described_class.new(project, user).execute(regex_match)
end
context 'the merge request exists' do context 'the merge request exists' do
it 'returns the merge request' do it 'returns the merge request' do
expect(subject[:response_type]).to be :in_channel expect(subject[:response_type]).to be(:in_channel)
expect(subject[:text]).to match merge_request.title expect(subject[:text]).to match(merge_request.title)
end end
end end
...@@ -22,8 +26,8 @@ describe Gitlab::ChatCommands::MergeRequestSearch, service: true do ...@@ -22,8 +26,8 @@ describe Gitlab::ChatCommands::MergeRequestSearch, service: true do
let(:regex_match) { described_class.match("mergerequest search 12334") } let(:regex_match) { described_class.match("mergerequest search 12334") }
it "returns a 404 message" do it "returns a 404 message" do
expect(subject[:response_type]).to be :ephemeral expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to start_with '404 not found!' expect(subject[:text]).to start_with('404 not found!')
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment