]> source.dussan.org Git - redmine.git/commitdiff
Link to user in wiki syntax (#4179).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Wed, 7 Jun 2017 20:10:57 +0000 (20:10 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Wed, 7 Jun 2017 20:10:57 +0000 (20:10 +0000)
Patch by Marius BALTEANU.

git-svn-id: http://svn.redmine.org/redmine/trunk@16636 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/helpers/application_helper.rb
lib/redmine/wiki_formatting.rb
lib/redmine/wiki_formatting/markdown/formatter.rb
test/unit/helpers/application_helper_test.rb

index f1241d8b75a2f3116f01e10ad746d8425f1eda88..2a5c6d05d3a5f6d70e94c4476994276246b5ddf5 100644 (file)
@@ -224,7 +224,7 @@ module ApplicationHelper
       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,
@@ -810,6 +810,9 @@ module ApplicationHelper
   #  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
@@ -826,8 +829,8 @@ module ApplicationHelper
       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]
 
@@ -899,9 +902,7 @@ module ApplicationHelper
               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)
@@ -957,7 +958,14 @@ module ApplicationHelper
               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}"))
@@ -971,7 +979,7 @@ module ApplicationHelper
             (?<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>\#)|
@@ -987,8 +995,14 @@ module ApplicationHelper
                   -(?<comment_id>\d+)
                 )?
               )|
+              (
               (?<sep3>:)
               (?<identifier2>[^"\s<>][^\s<>]*?|"[^"]+?")
+              )|
+              (
+              (?<sep4>@)
+              (?<identifier3>[a-z0-9_\-@\.]*)
+              )
             )
             (?=
               (?=[[:punct:]][^A-Za-z0-9_/])|
@@ -1465,4 +1479,10 @@ module ApplicationHelper
     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
index 17348d16ee0594b0cbc183800c63553ceefd8fcc..03129aa2162426c85e257ce7bba3960c825ef486 100644 (file)
@@ -37,7 +37,7 @@ module Redmine
           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,
@@ -153,7 +153,7 @@ module Redmine
 
       # 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
@@ -161,7 +161,7 @@ module Redmine
             %(<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
index bfb04774cab558b936585dc7bb947e8399f83703..ba7f7c0c9e47d369618df2f0092e6553997b5035 100644 (file)
@@ -66,6 +66,10 @@ module Redmine
           html.gsub!(/(\w):&quot;(.+?)&quot;/) do
             "#{$1}:\"#{$2}\""
           end
+          # restore user links with @ in login name eg. [@jsmith@somenet.foo]
+          html.gsub!(%r{[@\A]<a href="mailto:(.*?)">(.*?)</a>}) do
+            "@#{$2}"
+          end
           html
         end
 
index 500fbd86e783b6dd6740873758b5fc7683b1ab77..678dcfda5aa0296fc3ad7dcc6695b18c3361a7df 100644 (file)
@@ -383,12 +383,25 @@ RAW
       # 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>},