From 9c046fea676b65c4883707fad22ceb8dd0e7525e Mon Sep 17 00:00:00 2001
From: skv <skv-headless@yandex.ru>
Date: Mon, 26 May 2014 16:40:10 +0400
Subject: [PATCH] links to issues on main dashboard

---
 app/helpers/gitlab_markdown_helper.rb       |  2 +-
 app/helpers/issues_helper.rb                | 82 ++++++++---------
 app/views/events/_commit.html.haml          |  2 +-
 lib/gitlab/markdown.rb                      | 97 +++++++++++++--------
 lib/gitlab/reference_extractor.rb           |  2 +-
 spec/helpers/gitlab_markdown_helper_spec.rb |  3 +-
 6 files changed, 110 insertions(+), 78 deletions(-)

diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 69425bc171d..39ec5672fc0 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -19,7 +19,7 @@ module GitlabMarkdownHelper
                      escape_once(body)
                    end
 
-    gfm_body = gfm(escaped_body, html_options)
+    gfm_body = gfm(escaped_body, @project, html_options)
 
     gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match|
       "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 7c58908165c..2031519c32f 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -13,76 +13,80 @@ module IssuesHelper
     OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
   end
 
-  def url_for_project_issues
-    return "" if @project.nil?
+  def url_for_project_issues(project = @project)
+    return '' if project.nil?
 
-    if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      project_issues_path(@project)
+    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+      project_issues_path(project)
     else
-      url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"]
-      url.gsub(':project_id', @project.id.to_s)
-         .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
+      url = Gitlab.config.issues_tracker[project.issues_tracker]['project_url']
+      url.gsub(':project_id', project.id.to_s).
+          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
     end
   end
 
-  def url_for_new_issue
-    return "" if @project.nil?
+  def url_for_new_issue(project = @project)
+    return '' if project.nil?
 
-    if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      url = new_project_issue_path project_id: @project
+    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+      url = new_project_issue_path project_id: project
     else
-      url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"]
-      url.gsub(':project_id', @project.id.to_s)
-        .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
+      issues_tracker = Gitlab.config.issues_tracker[project.issues_tracker]
+      url = issues_tracker['new_issue_url']
+      url.gsub(':project_id', project.id.to_s).
+          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
     end
   end
 
-  def url_for_issue(issue_iid)
-    return "" if @project.nil?
+  def url_for_issue(issue_iid, project = @project)
+    return '' if project.nil?
 
-    if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-      url = project_issue_url project_id: @project, id: issue_iid
+    if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+      url = project_issue_url project_id: project, id: issue_iid
     else
-      url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"]
-      url.gsub(':id', issue_iid.to_s)
-        .gsub(':project_id', @project.id.to_s)
-        .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
+      url = Gitlab.config.issues_tracker[project.issues_tracker]['issues_url']
+      url.gsub(':id', issue_iid.to_s).
+          gsub(':project_id', project.id.to_s).
+          gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
     end
   end
 
-  def title_for_issue(issue_iid)
-    return "" if @project.nil?
+  def title_for_issue(issue_iid, project = @project)
+    return '' if project.nil?
 
-    if @project.used_default_issues_tracker? && issue = @project.issues.where(iid: issue_iid).first
-      issue.title
-    else
-      ""
+    if project.used_default_issues_tracker?
+      issue = project.issues.where(iid: issue_iid).first
+      return issue.title if issue
     end
+
+    ''
   end
 
   # Checks if issues_tracker setting exists in gitlab.yml
   def external_issues_tracker_enabled?
-    if Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
-      true
-    else
-      false
-    end
+    Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
   end
 
   def bulk_update_milestone_options
-    options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
+    options_for_select(['None (backlog)']) +
+        options_from_collection_for_select(project_active_milestones, 'id',
+                                           'title', params[:milestone_id])
   end
 
-  def bulk_update_assignee_options
-    options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
+  def bulk_update_assignee_options(project = @project)
+    options_for_select(['None (unassigned)']) +
+        options_from_collection_for_select(project.team.members, 'id',
+                                           'name', params[:assignee_id])
   end
 
