Project

General

Profile

Feature #4179 » 4179_link_to_user_in_wiki_syntax.patch

Marius BĂLTEANU, 2017-05-07 14:16

View differences:

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
            mail
......
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):&quot;(.+?)&quot;/) 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>},
(1-1/5)