Commit 3b3d9371 authored by Michael Kozono's avatar Michael Kozono

Merge branch '12905-c-design-url-support' into 'master'

12905-c support link reference parsing

Closes #196736 and #12905

See merge request gitlab-org/gitlab!23114
parents 6735832c 54da8aa0
...@@ -74,7 +74,7 @@ module Referable ...@@ -74,7 +74,7 @@ module Referable
#{Regexp.escape(Gitlab.config.gitlab.url)} #{Regexp.escape(Gitlab.config.gitlab.url)}
\/#{Project.reference_pattern} \/#{Project.reference_pattern}
(?:\/\-)? (?:\/\-)?
\/#{Regexp.escape(route)} \/#{route.is_a?(Regexp) ? route : Regexp.escape(route)}
\/#{pattern} \/#{pattern}
(?<path> (?<path>
(\/[a-z0-9_=-]+)* (\/[a-z0-9_=-]+)*
......
...@@ -150,7 +150,13 @@ module DesignManagement ...@@ -150,7 +150,13 @@ module DesignManagement
end end
def self.link_reference_pattern def self.link_reference_pattern
nil @link_reference_pattern ||= begin
exts = SAFE_IMAGE_EXT + DANGEROUS_IMAGE_EXT
path_segment = %r{issues/(?<issue>\d+)/designs}
filename_pattern = %r{(?<simple_file_name>[a-z0-9_=-]+\.(#{exts.join('|')}))}i
super(path_segment, filename_pattern)
end
end end
def to_ability_name def to_ability_name
......
...@@ -69,16 +69,17 @@ module Banzai ...@@ -69,16 +69,17 @@ module Banzai
def self.parse_symbol(raw, match_data) def self.parse_symbol(raw, match_data)
filename = parse_filename(raw, match_data) filename = parse_filename(raw, match_data)
Identifier.new(filename: filename, issue_iid: match_data[:issue].to_i) iid = match_data[:issue].to_i
Identifier.new(filename: filename, issue_iid: iid)
end end
def self.parse_filename(raw, match_data) def self.parse_filename(raw, match_data)
if efn = match_data[:escaped_filename] if name = match_data[:simple_file_name]
name
elsif efn = match_data[:escaped_filename]
efn.gsub(/(\\ \\ | \\ ")/x) { |x| x[1] } efn.gsub(/(\\ \\ | \\ ")/x) { |x| x[1] }
elsif b64_name = match_data[:base_64_encoded_name] elsif b64_name = match_data[:base_64_encoded_name]
Base64.decode64(b64_name) Base64.decode64(b64_name)
elsif name = match_data[:simple_file_name]
name
else else
raise "Unexpected name format: #{raw}" raise "Unexpected name format: #{raw}"
end end
......
...@@ -43,6 +43,22 @@ describe Banzai::Filter::DesignReferenceFilter do ...@@ -43,6 +43,22 @@ describe Banzai::Filter::DesignReferenceFilter do
end end
end end
shared_examples 'a good link reference' do
let(:link) { doc.css('a').first }
let(:href) { path_for_design(design) }
let(:title) { design.filename }
it 'produces a good link', :aggregate_failures do
expect(link.attr('href')).to eq(href)
expect(link.attr('title')).to eq(title)
expect(link.attr('class')).to eq('gfm gfm-design has-tooltip')
expect(link.attr('data-project')).to eq(project.id.to_s)
expect(link.attr('data-issue')).to eq(issue.id.to_s)
expect(link.attr('data-original')).to eq(reference)
expect(link.text).to eq(design.to_reference)
end
end
describe '.call' do describe '.call' do
it 'requires project context' do it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
...@@ -151,7 +167,7 @@ describe Banzai::Filter::DesignReferenceFilter do ...@@ -151,7 +167,7 @@ describe Banzai::Filter::DesignReferenceFilter do
it 'links to the design' do it 'links to the design' do
expect(doc.css('a').first.attr('href')) expect(doc.css('a').first.attr('href'))
.to eq url_for_design(design) .to eq path_for_design(design)
end end
end end
...@@ -166,16 +182,7 @@ describe Banzai::Filter::DesignReferenceFilter do ...@@ -166,16 +182,7 @@ describe Banzai::Filter::DesignReferenceFilter do
end end
context 'the user has permission' do context 'the user has permission' do
it 'produces a good link', :aggregate_failures do it_behaves_like 'a good link reference'
link = doc.css('a').first
expect(link.attr('href')).to eq(url_for_design(design))
expect(link.attr('title')).to eq(design.filename)
expect(link.attr('class')).to eq('gfm gfm-design has-tooltip')
expect(link.attr('data-project')).to eq(project.id.to_s)
expect(link.attr('data-issue')).to eq(issue.id.to_s)
expect(link.attr('data-original')).to eq(reference)
end
end end
context 'the filename needs to be escaped' do context 'the filename needs to be escaped' do
...@@ -206,6 +213,28 @@ describe Banzai::Filter::DesignReferenceFilter do ...@@ -206,6 +213,28 @@ describe Banzai::Filter::DesignReferenceFilter do
end end
end end
context 'URL reference' do
let(:reference) { url_for_design(design) }
it 'matches the link_reference_pattern' do
expect(reference).to match(DesignManagement::Design.link_reference_pattern)
end
it 'constructs the appropriate references_per_parent structure' do
filter = filter_instance
filter.call
expect(filter.references_per_parent).to eq({
project.full_path => [filter.record_identifier(design)].to_set
})
end
it_behaves_like 'a good link reference' do
let(:href) { reference }
end
end
context 'cross-project / cross-namespace complete reference' do context 'cross-project / cross-namespace complete reference' do
let(:reference) { x_project_design.to_reference(project) } let(:reference) { x_project_design.to_reference(project) }
...@@ -213,7 +242,7 @@ describe Banzai::Filter::DesignReferenceFilter do ...@@ -213,7 +242,7 @@ describe Banzai::Filter::DesignReferenceFilter do
it 'links to a valid reference' do it 'links to a valid reference' do
expect(doc.css('a').first.attr('href')) expect(doc.css('a').first.attr('href'))
.to eq url_for_design(x_project_design) .to eq path_for_design(x_project_design)
end end
context 'the current user does not have access to that project' do context 'the current user does not have access to that project' do
......
...@@ -19,11 +19,16 @@ module DesignManagementTestHelpers ...@@ -19,11 +19,16 @@ module DesignManagementTestHelpers
act_on_designs(designs) { ::DesignManagement::Action.modification } act_on_designs(designs) { ::DesignManagement::Action.modification }
end end
def url_for_design(design) def path_for_design(design)
path_options = { vueroute: design.filename } path_options = { vueroute: design.filename }
Gitlab::Routing.url_helpers.designs_project_issue_path(design.project, design.issue, path_options) Gitlab::Routing.url_helpers.designs_project_issue_path(design.project, design.issue, path_options)
end end
def url_for_design(design)
path_options = { vueroute: design.filename }
Gitlab::Routing.url_helpers.designs_project_issue_url(design.project, design.issue, path_options)
end
private private
def act_on_designs(designs, &block) def act_on_designs(designs, &block)
......
...@@ -297,8 +297,8 @@ module Banzai ...@@ -297,8 +297,8 @@ module Banzai
@references_per[parent_type] ||= begin @references_per[parent_type] ||= begin
refs = Hash.new { |hash, key| hash[key] = Set.new } refs = Hash.new { |hash, key| hash[key] = Set.new }
regex = [ regex = [
object_class.reference_pattern, object_class.link_reference_pattern,
object_class.link_reference_pattern object_class.reference_pattern
].compact.reduce { |a, b| Regexp.union(a, b) } ].compact.reduce { |a, b| Regexp.union(a, b) }
nodes.each do |node| nodes.each do |node|
......
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