Commit 947231a4 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'rs-relative-link-filter' into 'master'

Minor RelativeLinkFilter cleanup

See merge request !649
parents 19251a1f 7f2fb72a
...@@ -68,9 +68,9 @@ module Gitlab ...@@ -68,9 +68,9 @@ module Gitlab
reference_class: html_options[:class], reference_class: html_options[:class],
# RelativeLinkFilter # RelativeLinkFilter
ref: @ref, ref: @ref,
requested_path: @path, requested_path: @path,
project_wiki: @project_wiki project_wiki: @project_wiki
} }
result = pipeline.call(text, context) result = pipeline.call(text, context)
......
...@@ -9,19 +9,18 @@ module Gitlab ...@@ -9,19 +9,18 @@ module Gitlab
# :commit # :commit
# :project # :project
# :project_wiki # :project_wiki
# :requested_path
# :ref # :ref
# :requested_path
class RelativeLinkFilter < HTML::Pipeline::Filter class RelativeLinkFilter < HTML::Pipeline::Filter
def call def call
if linkable_files? return doc unless linkable_files?
doc.search('a').each do |el|
process_link_attr el.attribute('href') doc.search('a').each do |el|
end process_link_attr el.attribute('href')
end
doc.search('img').each do |el|
process_link_attr el.attribute('src') doc.search('img').each do |el|
end process_link_attr el.attribute('src')
end end
doc doc
...@@ -40,6 +39,8 @@ module Gitlab ...@@ -40,6 +39,8 @@ module Gitlab
if uri.relative? && uri.path.present? if uri.relative? && uri.path.present?
html_attr.value = rebuild_relative_uri(uri).to_s html_attr.value = rebuild_relative_uri(uri).to_s
end end
rescue URI::Error
# noop
end end
def rebuild_relative_uri(uri) def rebuild_relative_uri(uri)
...@@ -85,12 +86,25 @@ module Gitlab ...@@ -85,12 +86,25 @@ module Gitlab
repository.tree(current_sha, path).entries.any? repository.tree(current_sha, path).entries.any?
end end
# Check if the path is pointing to a directory(tree) or a file(blob) # Get the type of the given path
# eg. doc/api is directory and doc/README.md is file. #
# path - String path to check
#
# Examples:
#
# path_type('doc/README.md') # => 'blob'
# path_type('doc/logo.png') # => 'raw'
# path_type('doc/api') # => 'tree'
#
# Returns a String
def path_type(path) def path_type(path)
return 'tree' if repository.tree(current_sha, path).entries.any? if repository.tree(current_sha, path).entries.any?
return 'raw' if repository.blob_at(current_sha, path).try(:image?) 'tree'
'blob' elsif repository.blob_at(current_sha, path).try(:image?)
'raw'
else
'blob'
end
end end
def current_sha def current_sha
......
...@@ -2,119 +2,114 @@ require 'spec_helper' ...@@ -2,119 +2,114 @@ require 'spec_helper'
module Gitlab::Markdown module Gitlab::Markdown
describe RelativeLinkFilter do describe RelativeLinkFilter do
include ActionView::Helpers::TagHelper def filter(doc)
described_class.call(doc, {
let!(:project) { create(:project) } commit: project.commit,
project: project,
project_wiki: project_wiki,
ref: ref,
requested_path: requested_path
})
end
let(:commit) { project.commit } def image(path)
let(:project_path) { project.path_with_namespace } %(<img src="#{path}" />)
let(:repository) { project.repository } end
let(:ref) { 'markdown' }
let(:project_wiki) { nil } def link(path)
let(:requested_path) { '/' } %(<a href="#{path}">#{path}</a>)
let(:blob) { RepoHelpers.sample_blob }
let(:context) do
{
commit: commit,
project: project,
project_wiki: project_wiki,
requested_path: requested_path,
ref: ref
}
end end
let(:project) { create(:project) }
let(:project_path) { project.path_with_namespace }
let(:ref) { 'markdown' }
let(:project_wiki) { nil }
let(:requested_path) { '/' }
shared_examples :preserve_unchanged do shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
it "should not modify any relative url in anchor" do doc = filter(link('README.md'))
doc = tag(:a, href: 'README.md') expect(doc.at_css('a')['href']).to eq 'README.md'
expect( filter(doc) ).to match '"README.md"'
end end
it "should not modify any relative url in image" do it 'does not modify any relative URL in image' do
doc = tag(:img, src: 'files/images/logo-black.png') doc = filter(image('files/images/logo-black.png'))
expect( filter(doc) ).to match '"files/images/logo-black.png"' expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
end end
end end
shared_examples :relative_to_requested do shared_examples :relative_to_requested do
it 'rebuilds URL relative to the requested path' do
it "should rebuild url relative to the requested path" do doc = filter(link('users.md'))
expect( filter(tag(:a, href: 'users.md')) ).to \ expect(doc.at_css('a')['href']).
match %("/#{project_path}/blob/#{ref}/doc/api/users.md") to eq "/#{project_path}/blob/#{ref}/doc/api/users.md"
end end
end end
context 'with a project_wiki' do
context "with a project_wiki" do
let(:project_wiki) { double('ProjectWiki') } let(:project_wiki) { double('ProjectWiki') }
include_examples :preserve_unchanged include_examples :preserve_unchanged
end end
context "without a repository" do context 'without a repository' do
let!(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
include_examples :preserve_unchanged include_examples :preserve_unchanged
end end
context "with an empty repository" do context 'with an empty repository' do
let!(:project) { create(:project_empty_repo) } let(:project) { create(:project_empty_repo) }
include_examples :preserve_unchanged include_examples :preserve_unchanged
end end
it 'does not raise an exception on invalid URIs' do
act = link("://foo")
expect { filter(act) }.not_to raise_error
end
context "with a valid repository" do context 'with a valid repository' do
it 'rebuilds relative URL for a file in the repo' do
it "should rebuild relative url for a file in the repo" do doc = filter(link('doc/api/README.md'))
expect( filter(tag(:a, href: 'doc/api/README.md')) ).to \ expect(doc.at_css('a')['href']).
match %("/#{project_path}/blob/#{ref}/doc/api/README.md") to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
end end
it "should rebuild relative url for a file in the repo with an anchor" do it 'rebuilds relative URL for a file in the repo with an anchor' do
expect( filter(tag(:a, href: 'README.md#section')) ).to \ doc = filter(link('README.md#section'))
match %("/#{project_path}/blob/#{ref}/README.md#section") expect(doc.at_css('a')['href']).
to eq "/#{project_path}/blob/#{ref}/README.md#section"
end end
it "should rebuild relative url for a directory in the repo" do it 'rebuilds relative URL for a directory in the repo' do
expect( filter(tag(:a, href: 'doc/api/')) ).to \ doc = filter(link('doc/api/'))
match %("/#{project_path}/tree/#{ref}/doc/api") expect(doc.at_css('a')['href']).
to eq "/#{project_path}/tree/#{ref}/doc/api"
end end
it "should rebuild relative url for an image in the repo" do it 'rebuilds relative URL for an image in the repo' do
expect( filter(tag(:img, src: 'files/images/logo-black.png')) ).to \ doc = filter(link('files/images/logo-black.png'))
match %("/#{project_path}/raw/#{ref}/files/images/logo-black.png") expect(doc.at_css('a')['href']).
to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
end end
it "should not modify relative url with an anchor only" do it 'does not modify relative URL with an anchor only' do
doc = tag(:a, href: '#section-1') doc = filter(link('#section-1'))
expect( filter(doc) ).to match %("#section-1") expect(doc.at_css('a')['href']).to eq '#section-1'
end end
it "should not modify absolute url" do it 'does not modify absolute URL' do
expect( filter(tag(:a, href: 'http://example.org')) ).to \ doc = filter(link('http://example.com'))
match %("http://example.org") expect(doc.at_css('a')['href']).to eq 'http://example.com'
end end
context "when requested path is a file in the repo" do context 'when requested path is a file in the repo' do
let(:requested_path) { 'doc/api/README.md' } let(:requested_path) { 'doc/api/README.md' }
include_examples :relative_to_requested include_examples :relative_to_requested
end end
context "when requested path is a directory in the repo" do context 'when requested path is a directory in the repo' do
let(:requested_path) { 'doc/api' } let(:requested_path) { 'doc/api' }
include_examples :relative_to_requested include_examples :relative_to_requested
end end
end end
def filter(doc)
described_class.call(doc, context).to_s
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