mirror of
https://github.com/redmine/redmine.git
synced 2025-11-10 07:16:03 +01:00
Fixed that Redmine links should not be parsed inside links (#18301).
git-svn-id: http://svn.redmine.org/redmine/trunk@13596 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -754,144 +754,148 @@ module ApplicationHelper
|
|||||||
# identifier:version:1.0.0
|
# identifier:version:1.0.0
|
||||||
# identifier:source:some/file
|
# identifier:source:some/file
|
||||||
def parse_redmine_links(text, default_project, obj, attr, only_path, options)
|
def parse_redmine_links(text, default_project, obj, attr, only_path, options)
|
||||||
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
|
text.gsub!(%r{<a( [^>]+?)?>(.*?)</a>|([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
|
||||||
leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17
|
tag_content, leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $3, $4, $5, $6, $7, $12, $13, $10 || $14 || $20, $16 || $21, $17, $19
|
||||||
link = nil
|
if tag_content
|
||||||
project = default_project
|
$&
|
||||||
if project_identifier
|
else
|
||||||
project = Project.visible.find_by_identifier(project_identifier)
|
link = nil
|
||||||
end
|
project = default_project
|
||||||
if esc.nil?
|
if project_identifier
|
||||||
if prefix.nil? && sep == 'r'
|
project = Project.visible.find_by_identifier(project_identifier)
|
||||||
if project
|
end
|
||||||
repository = nil
|
if esc.nil?
|
||||||
if repo_identifier
|
if prefix.nil? && sep == 'r'
|
||||||
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
|
||||||
else
|
|
||||||
repository = project.repository
|
|
||||||
end
|
|
||||||
# project.changesets.visible raises an SQL error because of a double join on repositories
|
|
||||||
if repository &&
|
|
||||||
(changeset = Changeset.visible.
|
|
||||||
find_by_repository_id_and_revision(repository.id, identifier))
|
|
||||||
link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"),
|
|
||||||
{:only_path => only_path, :controller => 'repositories',
|
|
||||||
:action => 'revision', :id => project,
|
|
||||||
:repository_id => repository.identifier_param,
|
|
||||||
:rev => changeset.revision},
|
|
||||||
:class => 'changeset',
|
|
||||||
:title => truncate_single_line_raw(changeset.comments, 100))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif sep == '#'
|
|
||||||
oid = identifier.to_i
|
|
||||||
case prefix
|
|
||||||
when nil
|
|
||||||
if oid.to_s == identifier &&
|
|
||||||
issue = Issue.visible.includes(:status).find_by_id(oid)
|
|
||||||
anchor = comment_id ? "note-#{comment_id}" : nil
|
|
||||||
link = link_to(h("##{oid}#{comment_suffix}"),
|
|
||||||
{:only_path => only_path, :controller => 'issues',
|
|
||||||
:action => 'show', :id => oid, :anchor => anchor},
|
|
||||||
:class => issue.css_classes,
|
|
||||||
:title => "#{issue.subject.truncate(100)} (#{issue.status.name})")
|
|
||||||
end
|
|
||||||
when 'document'
|
|
||||||
if document = Document.visible.find_by_id(oid)
|
|
||||||
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
|
||||||
:class => 'document'
|
|
||||||
end
|
|
||||||
when 'version'
|
|
||||||
if version = Version.visible.find_by_id(oid)
|
|
||||||
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
|
||||||
:class => 'version'
|
|
||||||
end
|
|
||||||
when 'message'
|
|
||||||
if message = Message.visible.includes(:parent).find_by_id(oid)
|
|
||||||
link = link_to_message(message, {:only_path => only_path}, :class => 'message')
|
|
||||||
end
|
|
||||||
when 'forum'
|
|
||||||
if board = Board.visible.find_by_id(oid)
|
|
||||||
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
|
||||||
:class => 'board'
|
|
||||||
end
|
|
||||||
when 'news'
|
|
||||||
if news = News.visible.find_by_id(oid)
|
|
||||||
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
|
||||||
:class => 'news'
|
|
||||||
end
|
|
||||||
when 'project'
|
|
||||||
if p = Project.visible.find_by_id(oid)
|
|
||||||
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif sep == ':'
|
|
||||||
# removes the double quotes if any
|
|
||||||
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
|
|
||||||
name = CGI.unescapeHTML(name)
|
|
||||||
case prefix
|
|
||||||
when 'document'
|
|
||||||
if project && document = project.documents.visible.find_by_title(name)
|
|
||||||
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
|
||||||
:class => 'document'
|
|
||||||
end
|
|
||||||
when 'version'
|
|
||||||
if project && version = project.versions.visible.find_by_name(name)
|
|
||||||
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
|
||||||
:class => 'version'
|
|
||||||
end
|
|
||||||
when 'forum'
|
|
||||||
if project && board = project.boards.visible.find_by_name(name)
|
|
||||||
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
|
||||||
:class => 'board'
|
|
||||||
end
|
|
||||||
when 'news'
|
|
||||||
if project && news = project.news.visible.find_by_title(name)
|
|
||||||
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
|
||||||
:class => 'news'
|
|
||||||
end
|
|
||||||
when 'commit', 'source', 'export'
|
|
||||||
if project
|
if project
|
||||||
repository = nil
|
repository = nil
|
||||||
if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
|
if repo_identifier
|
||||||
repo_prefix, repo_identifier, name = $1, $2, $3
|
|
||||||
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
||||||
else
|
else
|
||||||
repository = project.repository
|
repository = project.repository
|
||||||
end
|
end
|
||||||
if prefix == 'commit'
|
# project.changesets.visible raises an SQL error because of a double join on repositories
|
||||||
if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
|
if repository &&
|
||||||
link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
|
(changeset = Changeset.visible.
|
||||||
:class => 'changeset',
|
find_by_repository_id_and_revision(repository.id, identifier))
|
||||||
:title => truncate_single_line_raw(changeset.comments, 100)
|
link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"),
|
||||||
end
|
{:only_path => only_path, :controller => 'repositories',
|
||||||
else
|
:action => 'revision', :id => project,
|
||||||
if repository && User.current.allowed_to?(:browse_repository, project)
|
:repository_id => repository.identifier_param,
|
||||||
name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
|
:rev => changeset.revision},
|
||||||
path, rev, anchor = $1, $3, $5
|
:class => 'changeset',
|
||||||
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
|
:title => truncate_single_line_raw(changeset.comments, 100))
|
||||||
:path => to_path_param(path),
|
|
||||||
:rev => rev,
|
|
||||||
:anchor => anchor},
|
|
||||||
:class => (prefix == 'export' ? 'source download' : 'source')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
repo_prefix = nil
|
|
||||||
end
|
end
|
||||||
when 'attachment'
|
elsif sep == '#'
|
||||||
attachments = options[:attachments] || []
|
oid = identifier.to_i
|
||||||
attachments += obj.attachments if obj.respond_to?(:attachments)
|
case prefix
|
||||||
if attachments && attachment = Attachment.latest_attach(attachments, name)
|
when nil
|
||||||
link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
|
if oid.to_s == identifier &&
|
||||||
|
issue = Issue.visible.includes(:status).find_by_id(oid)
|
||||||
|
anchor = comment_id ? "note-#{comment_id}" : nil
|
||||||
|
link = link_to(h("##{oid}#{comment_suffix}"),
|
||||||
|
{:only_path => only_path, :controller => 'issues',
|
||||||
|
:action => 'show', :id => oid, :anchor => anchor},
|
||||||
|
:class => issue.css_classes,
|
||||||
|
:title => "#{issue.subject.truncate(100)} (#{issue.status.name})")
|
||||||
|
end
|
||||||
|
when 'document'
|
||||||
|
if document = Document.visible.find_by_id(oid)
|
||||||
|
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
||||||
|
:class => 'document'
|
||||||
|
end
|
||||||
|
when 'version'
|
||||||
|
if version = Version.visible.find_by_id(oid)
|
||||||
|
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
||||||
|
:class => 'version'
|
||||||
|
end
|
||||||
|
when 'message'
|
||||||
|
if message = Message.visible.includes(:parent).find_by_id(oid)
|
||||||
|
link = link_to_message(message, {:only_path => only_path}, :class => 'message')
|
||||||
|
end
|
||||||
|
when 'forum'
|
||||||
|
if board = Board.visible.find_by_id(oid)
|
||||||
|
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
||||||
|
:class => 'board'
|
||||||
|
end
|
||||||
|
when 'news'
|
||||||
|
if news = News.visible.find_by_id(oid)
|
||||||
|
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
||||||
|
:class => 'news'
|
||||||
|
end
|
||||||
|
when 'project'
|
||||||
|
if p = Project.visible.find_by_id(oid)
|
||||||
|
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
when 'project'
|
elsif sep == ':'
|
||||||
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
|
# removes the double quotes if any
|
||||||
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
|
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
|
||||||
|
name = CGI.unescapeHTML(name)
|
||||||
|
case prefix
|
||||||
|
when 'document'
|
||||||
|
if project && document = project.documents.visible.find_by_title(name)
|
||||||
|
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
||||||
|
:class => 'document'
|
||||||
|
end
|
||||||
|
when 'version'
|
||||||
|
if project && version = project.versions.visible.find_by_name(name)
|
||||||
|
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
||||||
|
:class => 'version'
|
||||||
|
end
|
||||||
|
when 'forum'
|
||||||
|
if project && board = project.boards.visible.find_by_name(name)
|
||||||
|
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
||||||
|
:class => 'board'
|
||||||
|
end
|
||||||
|
when 'news'
|
||||||
|
if project && news = project.news.visible.find_by_title(name)
|
||||||
|
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
||||||
|
:class => 'news'
|
||||||
|
end
|
||||||
|
when 'commit', 'source', 'export'
|
||||||
|
if project
|
||||||
|
repository = nil
|
||||||
|
if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
|
||||||
|
repo_prefix, repo_identifier, name = $1, $2, $3
|
||||||
|
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
||||||
|
else
|
||||||
|
repository = project.repository
|
||||||
|
end
|
||||||
|
if prefix == 'commit'
|
||||||
|
if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
|
||||||
|
link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
|
||||||
|
:class => 'changeset',
|
||||||
|
:title => truncate_single_line_raw(changeset.comments, 100)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if repository && User.current.allowed_to?(:browse_repository, project)
|
||||||
|
name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
|
||||||
|
path, rev, anchor = $1, $3, $5
|
||||||
|
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
|
||||||
|
:path => to_path_param(path),
|
||||||
|
:rev => rev,
|
||||||
|
:anchor => anchor},
|
||||||
|
:class => (prefix == 'export' ? 'source download' : 'source')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
repo_prefix = nil
|
||||||
|
end
|
||||||
|
when 'attachment'
|
||||||
|
attachments = options[:attachments] || []
|
||||||
|
attachments += obj.attachments if obj.respond_to?(:attachments)
|
||||||
|
if attachments && attachment = Attachment.latest_attach(attachments, name)
|
||||||
|
link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
|
||||||
|
end
|
||||||
|
when 'project'
|
||||||
|
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
|
||||||
|
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
|
||||||
end
|
end
|
||||||
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -363,6 +363,12 @@ RAW
|
|||||||
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_not_parse_redmine_links_inside_link
|
||||||
|
raw = "r1 should not be parsed in http://example.com/url-r1/"
|
||||||
|
assert_match %r{<p><a class="changeset".*>r1</a> should not be parsed in <a class="external" href="http://example.com/url-r1/">http://example.com/url-r1/</a></p>},
|
||||||
|
textilizable(raw, :project => Project.find(1))
|
||||||
|
end
|
||||||
|
|
||||||
def test_redmine_links_with_a_different_project_before_current_project
|
def test_redmine_links_with_a_different_project_before_current_project
|
||||||
vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
|
vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
|
||||||
vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
|
vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
|
||||||
|
|||||||
Reference in New Issue
Block a user