Redirect to external issue tracker from /issues

Prior, in order to display the correct link to "Issues" in the project
navigation, we were performing a check against the project to see if it
used an external issue tracker, and if so, we used that URL. This was
inefficient.

Now, we simply _always_ link to `namespace_project_issues_path`, and
then in the controller we redirect to the external tracker if it's
present.

This also removes the need for the url_for_issue helper. Bonus! 🎉
This commit is contained in:
Robert Speicher 2016-08-01 16:59:44 -07:00
parent 957331bf45
commit a70431f874
6 changed files with 45 additions and 86 deletions

View file

@ -5,6 +5,7 @@ class Projects::IssuesController < Projects::ApplicationController
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections include IssuableCollections
before_action :redirect_to_external_issue_tracker, only: [:index]
before_action :module_enabled before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests, before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
:related_branches, :can_create_branch] :related_branches, :can_create_branch]
@ -201,6 +202,12 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless @project.issues_enabled && @project.default_issues_tracker? return render_404 unless @project.issues_enabled && @project.default_issues_tracker?
end end
def redirect_to_external_issue_tracker
return unless @project.external_issue_tracker
redirect_to @project.external_issue_tracker.issues_url
end
# Since iids are implemented only in 6.1 # Since iids are implemented only in 6.1
# user may navigate to issue page using old global ids. # user may navigate to issue page using old global ids.
# #

View file

@ -13,22 +13,6 @@ module IssuesHelper
OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned') OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
end end
def url_for_project_issues(project = @project, options = {})
return '' if project.nil?
url =
if options[:only_path]
project.issues_tracker.project_path
else
project.issues_tracker.project_url
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def url_for_new_issue(project = @project, options = {}) def url_for_new_issue(project = @project, options = {})
return '' if project.nil? return '' if project.nil?

View file

@ -66,7 +66,7 @@
- if project_nav_tab? :issues - if project_nav_tab? :issues
= nav_link(controller: [:issues, :labels, :milestones]) do = nav_link(controller: [:issues, :labels, :milestones]) do
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do = link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do
%span %span
Issues Issues
- if @project.default_issues_tracker? - if @project.default_issues_tracker?

View file

@ -2,7 +2,7 @@
%ul{ class: (container_class) } %ul{ class: (container_class) }
- if project_nav_tab?(:issues) && !current_controller?(:merge_requests) - if project_nav_tab?(:issues) && !current_controller?(:merge_requests)
= nav_link(controller: :issues) do = nav_link(controller: :issues) do
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues' do = link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues' do
%span %span
Issues Issues

View file

@ -6,6 +6,19 @@ describe Projects::IssuesController do
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
describe "GET #index" do describe "GET #index" do
context 'external issue tracker' do
it 'redirects to the external issue tracker' do
external = double(issues_url: 'https://example.com/issues')
allow(project).to receive(:external_issue_tracker).and_return(external)
controller.instance_variable_set(:@project, project)
get :index, namespace_id: project.namespace.path, project_id: project
expect(response).to redirect_to('https://example.com/issues')
end
end
context 'internal issue tracker' do
before do before do
sign_in(user) sign_in(user)
project.team << [user, :developer] project.team << [user, :developer]
@ -39,6 +52,7 @@ describe Projects::IssuesController do
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
end end
end
describe 'PUT #update' do describe 'PUT #update' do
context 'when moving issue to another private project' do context 'when moving issue to another private project' do

View file

@ -5,52 +5,6 @@ describe IssuesHelper do
let(:issue) { create :issue, project: project } let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project } let(:ext_project) { create :redmine_project }
describe "url_for_project_issues" do
let(:project_url) { ext_project.external_issue_tracker.project_url }
let(:ext_expected) { project_url.gsub(':project_id', ext_project.id.to_s) }
let(:int_expected) { polymorphic_path([@project.namespace, project]) }
it "should return internal path if used internal tracker" do
@project = project
expect(url_for_project_issues).to match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
expect(url_for_project_issues).to match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
expect(url_for_project_issues).to eq ""
end
it 'returns an empty string if project_url is invalid' do
expect(project).to receive_message_chain('issues_tracker.project_url') { 'javascript:alert("foo");' }
expect(url_for_project_issues(project)).to eq ''
end
it 'returns an empty string if project_path is invalid' do
expect(project).to receive_message_chain('issues_tracker.project_path') { 'javascript:alert("foo");' }
expect(url_for_project_issues(project, only_path: true)).to eq ''
end
describe "when external tracker was enabled and then config removed" do
before do
@project = ext_project
allow(Gitlab.config).to receive(:issues_tracker).and_return(nil)
end
it "should return path to external tracker" do
expect(url_for_project_issues).to match(ext_expected)
end
end
end
describe "url_for_issue" do describe "url_for_issue" do
let(:issues_url) { ext_project.external_issue_tracker.issues_url} let(:issues_url) { ext_project.external_issue_tracker.issues_url}
let(:ext_expected) { issues_url.gsub(':id', issue.iid.to_s).gsub(':project_id', ext_project.id.to_s) } let(:ext_expected) { issues_url.gsub(':id', issue.iid.to_s).gsub(':project_id', ext_project.id.to_s) }