-  def assignee_options object
-    options_from_collection_for_select(@project.team.members.sort_by(&:name), 'id', 'name', object.assignee_id)
+  def assignee_options(object, project = @project)
+    options_from_collection_for_select(project.team.members.sort_by(&:name),
+                                       'id', 'name', object.assignee_id)
   end
 
   def milestone_options object
-    options_from_collection_for_select(object.project.milestones.active, 'id', 'title', object.milestone_id)
+    options_from_collection_for_select(object.project.milestones.active,
+                                       'id', 'title', object.milestone_id)
   end
 
   def issue_box_class(item)
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 135320da57e..0e03e116e7d 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -2,4 +2,4 @@
   .commit-row-title
     = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
     &nbsp;
-    = gfm event_commit_title(commit[:message])
+    = gfm event_commit_title(commit[:message]), project
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index dca3d7a7bed..73a149621c1 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -33,10 +33,9 @@ module Gitlab
     # Public: Parse the provided text with GitLab-Flavored Markdown
     #
     # text         - the source text
+    # project      - extra options for the reference links as given to link_to
     # html_options - extra options for the reference links as given to link_to
-    #
-    # Note: reference links will only be generated if @project is set
-    def gfm(text, html_options = {})
+    def gfm(text, project = @project, html_options = {})
       return text if text.nil?
 
       # Duplicate the string so we don't alter the original, then call to_str
@@ -56,14 +55,19 @@ module Gitlab
 
       # TODO: add popups with additional information
 
-      text = parse(text)
+      text = parse(text, project)
 
       # Insert pre block extractions
       text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
         insert_piece($1)
       end
 
-      sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class), tags: ActionView::Base.sanitized_allowed_tags + %w(table tr td th)
+      allowed_attributes = ActionView::Base.sanitized_allowed_attributes
+      allowed_tags = ActionView::Base.sanitized_allowed_tags
+
+      sanitize text.html_safe,
+               attributes: allowed_attributes + %w(id class),
+               tags: allowed_tags + %w(table tr td th)
     end
 
     private
@@ -84,11 +88,9 @@ module Gitlab
     #
     # text - Text to parse
     #
-    # Note: reference links will only be generated if @project is set
-    #
     # Returns parsed text
-    def parse(text)
-      parse_references(text) if @project
+    def parse(text, project = @project)
+      parse_references(text, project) if project
       parse_emoji(text)
 
       text
@@ -110,7 +112,7 @@ module Gitlab
 
     TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze
 
-    def parse_references(text)
+    def parse_references(text, project = @project)
       # parse reference links
       text.gsub!(REFERENCE_PATTERN) do |match|
         prefix     = $~[:prefix]
@@ -123,7 +125,7 @@ module Gitlab
           # Avoid HTML entities
           if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
             match
-          elsif ref_link = reference_link(type, identifier)
+          elsif ref_link = reference_link(type, identifier, project)
             "#{prefix}#{ref_link}#{suffix}"
           else
             match
@@ -153,7 +155,7 @@ module Gitlab
     #
     # Returns boolean
     def valid_emoji?(emoji)
-      Emoji.find_by_name emoji
+      Emoji.find_by_name(emoji)
     end
 
     # Private: Dispatches to a dedicated processing method based on reference
@@ -162,52 +164,77 @@ module Gitlab
     # identifier - Object identifier (Issue ID, SHA hash, etc.)
     #
     # Returns string rendered by the processing method
-    def reference_link(type, identifier)
-      send("reference_#{type}", identifier)
+    def reference_link(type, identifier, project = @project)
+      send("reference_#{type}", identifier, project)
     end
 
