image_tag(
thumbnail_path(attachment),
:srcset => "#{thumbnail_path(attachment, :size => Setting.thumbnails_size.to_i * 2)} 2x",
- :width => Setting.thumbnails_size
+ :width => Setting.thumbnails_size
),
named_attachment_path(
attachment,
# Projects:
# project:someproject -> Link to project named "someproject"
# project#3 -> Link to project with id 3
+ # Users:
+ # user:jsmith -> Link to user with login jsmith
+ # @jsmith -> Link to user with login jsmith
#
# Links can refer other objects from other projects, using project identifier:
# identifier:r52
prefix = $~[:prefix]
repo_prefix = $~[:repo_prefix]
repo_identifier = $~[:repo_identifier]
- sep = $~[:sep1] || $~[:sep2] || $~[:sep3]
- identifier = $~[:identifier1] || $~[:identifier2]
+ sep = $~[:sep1] || $~[:sep2] || $~[:sep3] || $~[:sep4]
+ identifier = $~[:identifier1] || $~[:identifier2] || $~[:identifier3]
comment_suffix = $~[:comment_suffix]
comment_id = $~[:comment_id]
end
end
elsif sep == ':'
- # removes the double quotes if any
- name = identifier.gsub(%r{^"(.*)"$}, "\\1")
- name = CGI.unescapeHTML(name)
+ name = remove_double_quotes(identifier)
case prefix
when 'document'
if project && document = project.documents.visible.find_by_title(name)
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
+ when 'user'
+ u = User.visible.where(:login => name, :type => 'User').first
+ link = link_to_user(u) if u
end
+ elsif "@"
+ name = remove_double_quotes(identifier)
+ u = User.visible.where(:login => name, :type => 'User').first
+ link = link_to_user(u) if u
end
end
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
(?<leading>[\s\(,\-\[\>]|^)
(?<esc>!)?
(?<project_prefix>(?<project_identifier>[a-z0-9\-_]+):)?
- (?<prefix>attachment|document|version|forum|news|message|project|commit|source|export)?
+ (?<prefix>attachment|document|version|forum|news|message|project|commit|source|export|user)?
(
(
(?<sep1>\#)|
-(?<comment_id>\d+)
)?
)|
+ (
(?<sep3>:)
(?<identifier2>[^"\s<>][^\s<>]*?|"[^"]+?")
+ )|
+ (
+ (?<sep4>@)
+ (?<identifier3>[a-z0-9_\-@\.]*)
+ )
)
(?=
(?=[[:punct:]][^A-Za-z0-9_/])|
extend helper
return self
end
+
+ # remove double quotes if any
+ def remove_double_quotes(identifier)
+ name = identifier.gsub(%r{^"(.*)"$}, "\\1")
+ return CGI.unescapeHTML(name)
+ end
end
args :
%w(Formatter Helper HtmlParser).map {|m| "Redmine::WikiFormatting::#{name.classify}::#{m}".constantize rescue nil}
- raise "A formatter class is required" if formatter.nil?
+ raise "A formatter class is required" if formatter.nil?
@@formatters[name] = {
:formatter => formatter,
# Destructively replaces email addresses into clickable links
def auto_mailto!(text)
- text.gsub!(/([\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
+ text.gsub!(/((?<!@)\b[\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
mail = $1
if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
mail
%(<a class="email" href="mailto:#{ERB::Util.html_escape mail}">#{ERB::Util.html_escape mail}</a>).html_safe
end
end
- end
+ end
end
# Default formatter module
# invalid expressions
'source:' => 'source:',
# url hash
- "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
+ "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
+ # user
+ 'user:jsmith' => link_to_user(User.find_by_id(2)),
+ '@jsmith' => link_to_user(User.find_by_id(2)),
+ # invalid user
+ 'user:foobar' => 'user:foobar',
}
@project = Project.find(1)
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
end
+ def test_user_links_with_email_as_login_name_should_not_be_parsed
+ u = User.generate!(:login => 'jsmith@somenet.foo')
+ raw = "@jsmith@somenet.foo should not be parsed in jsmith@somenet.foo"
+
+ assert_match %r{<p><a class="user active".*>#{u.name}</a> should not be parsed in <a class="email" href="mailto:jsmith@somenet.foo">jsmith@somenet.foo</a></p>},
+ textilizable(raw, :project => Project.find(1))
+ 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>},