diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index ee0ee05c3befe47c35b2991a98dd0b19891ead54..ea5882a172b08ad3b6a09863ebe2f96d0d9ffafd 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -26,15 +26,20 @@ module Gitlab # => "\":trollface:\" module Markdown REFERENCE_PATTERN = %r{ - (\W)? # Prefix (1) - ( # Reference (2) - @([\w\._]+) # User name (3) - |[#!$](\d+) # Issue/MR/Snippet ID (4) - |([\h]{6,40}) # Commit ID (5) + (?\W)? # Prefix + ( # Reference + @(?[\w\._]+) # User name + |@\{\ *(?[\w_\.][\w_\. ]+[\w_\.])\ *\} # User name alt syntax: @{User Name} + |\#(?\d+) # Issue ID + |!(?\d+) # MR ID + |\$(?\d+) # Snippet ID + |(?[\h]{6,40}) # Commit ID ) - (\W)? # Suffix (6) + (?\W)? # Suffix }x.freeze + TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze + EMOJI_PATTERN = %r{(:(\S+):)}.freeze attr_reader :html_options @@ -95,16 +100,16 @@ module Gitlab def parse_references(text) # parse reference links text.gsub!(REFERENCE_PATTERN) do |match| - prefix = $1 || '' - reference = $2 - identifier = $3 || $4 || $5 - suffix = $6 || '' + prefix = $~[:prefix] + suffix = $~[:suffix] + type = TYPES.select{|t| !$~[t].nil?}.first + identifier = $~[type] # Avoid HTML entities - if prefix.ends_with?('&') || suffix.starts_with?(';') + if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';' match - elsif ref_link = reference_link(reference, identifier) - prefix + ref_link + suffix + elsif ref_link = reference_link(type, identifier) + "#{prefix}#{ref_link}#{suffix}" else match end @@ -137,19 +142,12 @@ module Gitlab # identifier - Object identifier (Issue ID, SHA hash, etc.) # # Returns string rendered by the processing method - def reference_link(reference, identifier) - case reference - when /^@/ then reference_user(identifier) - when /^#/ then reference_issue(identifier) - when /^!/ then reference_merge_request(identifier) - when /^\$/ then reference_snippet(identifier) - when /^\h/ then reference_commit(identifier) - end + def reference_link(type, identifier) + send("reference_#{type}", identifier) end def reference_user(identifier) - if user = @project.users.where(name: identifier).first - member = @project.users_projects.where(user_id: user).first + if member = @project.users_projects.joins(:user).where(users: { name: identifier }).first link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member end end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 05e4527b278ef94e1b9587b4f279eb08e11273d1..961f68bce4d87c02e377879e417a1921c5baccdc 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -82,6 +82,7 @@ describe GitlabMarkdownHelper do describe "referencing a team member" do let(:actual) { "@#{user.name} you are right." } + let(:actual_w_spaces) { "@{#{user.name}} you are rigth." } let(:expected) { project_team_member_path(project, member) } before do @@ -102,6 +103,21 @@ describe GitlabMarkdownHelper do gfm(actual).should match(expected) end + it "should link using name with space" do + user.update_attributes(name: "King Kong") + gfm(actual_w_spaces).should match(expected) + end + + it "should link using name with space and dots" do + user.update_attributes(name: "King.alpha Kong") + gfm(actual_w_spaces).should match(expected) + end + + it "should link using name with space and underscore" do + user.update_attributes(name: "King_alpha Kong") + gfm(actual_w_spaces).should match(expected) + end + it "should link with adjacent text" do actual = "Mail the admin (@gfm)" gfm(actual).should match(expected)