Feature #4179 » 4179_link_to_user_in_wiki_syntax.patch
app/helpers/application_helper.rb | ||
---|---|---|
224 | 224 |
image_tag( |
225 | 225 |
thumbnail_path(attachment), |
226 | 226 |
:srcset => "#{thumbnail_path(attachment, :size => Setting.thumbnails_size.to_i * 2)} 2x", |
227 |
:width => Setting.thumbnails_size
|
|
227 |
:width => Setting.thumbnails_size |
|
228 | 228 |
), |
229 | 229 |
named_attachment_path( |
230 | 230 |
attachment, |
... | ... | |
807 | 807 |
# Projects: |
808 | 808 |
# project:someproject -> Link to project named "someproject" |
809 | 809 |
# project#3 -> Link to project with id 3 |
810 |
# Users: |
|
811 |
# user:jsmith -> Link to user with login jsmith |
|
812 |
# @jsmith -> Link to user with login jsmith |
|
810 | 813 |
# |
811 | 814 |
# Links can refer other objects from other projects, using project identifier: |
812 | 815 |
# identifier:r52 |
... | ... | |
823 | 826 |
prefix = $~[:prefix] |
824 | 827 |
repo_prefix = $~[:repo_prefix] |
825 | 828 |
repo_identifier = $~[:repo_identifier] |
826 |
sep = $~[:sep1] || $~[:sep2] || $~[:sep3] |
|
827 |
identifier = $~[:identifier1] || $~[:identifier2] |
|
829 |
sep = $~[:sep1] || $~[:sep2] || $~[:sep3] || $~[:sep4]
|
|
830 |
identifier = $~[:identifier1] || $~[:identifier2] || $~[:identifier3]
|
|
828 | 831 |
comment_suffix = $~[:comment_suffix] |
829 | 832 |
comment_id = $~[:comment_id] |
830 | 833 | |
... | ... | |
896 | 899 |
end |
897 | 900 |
end |
898 | 901 |
elsif sep == ':' |
899 |
# removes the double quotes if any |
|
900 |
name = identifier.gsub(%r{^"(.*)"$}, "\\1") |
|
901 |
name = CGI.unescapeHTML(name) |
|
902 |
name = remove_double_quotes(identifier) |
|
902 | 903 |
case prefix |
903 | 904 |
when 'document' |
904 | 905 |
if project && document = project.documents.visible.find_by_title(name) |
... | ... | |
954 | 955 |
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first |
955 | 956 |
link = link_to_project(p, {:only_path => only_path}, :class => 'project') |
956 | 957 |
end |
958 |
when 'user' |
|
959 |
u = User.visible.where(:login => name, :type => 'User').first |
|
960 |
link = link_to_user(u) if u |
|
957 | 961 |
end |
962 |
elsif "@" |
|
963 |
name = remove_double_quotes(identifier) |
|
964 |
u = User.visible.where(:login => name, :type => 'User').first |
|
965 |
link = link_to_user(u) if u |
|
958 | 966 |
end |
959 | 967 |
end |
960 | 968 |
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) |
... | ... | |
968 | 976 |
(?<leading>[\s\(,\-\[\>]|^) |
969 | 977 |
(?<esc>!)? |
970 | 978 |
(?<project_prefix>(?<project_identifier>[a-z0-9\-_]+):)? |
971 |
(?<prefix>attachment|document|version|forum|news|message|project|commit|source|export)? |
|
979 |
(?<prefix>attachment|document|version|forum|news|message|project|commit|source|export|user)?
|
|
972 | 980 |
( |
973 | 981 |
( |
974 | 982 |
(?<sep1>\#)| |
... | ... | |
984 | 992 |
-(?<comment_id>\d+) |
985 | 993 |
)? |
986 | 994 |
)| |
995 |
( |
|
987 | 996 |
(?<sep3>:) |
988 | 997 |
(?<identifier2>[^"\s<>][^\s<>]*?|"[^"]+?") |
998 |
)| |
|
999 |
( |
|
1000 |
(?<sep4>@) |
|
1001 |
(?<identifier3>[a-z0-9_\-@\.]*) |
|
1002 |
) |
|
989 | 1003 |
) |
990 | 1004 |
(?= |
991 | 1005 |
(?=[[:punct:]][^A-Za-z0-9_/])| |
... | ... | |
1462 | 1476 |
extend helper |
1463 | 1477 |
return self |
1464 | 1478 |
end |
1479 | ||
1480 |
# remove double quotes if any |
|
1481 |
def remove_double_quotes(identifier) |
|
1482 |
name = identifier.gsub(%r{^"(.*)"$}, "\\1") |
|
1483 |
return CGI.unescapeHTML(name) |
|
1484 |
end |
|
1465 | 1485 |
end |
lib/redmine/wiki_formatting.rb | ||
---|---|---|
37 | 37 |
args : |
38 | 38 |
%w(Formatter Helper HtmlParser).map {|m| "Redmine::WikiFormatting::#{name.classify}::#{m}".constantize rescue nil} |
39 | 39 | |
40 |
raise "A formatter class is required" if formatter.nil?
|
|
40 |
raise "A formatter class is required" if formatter.nil? |
|
41 | 41 | |
42 | 42 |
@@formatters[name] = { |
43 | 43 |
:formatter => formatter, |
... | ... | |
153 | 153 | |
154 | 154 |
# Destructively replaces email addresses into clickable links |
155 | 155 |
def auto_mailto!(text) |
156 |
text.gsub!(/([\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do |
|
156 |
text.gsub!(/((?<!@)\b[\w\.!#\$%\-+.\/]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
|
|
157 | 157 |
mail = $1 |
158 | 158 |
if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) |
159 | 159 |
|
... | ... | |
161 | 161 |
%(<a class="email" href="mailto:#{ERB::Util.html_escape mail}">#{ERB::Util.html_escape mail}</a>).html_safe |
162 | 162 |
end |
163 | 163 |
end |
164 |
end
|
|
164 |
end |
|
165 | 165 |
end |
166 | 166 | |
167 | 167 |
# Default formatter module |
lib/redmine/wiki_formatting/markdown/formatter.rb | ||
---|---|---|
66 | 66 |
html.gsub!(/(\w):"(.+?)"/) do |
67 | 67 |
"#{$1}:\"#{$2}\"" |
68 | 68 |
end |
69 |
# restore user links with @ in login name eg. [@jsmith@somenet.foo] |
|
70 |
html.gsub!(%r{[@\A]<a href="mailto:(.*?)">(.*?)</a>}) do |
|
71 |
"@#{$2}" |
|
72 |
end |
|
69 | 73 |
html |
70 | 74 |
end |
71 | 75 |
test/unit/helpers/application_helper_test.rb | ||
---|---|---|
383 | 383 |
# invalid expressions |
384 | 384 |
'source:' => 'source:', |
385 | 385 |
# url hash |
386 |
"http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>', |
|
386 |
"http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>', |
|
387 |
# user |
|
388 |
'user:jsmith' => link_to_user(User.find_by_id(2)), |
|
389 |
'@jsmith' => link_to_user(User.find_by_id(2)), |
|
390 |
# invalid user |
|
391 |
'user:foobar' => 'user:foobar', |
|
387 | 392 |
} |
388 | 393 |
@project = Project.find(1) |
389 | 394 |
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" } |
390 | 395 |
end |
391 | 396 | |
397 |
def test_user_links_with_email_as_login_name_should_not_be_parsed |
|
398 |
u = User.generate!(:login => 'jsmith@somenet.foo') |
|
399 |
raw = "@jsmith@somenet.foo should not be parsed in jsmith@somenet.foo" |
|
400 | ||
401 |
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>}, |
|
402 |
textilizable(raw, :project => Project.find(1)) |
|
403 |
end |
|
404 | ||
392 | 405 |
def test_should_not_parse_redmine_links_inside_link |
393 | 406 |
raw = "r1 should not be parsed in http://example.com/url-r1/" |
394 | 407 |
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>}, |