Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2015-10-07 18:00:48 +0300
committerDouwe Maan <douwe@gitlab.com>2015-10-07 18:00:48 +0300
commitf42cfa9e8757161414f88e50d23b1d618bffad1f (patch)
tree8c379580d815a37e3090213974fed6969fb2927a /lib/gitlab
parent12626f029dc4ab345f8afa1fd42a3c04723ec55e (diff)
Refactor reference gathering to use a dedicated filter
Diffstat (limited to 'lib/gitlab')
-rw-r--r--lib/gitlab/markdown/commit_range_reference_filter.rb16
-rw-r--r--lib/gitlab/markdown/commit_reference_filter.rb24
-rw-r--r--lib/gitlab/markdown/external_issue_reference_filter.rb3
-rw-r--r--lib/gitlab/markdown/issue_reference_filter.rb11
-rw-r--r--lib/gitlab/markdown/label_reference_filter.rb11
-rw-r--r--lib/gitlab/markdown/merge_request_reference_filter.rb11
-rw-r--r--lib/gitlab/markdown/redactor_filter.rb44
-rw-r--r--lib/gitlab/markdown/reference_filter.rb34
-rw-r--r--lib/gitlab/markdown/reference_gatherer_filter.rb49
-rw-r--r--lib/gitlab/markdown/snippet_reference_filter.rb11
-rw-r--r--lib/gitlab/markdown/user_reference_filter.rb42
-rw-r--r--lib/gitlab/reference_extractor.rb2
12 files changed, 169 insertions, 89 deletions
diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb
index bb496135d92..e070edae0a4 100644
--- a/lib/gitlab/markdown/commit_range_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_range_reference_filter.rb
@@ -26,6 +26,18 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ project = Project.find(node.attr("data-project")) rescue nil
+ return unless project
+
+ id = node.attr("data-commit-range")
+ range = CommitRange.new(id, project)
+
+ return unless range.valid_commits?
+
+ { commit_range: range }
+ end
+
def initialize(*args)
super
@@ -53,13 +65,11 @@ module Gitlab
range = CommitRange.new(id, project)
if range.valid_commits?
- push_result(:commit_range, range)
-
url = url_for_commit_range(project, range)
title = range.reference_title
klass = reference_class(:commit_range)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, commit_range: id)
project_ref += '@' if project_ref
diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb
index fcbb2e936a5..8cdbeb1f9cf 100644
--- a/lib/gitlab/markdown/commit_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_reference_filter.rb
@@ -26,6 +26,18 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ project = Project.find(node.attr("data-project")) rescue nil
+ return unless project
+
+ id = node.attr("data-commit")
+ commit = commit_from_ref(project, id)
+
+ return unless commit
+
+ { commit: commit }
+ end
+
def call
replace_text_nodes_matching(Commit.reference_pattern) do |content|
commit_link_filter(content)
@@ -39,17 +51,15 @@ module Gitlab
# Returns a String with commit references replaced with links. All links
# have `gfm` and `gfm-commit` class names attached for styling.
def commit_link_filter(text)
- self.class.references_in(text) do |match, commit_ref, project_ref|
+ self.class.references_in(text) do |match, id, project_ref|
project = self.project_from_ref(project_ref)
- if commit = commit_from_ref(project, commit_ref)
- push_result(:commit, commit)
-
+ if commit = self.class.commit_from_ref(project, id)
url = url_for_commit(project, commit)
title = escape_once(commit.link_title)
klass = reference_class(:commit)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, commit: id)
project_ref += '@' if project_ref
@@ -62,9 +72,9 @@ module Gitlab
end
end
- def commit_from_ref(project, commit_ref)
+ def self.commit_from_ref(project, id)
if project && project.valid_repo?
- project.commit(commit_ref)
+ project.commit(id)
end
end
diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb
index f7c43e1ca89..8f86f13976a 100644
--- a/lib/gitlab/markdown/external_issue_reference_filter.rb
+++ b/lib/gitlab/markdown/external_issue_reference_filter.rb
@@ -47,8 +47,9 @@ module Gitlab
title = escape_once("Issue in #{project.external_issue_tracker.title}")
klass = reference_class(:issue)
+ data = data_attribute(project: project.id)
- %(<a href="#{url}"
+ %(<a href="#{url}" #{data}
title="#{title}"
class="#{klass}">#{match}</a>)
end
diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb
index 01320f80796..cd2a9b75680 100644
--- a/lib/gitlab/markdown/issue_reference_filter.rb
+++ b/lib/gitlab/markdown/issue_reference_filter.rb
@@ -27,6 +27,13 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ issue = Issue.find(node.attr("data-issue")) rescue nil
+ return unless issue
+
+ { issue: issue }
+ end
+
def call
replace_text_nodes_matching(Issue.reference_pattern) do |content|
issue_link_filter(content)
@@ -45,13 +52,11 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && issue = project.get_issue(id)
- push_result(:issue, issue)
-
url = url_for_issue(id, project, only_path: context[:only_path])
title = escape_once("Issue: #{issue.title}")
klass = reference_class(:issue)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, issue: issue.id)
%(<a href="#{url}" #{data}
title="#{title}"
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index 1e5cb12071e..59568ab531f 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -22,6 +22,13 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ label = Label.find(node.attr("data-label")) rescue nil
+ return unless label
+
+ { label: label }
+ end
+
def call
replace_text_nodes_matching(Label.reference_pattern) do |content|
label_link_filter(content)
@@ -41,11 +48,9 @@ module Gitlab
params = label_params(id, name)
if label = project.labels.find_by(params)
- push_result(:label, label)
-
url = url_for_label(project, label)
klass = reference_class(:label)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, label: label.id)
%(<a href="#{url}" #{data}
class="#{klass}">#{render_colored_label(label)}</a>)
diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb
index ecbd263d0e0..440574e574b 100644
--- a/lib/gitlab/markdown/merge_request_reference_filter.rb
+++ b/lib/gitlab/markdown/merge_request_reference_filter.rb
@@ -27,6 +27,13 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ merge_request = MergeRequest.find(node.attr("data-merge-request")) rescue nil
+ return unless merge_request
+
+ { merge_request: merge_request }
+ end
+
def call
replace_text_nodes_matching(MergeRequest.reference_pattern) do |content|
merge_request_link_filter(content)
@@ -45,11 +52,9 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && merge_request = project.merge_requests.find_by(iid: id)
- push_result(:merge_request, merge_request)
-
title = escape_once("Merge Request: #{merge_request.title}")
klass = reference_class(:merge_request)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, merge_request: merge_request.id)
url = url_for_merge_request(merge_request, project)
diff --git a/lib/gitlab/markdown/redactor_filter.rb b/lib/gitlab/markdown/redactor_filter.rb
index ae1c3c365bd..07ea6207d22 100644
--- a/lib/gitlab/markdown/redactor_filter.rb
+++ b/lib/gitlab/markdown/redactor_filter.rb
@@ -19,49 +19,19 @@ module Gitlab
doc
end
+ private
+
def user_can_reference?(node)
- if node.has_attribute?('data-group-id')
- user_can_reference_group?(node.attr('data-group-id'))
- elsif node.has_attribute?('data-project-id')
- user_can_reference_project?(node.attr('data-project-id'))
- elsif node.has_attribute?('data-user-id')
- user_can_reference_user?(node.attr('data-user-id'))
+ if node.has_attribute?('data-reference-filter')
+ reference_type = node.attr('data-reference-filter')
+ reference_filter = reference_type.constantize
+
+ reference_filter.user_can_reference?(current_user, node)
else
true
end
end
- def user_can_reference_group?(id)
- group = Group.find(id)
-
- group && can?(:read_group, group)
- rescue ActiveRecord::RecordNotFound
- false
- end
-
- def user_can_reference_project?(id)
- project = Project.find(id)
-
- project && can?(:read_project, project)
- rescue ActiveRecord::RecordNotFound
- false
- end
-
- def user_can_reference_user?(id)
- # Permit all user reference links
- true
- end
-
- private
-
- def abilities
- Ability.abilities
- end
-
- def can?(ability, object)
- abilities.allowed?(current_user, ability, object)
- end
-
def current_user
context[:current_user]
end
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb
index 9b293c957d6..ea6136b3303 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/gitlab/markdown/reference_filter.rb
@@ -15,10 +15,17 @@ module Gitlab
# Results:
# :references - A Hash of references that were found and replaced.
class ReferenceFilter < HTML::Pipeline::Filter
- def initialize(*args)
- super
+ def self.user_can_reference?(user, node)
+ if node.has_attribute?('data-project')
+ project = Project.find(node.attr('data-project')) rescue nil
+ Ability.abilities.allowed?(user, :read_project, project)
+ else
+ true
+ end
+ end
- result[:references] = Hash.new { |hash, type| hash[type] = [] }
+ def self.referenced_by(node)
+ nil
end
# Returns a data attribute String to attach to a reference link
@@ -28,13 +35,14 @@ module Gitlab
#
# Examples:
#
- # data_attribute(1) # => "data-project-id=\"1\""
- # data_attribute(2, :user) # => "data-user-id=\"2\""
- # data_attribute(3, :group) # => "data-group-id=\"3\""
+ # data_attribute(project: 1) # => "data-reference-filter=\"SomeReferenceFilter\" data-project=\"1\""
+ # data_attribute(user: 2) # => "data-reference-filter=\"SomeReferenceFilter\" data-user=\"2\""
+ # data_attribute(group: 3) # => "data-reference-filter=\"SomeReferenceFilter\" data-group=\"3\""
#
# Returns a String
- def data_attribute(id, type = :project)
- %Q(data-#{type}-id="#{id}")
+ def data_attribute(attributes = {})
+ attributes[:reference_filter] = self.class.name
+ attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{value}") }.join(" ")
end
def escape_once(html)
@@ -59,16 +67,6 @@ module Gitlab
context[:project]
end
- # Add a reference to the pipeline's result Hash
- #
- # type - Singular Symbol reference type (e.g., :issue, :user, etc.)
- # values - One or more Objects to add
- def push_result(type, *values)
- return if values.empty?
-
- result[:references][type].push(*values)
- end
-
def reference_class(type)
"gfm gfm-#{type}"
end
diff --git a/lib/gitlab/markdown/reference_gatherer_filter.rb b/lib/gitlab/markdown/reference_gatherer_filter.rb
new file mode 100644
index 00000000000..d64671e9550
--- /dev/null
+++ b/lib/gitlab/markdown/reference_gatherer_filter.rb
@@ -0,0 +1,49 @@
+require 'gitlab/markdown'
+require 'html/pipeline/filter'
+
+module Gitlab
+ module Markdown
+ # HTML filter that removes references to records that the current user does
+ # not have permission to view.
+ #
+ # Expected to be run in its own post-processing pipeline.
+ #
+ class ReferenceGathererFilter < HTML::Pipeline::Filter
+ def initialize(*)
+ super
+
+ result[:references] ||= Hash.new { |hash, type| hash[type] = [] }
+ end
+
+ def call
+ doc.css('a.gfm').each do |node|
+ gather_references(node)
+ end
+
+ doc
+ end
+
+ private
+
+ def gather_references(node)
+ return unless node.has_attribute?('data-reference-filter')
+
+ reference_type = node.attr('data-reference-filter')
+ reference_filter = reference_type.constantize
+
+ return unless reference_filter.user_can_reference?(current_user, node)
+
+ references = reference_filter.referenced_by(node)
+ return unless references
+
+ references.each do |type, values|
+ result[:references][type].push(*values)
+ end
+ end
+
+ def current_user
+ context[:current_user]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb
index e2cf89cb1d8..a7396e96529 100644
--- a/lib/gitlab/markdown/snippet_reference_filter.rb
+++ b/lib/gitlab/markdown/snippet_reference_filter.rb
@@ -27,6 +27,13 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ snippet = Snippet.find(node.attr("data-snippet")) rescue nil
+ return unless snippet
+
+ { snippet: snippet }
+ end
+
def call
replace_text_nodes_matching(Snippet.reference_pattern) do |content|
snippet_link_filter(content)
@@ -45,11 +52,9 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && snippet = project.snippets.find_by(id: id)
- push_result(:snippet, snippet)
-
title = escape_once("Snippet: #{snippet.title}")
klass = reference_class(:snippet)
- data = data_attribute(project.id)
+ data = data_attribute(project: project.id, snippet: snippet.id)
url = url_for_snippet(snippet, project)
diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb
index c08811effb2..0d2be7499b7 100644
--- a/lib/gitlab/markdown/user_reference_filter.rb
+++ b/lib/gitlab/markdown/user_reference_filter.rb
@@ -23,6 +23,34 @@ module Gitlab
end
end
+ def self.referenced_by(node)
+ if node.has_attribute?('data-group')
+ group = Group.find(node.attr('data-group')) rescue nil
+ return unless group
+
+ { user: group.users }
+ elsif node.has_attribute?('data-user')
+ user = User.find(node.attr('data-user')) rescue nil
+ return unless user
+
+ { user: user }
+ elsif node.has_attribute?('data-project')
+ project = Project.find(node.attr('data-project')) rescue nil
+ return unless project
+
+ { user: project.team.members.flatten }
+ end
+ end
+
+ def self.user_can_reference?(user, node)
+ if node.has_attribute?('data-group')
+ group = Group.find(node.attr('data-group')) rescue nil
+ Ability.abilities.allowed?(user, :read_group, group)
+ else
+ super
+ end
+ end
+
def call
replace_text_nodes_matching(User.reference_pattern) do |content|
user_link_filter(content)
@@ -61,14 +89,12 @@ module Gitlab
def link_to_all
project = context[:project]
- # FIXME (rspeicher): Law of Demeter
- push_result(:user, *project.team.members.flatten)
-
url = urls.namespace_project_url(project.namespace, project,
only_path: context[:only_path])
+ data = data_attribute(project: project.id)
text = User.reference_prefix + 'all'
- %(<a href="#{url}" class="#{link_class}">#{text}</a>)
+ %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
end
def link_to_namespace(namespace)
@@ -80,20 +106,16 @@ module Gitlab
end
def link_to_group(group, namespace)
- push_result(:user, *namespace.users)
-
url = urls.group_url(group, only_path: context[:only_path])
- data = data_attribute(namespace.id, :group)
+ data = data_attribute(group: namespace.id)
text = Group.reference_prefix + group
%(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
end
def link_to_user(user, namespace)
- push_result(:user, namespace.owner)
-
url = urls.user_url(user, only_path: context[:only_path])
- data = data_attribute(namespace.owner_id, :user)
+ data = data_attribute(user: namespace.owner_id)
text = User.reference_prefix + user
%(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 0961bd80421..2e546ef0d54 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -50,7 +50,7 @@ module Gitlab
ignore_blockquotes: true
}
- pipeline = HTML::Pipeline.new([filter], context)
+ pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context)
result = pipeline.call(@text)
result[:references][filter_type]