diff options
author | Sean McGivern <sean@gitlab.com> | 2017-08-03 12:50:06 +0100 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2017-08-07 11:55:00 +0100 |
commit | 149528f472f3d2f3865ae01c764b81c6a97f9380 (patch) | |
tree | 8c9e38e7071b0a0002d3741259a7318e7a0427e5 /lib/banzai | |
parent | 03b816f3e845c9b25d3588336fc1616238465deb (diff) | |
download | gitlab-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.rb | 41 | ||||
-rw-r--r-- | lib/banzai/filter/milestone_reference_filter.rb | 34 |
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 |