-    def reference_user(identifier)
-      if user = User.find_by_username(identifier)
-        link_to("@#{identifier}", user_url(identifier), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}"))
+    def reference_user(identifier, project = @project)
+      if user = User.find_by(username: identifier)
+        options = html_options.merge(
+          class: "gfm gfm-team_member #{html_options[:class]}"
+        )
+        link_to("@#{identifier}", user_url(identifier), options)
       end
     end
 
-    def reference_issue(identifier)
-      if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
-        if @project.issue_exists? identifier
-          url = url_for_issue(identifier)
+    def reference_issue(identifier, project = @project)
+      if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
+        if project.issue_exists? identifier
+          url = url_for_issue(identifier, project)
           title = title_for_issue(identifier)
+          options = html_options.merge(
+            title: "Issue: #{title}",
+            class: "gfm gfm-issue #{html_options[:class]}"
+          )
 
-          link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}"))
+          link_to("##{identifier}", url, options)
         end
-      else
-        reference_jira_issue(identifier) if @project.issues_tracker == "jira"
+      elsif project.issues_tracker == 'jira'
+        reference_jira_issue(identifier, project)
       end
     end
 
-    def reference_merge_request(identifier)
-      if merge_request = @project.merge_requests.where(iid: identifier).first
-        link_to("!#{identifier}", project_merge_request_url(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}"))
+    def reference_merge_request(identifier, project = @project)
+      if merge_request = project.merge_requests.find_by(iid: identifier)
+        options = html_options.merge(
+          title: "Merge Request: #{merge_request.title}",
+          class: "gfm gfm-merge_request #{html_options[:class]}"
+        )
+        url = project_merge_request_url(project, merge_request)
+        link_to("!#{identifier}", url, options)
       end
     end
 
-    def reference_snippet(identifier)
-      if snippet = @project.snippets.where(id: identifier).first
-        link_to("$#{identifier}", project_snippet_url(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}"))
+    def reference_snippet(identifier, project = @project)
+      if snippet = project.snippets.find_by(id: identifier)
+        options = html_options.merge(
+          title: "Snippet: #{snippet.title}",
+          class: "gfm gfm-snippet #{html_options[:class]}"
+        )
+        link_to("$#{identifier}", project_snippet_url(project, snippet),
+                options)
       end
     end
 
-    def reference_commit(identifier)
-      if @project.valid_repo? && commit = @project.repository.commit(identifier)
-        link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: commit.link_title, class: "gfm gfm-commit #{html_options[:class]}"))
+    def reference_commit(identifier, project = @project)
+      if project.valid_repo? && commit = project.repository.commit(identifier)
+        options = html_options.merge(
+          title: commit.link_title,
+          class: "gfm gfm-commit #{html_options[:class]}"
+        )
+        link_to(identifier, project_commit_url(project, commit), options)
       end
     end
 
-    def reference_jira_issue(identifier)
+    def reference_jira_issue(identifier, project = @project)
       url = url_for_issue(identifier)
       title = Gitlab.config.issues_tracker[@project.issues_tracker]["title"]
 
-      link_to("#{identifier}", url, html_options.merge(title: "Issue in #{title}", class: "gfm gfm-issue #{html_options[:class]}"))
+      options = html_options.merge(
+        title: "Issue in #{title}",
+        class: "gfm gfm-issue #{html_options[:class]}"
+      )
+      link_to("#{identifier}", url, options)
     end
   end
 end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 94b01e808d9..1eda614807f 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -51,7 +51,7 @@ module Gitlab
 
     private
 
-    def reference_link type, identifier
+    def reference_link(type, identifier, project)
       # Append identifier to the appropriate collection.
       send("#{type}s") << identifier
     end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 49b48d26e2b..fc9d1ac90c0 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -41,7 +41,8 @@ describe GitlabMarkdownHelper do
     end
 
     it "should forward HTML options to links" do
-      gfm("Fixed in #{commit.id}", class: "foo").should have_selector("a.gfm.foo")
+      gfm("Fixed in #{commit.id}", @project, class: 'foo').
+          should have_selector('a.gfm.foo')
     end
 
     describe "referencing a commit" do
-- 
GitLab