summaryrefslogtreecommitdiff
path: root/lib/banzai
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2017-08-03 12:50:06 +0100
committerSean McGivern <sean@gitlab.com>2017-08-07 11:55:00 +0100
commit149528f472f3d2f3865ae01c764b81c6a97f9380 (patch)
tree8c9e38e7071b0a0002d3741259a7318e7a0427e5 /lib/banzai
parent03b816f3e845c9b25d3588336fc1616238465deb (diff)
downloadgitlab-ce-149528f472f3d2f3865ae01c764b81c6a97f9380.tar.gz
Support references to group milestones
Group milestones can only be referred to by name, not IID. They also do not support cross-project references.
Diffstat (limited to 'lib/banzai')
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb41
-rw-r--r--lib/banzai/filter/milestone_reference_filter.rb34
2 files changed, 64 insertions, 11 deletions
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 685b43605ae..5db4fe77885 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -59,6 +59,12 @@ module Banzai
# Example: project.merge_requests.find
end
+ # Override if the link reference pattern produces a different ID (global
+ # ID vs internal ID, for instance) to the regular reference pattern.
+ def find_object_from_link(project, id)
+ find_object(project, id)
+ end
+
def find_object_cached(project, id)
if RequestStore.active?
cache = find_objects_cache[object_class][project.id]
@@ -69,6 +75,16 @@ module Banzai
end
end
+ def find_object_from_link_cached(project, id)
+ if RequestStore.active?
+ cache = find_objects_from_link_cache[object_class][project.id]
+
+ get_or_set_cache(cache, id) { find_object_from_link(project, id) }
+ else
+ find_object_from_link(project, id)
+ end
+ end
+
def project_from_ref_cached(ref)
if RequestStore.active?
cache = project_refs_cache
@@ -120,7 +136,7 @@ module Banzai
if link == inner_html && inner_html =~ /\A#{link_pattern}/
replace_link_node_with_text(node, link) do
- object_link_filter(inner_html, link_pattern)
+ object_link_filter(inner_html, link_pattern, link_reference: true)
end
next
@@ -128,7 +144,7 @@ module Banzai
if link =~ /\A#{link_pattern}\z/
replace_link_node_with_href(node, link) do
- object_link_filter(link, link_pattern, link_content: inner_html)
+ object_link_filter(link, link_pattern, link_content: inner_html, link_reference: true)
end
next
@@ -146,15 +162,26 @@ module Banzai
# text - String text to replace references in.
# pattern - Reference pattern to match against.
# link_content - Original content of the link being replaced.
+ # link_reference - True if this was using the link reference pattern,
+ # false otherwise.
#
# Returns a String with references replaced with links. All links
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
- def object_link_filter(text, pattern, link_content: nil)
+ def object_link_filter(text, pattern, link_content: nil, link_reference: false)
references_in(text, pattern) do |match, id, project_ref, namespace_ref, matches|
project_path = full_project_path(namespace_ref, project_ref)
project = project_from_ref_cached(project_path)
- if project && object = find_object_cached(project, id)
+ if project
+ object =
+ if link_reference
+ find_object_from_link_cached(project, id)
+ else
+ find_object_cached(project, id)
+ end
+ end
+
+ if object
title = object_link_title(object)
klass = reference_class(object_sym)
@@ -303,6 +330,12 @@ module Banzai
end
end
+ def find_objects_from_link_cache
+ RequestStore[:banzai_find_objects_from_link_cache] ||= Hash.new do |hash, key|
+ hash[key] = Hash.new { |h, k| h[k] = {} }
+ end
+ end
+
def url_for_object_cache
RequestStore[:banzai_url_for_object] ||= Hash.new do |hash, key|
hash[key] = Hash.new { |h, k| h[k] = {} }
diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb
index 45c033d32a8..4fc5f211e84 100644
--- a/lib/banzai/filter/milestone_reference_filter.rb
+++ b/lib/banzai/filter/milestone_reference_filter.rb
@@ -8,8 +8,15 @@ module Banzai
Milestone
end
+ # Links to project milestones contain the IID, but when we're handling
+ # 'regular' references, we need to use the global ID to disambiguate
+ # between group and project milestones.
def find_object(project, id)
- project.milestones.find_by(iid: id)
+ find_milestone_with_finder(project, id: id)
+ end
+
+ def find_object_from_link(project, iid)
+ find_milestone_with_finder(project, iid: iid)
end
def references_in(text, pattern = Milestone.reference_pattern)
@@ -22,7 +29,7 @@ module Banzai
milestone = find_milestone($~[:project], $~[:namespace], $~[:milestone_iid], $~[:milestone_name])
if milestone
- yield match, milestone.iid, $~[:project], $~[:namespace], $~
+ yield match, milestone.id, $~[:project], $~[:namespace], $~
else
match
end
@@ -36,7 +43,8 @@ module Banzai
return unless project
milestone_params = milestone_params(milestone_id, milestone_name)
- project.milestones.find_by(milestone_params)
+
+ find_milestone_with_finder(project, milestone_params)
end
def milestone_params(iid, name)
@@ -47,15 +55,27 @@ module Banzai
end
end
+ def find_milestone_with_finder(project, params)
+ finder_params = { project_ids: [project.id], order: nil }
+
+ # We don't support IID lookups for group milestones, because IIDs can
+ # clash between group and project milestones.
+ if project.group && !params[:iid]
+ finder_params[:group_ids] = [project.group.id]
+ end
+
+ MilestonesFinder.new(finder_params).execute.find_by(params)
+ end
+
def url_for_object(milestone, project)
- h = Gitlab::Routing.url_helpers
- h.project_milestone_url(project, milestone,
- only_path: context[:only_path])
+ Gitlab::Routing
+ .url_helpers
+ .milestone_url(milestone, only_path: context[:only_path])
end
def object_link_text(object, matches)
milestone_link = escape_once(super)
- reference = object.project.to_reference(project)
+ reference = object.project&.to_reference(project)
if reference.present?
"#{milestone_link} <i>in #{reference}</i>".html_safe