Class: Banzai::Filter::References::LabelReferenceFilter

Inherits:
AbstractReferenceFilter show all
Defined in:
lib/banzai/filter/references/label_reference_filter.rb

Overview

HTML filter that replaces label references with links.

Constant Summary

Constants inherited from AbstractReferenceFilter

AbstractReferenceFilter::REFERENCE_PLACEHOLDER, AbstractReferenceFilter::REFERENCE_PLACEHOLDER_PATTERN

Constants inherited from ReferenceFilter

ReferenceFilter::REFERENCE_TYPE_DATA_ATTRIBUTE

Instance Method Summary collapse

Methods inherited from AbstractReferenceFilter

#call, #data_attributes_for, #find_object_cached, #find_object_from_link, #find_object_from_link_cached, #from_ref_cached, #identifier, #initialize, #object_link_filter, #object_link_text_extras, #parent_type, #symbol_from_match, #url_for_object_cached

Methods included from CrossProjectReference

#parent_from_ref

Methods inherited from ReferenceFilter

call, #call, #call_and_update_nodes, #each_node, #group, #initialize, #nodes, #object_class, #project

Methods included from OutputSafety

#escape_once

Methods included from RequestStoreReferenceCache

#cached_call, #get_or_set_cache

Constructor Details

This class inherits a constructor from Banzai::Filter::References::AbstractReferenceFilter

Instance Method Details

#find_labels(parent) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 81

def find_labels(parent)
  params = if parent.is_a?(Group)
             { group_id: parent.id,
               include_ancestor_groups: true,
               only_group_labels: true }
           else
             { project: parent,
               include_ancestor_groups: true }
           end

  LabelsFinder.new(nil, params).execute(skip_authorization: true)
end

#find_object(parent_object, id) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 32

def find_object(parent_object, id)
  key = reference_cache.records_per_parent[parent_object].keys.find do |k|
    k[:label_id] == id[:label_id] || k[:label_name] == id[:label_name]
  end

  reference_cache.records_per_parent[parent_object][key] if key
end

#full_path_ref?(matches) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 128

def full_path_ref?(matches)
  matches[:namespace] && matches[:project]
end


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 107

def object_link_text(object, matches)
  label_suffix = ''
  parent = project || group

  if project || full_path_ref?(matches)
    project_path    = reference_cache.full_project_path(matches[:namespace], matches[:project])
    parent_from_ref = from_ref_cached(project_path)
    reference       = parent_from_ref.to_human_reference(parent)

    label_suffix = " <i>in #{ERB::Util.html_escape(reference)}</i>" if reference.present?
  end

  presenter = object.present(issuable_subject: parent)
  LabelsHelper.render_colored_label(presenter, suffix: label_suffix)
end


136
137
138
139
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 136

def object_link_title(object, matches)
  presenter = object.present(issuable_subject: project || group)
  LabelsHelper.label_tooltip_title(presenter)
end

#parentObject



141
142
143
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 141

def parent
  project || group
end

#parent_records(parent, ids) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 11

def parent_records(parent, ids)
  return Label.none unless parent.is_a?(Project) || parent.is_a?(Group)

  labels = find_labels(parent)
  label_ids = ids.map { |y| y[:label_id] }.compact

  unless label_ids.empty?
    id_relation = labels.where(id: label_ids)
  end

  label_names = ids.map { |y| y[:label_name] }.compact
  unless label_names.empty?
    label_relation = labels.where(title: label_names)
  end

  relation = [id_relation, label_relation].compact
  return Label.none if relation.all?(Label.none)

  Label.from_union(relation)
end

#parse_symbol(symbol, match_data) ⇒ Object

Transform a symbol extracted from the text to a meaningful value

This method has the contract that if a string ‘ref` refers to a record `record`, then `parse_symbol(ref) == record_identifier(record)`.

This contract is slightly broken here, as we only have either the label_id or the label_name, but not both. But below, we have both pieces of information. But it’s accounted for in ‘find_object`



48
49
50
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 48

def parse_symbol(symbol, match_data)
  { label_id: match_data[:label_id]&.to_i, label_name: match_data[:label_name]&.tr('"', '') }
end

#record_identifier(record) ⇒ Object

We assume that most classes are identifying records by ID.

This method has the contract that if a string ‘ref` refers to a record `record`, then `class.parse_symbol(ref) == record_identifier(record)`. See note in `parse_symbol` above



57
58
59
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 57

def record_identifier(record)
  { label_id: record.id, label_name: record.title }
end

#reference_class(type, tooltip: true) ⇒ Object



132
133
134
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 132

def reference_class(type, tooltip: true)
  super + ' gl-link gl-label-link'
end

#references_in(text, pattern = Label.reference_pattern) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 61

def references_in(text, pattern = Label.reference_pattern)
  labels = {}

  unescaped_html = unescape_html_entities(text).gsub(pattern).with_index do |match, index|
    ident = identifier($~)
    label = yield match, ident, $~[:project], $~[:namespace], $~

    if label != match
      labels[index] = label
      "#{REFERENCE_PLACEHOLDER}#{index}"
    else
      match
    end
  end

  return text if labels.empty?

  escape_with_placeholders(unescaped_html, labels)
end

#requires_unescaping?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 145

def requires_unescaping?
  true
end

#url_for_object(label, parent) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 94

def url_for_object(label, parent)
  label_url_method =
    if context[:label_url_method]
      context[:label_url_method]
    elsif parent.is_a?(Project)
      :project_issues_url
    end

  return unless label_url_method

  Gitlab::Routing.url_helpers.public_send(label_url_method, parent, label_name: label.name, only_path: context[:only_path]) # rubocop:disable GitlabSecurity/PublicSend
end


123
124
125
126
# File 'lib/banzai/filter/references/label_reference_filter.rb', line 123

def wrap_link(link, label)
  presenter = label.present(issuable_subject: project || group)
  LabelsHelper.wrap_label_html(link, small: true, label: presenter)
end