Class: Banzai::ReferenceParser::BaseParser
- Inherits:
-
Object
- Object
- Banzai::ReferenceParser::BaseParser
- Defined in:
- lib/banzai/reference_parser/base_parser.rb
Overview
Base class for reference parsing classes.
Each parser should also specify its reference type by calling ‘self.reference_type = …` in the body of the class. The value of this method should be a symbol such as :issue or :merge_request. For example:
class IssueParser < BaseParser
self.reference_type = :issue
end
The reference type is used to determine what nodes to pass to the referenced_by method.
Parser classes should either implement the instance method references_relation or overwrite referenced_by. The references_relation method is supposed to return an ActiveRecord::Relation used as a base relation for retrieving the objects referenced in a set of HTML nodes.
Each class can implement two additional methods:
-
nodes_user_can_reference: returns an Array of nodes the given user can refer to. -
nodes_visible_to_user: returns an Array of nodes that are visible to the given user.
You only need to overwrite these methods if you want to tweak who can see which references. For example, the IssueParser class defines its own nodes_visible_to_user method so it can ensure users can only see issues they have access to.
Direct Known Subclasses
AlertParser, CommitParser, CommitRangeParser, DesignParser, ExternalIssueParser, FeatureFlagParser, IssuableParser, LabelParser, MentionedGroupParser, MentionedUserParser, MilestoneParser, ProjectParser, SnippetParser, UserParser, WikiPageParser
Class Attribute Summary collapse
-
.reference_options ⇒ Object
Returns the value of attribute reference_options.
-
.reference_type ⇒ Object
Returns the value of attribute reference_type.
Class Method Summary collapse
-
.data_attribute ⇒ Object
Returns the attribute name containing the value for every object to be parsed by the current parser.
-
.reference_class ⇒ Object
Returns a model class to use as a reference.
Instance Method Summary collapse
- #can?(user, permission, subject = :global) ⇒ Boolean
-
#collection_cache_key(collection) ⇒ Object
Returns the cache key to use for a collection.
-
#collection_objects_for_ids(collection, ids) ⇒ Object
Queries the collection for the objects with the given IDs.
- #find_projects_for_hash_keys(hash) ⇒ Object
-
#gather_attributes_per_project(nodes, attribute) ⇒ Object
Returns a Hash containing attribute values per project ID.
-
#gather_references(nodes, ids_only: false) ⇒ Object
Gathers the references for the given HTML nodes.
-
#grouped_objects_for_nodes(nodes, collection, attribute) ⇒ Object
Returns a Hash containing objects for an attribute grouped per the nodes that reference them.
- #groups_for_nodes(nodes) ⇒ Object
-
#initialize(context) ⇒ BaseParser
constructor
context - An instance of
Banzai::RenderContext. -
#nodes_user_can_reference(user, nodes) ⇒ Object
Returns all the nodes containing references that the user can refer to.
-
#nodes_visible_to_user(user, nodes) ⇒ Object
Returns all the nodes that are visible to the given user.
-
#process(documents, ids_only: false) ⇒ Object
Processes the list of HTML documents and returns an Array containing all the references.
- #project_for_node(node) ⇒ Object
-
#projects_for_nodes(nodes) ⇒ Object
Returns a Hash containing the projects for a given list of HTML nodes.
-
#referenced_by(nodes, options = {}) ⇒ Object
Returns an Array of objects referenced by any of the given HTML nodes.
-
#references_relation ⇒ Object
Returns the ActiveRecord::Relation to use for querying references in the DB.
-
#unique_attribute_values(nodes, attribute) ⇒ Object
Returns an Array containing all unique values of an attribute of the given nodes.
Constructor Details
#initialize(context) ⇒ BaseParser
context - An instance of Banzai::RenderContext.
59 60 61 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 59 def initialize(context) @context = context end |
Class Attribute Details
.reference_options ⇒ Object
Returns the value of attribute reference_options.
38 39 40 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 38 def end |
.reference_type ⇒ Object
Returns the value of attribute reference_type.
38 39 40 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 38 def reference_type @reference_type end |
Class Method Details
.data_attribute ⇒ Object
Returns the attribute name containing the value for every object to be parsed by the current parser.
For example, for a parser class that returns “Animal” objects this attribute would be “data-animal”.
46 47 48 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 46 def self.data_attribute @data_attribute ||= "data-#{reference_type.to_s.dasherize}" end |
.reference_class ⇒ Object
Returns a model class to use as a reference. By default, the method does not take namespaces into account, thus parser classes can customize the reference class to use a model name with a namespace
54 55 56 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 54 def self.reference_class reference_type.to_s.classify.constantize end |
Instance Method Details
#can?(user, permission, subject = :global) ⇒ Boolean
248 249 250 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 248 def can?(user, , subject = :global) Ability.allowed?(user, , subject) end |
#collection_cache_key(collection) ⇒ Object
Returns the cache key to use for a collection.
208 209 210 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 208 def collection_cache_key(collection) collection.respond_to?(:model) ? collection.model : collection end |
#collection_objects_for_ids(collection, ids) ⇒ Object
Queries the collection for the objects with the given IDs.
If the RequestStore module is enabled this method will only query any objects that have not yet been queried. For objects that have already been queried the object is returned from the cache.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 187 def collection_objects_for_ids(collection, ids) if Gitlab::SafeRequestStore.active? ids = ids.map(&:to_i).uniq cache = collection_cache[collection_cache_key(collection)] to_query = ids - cache.keys unless to_query.empty? collection.where(id: to_query).each { |row| cache[row.id] = row } end ids.each_with_object([]) do |id, array| row = cache[id] array << row if row end else collection.where(id: ids) end end |
#find_projects_for_hash_keys(hash) ⇒ Object
252 253 254 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 252 def find_projects_for_hash_keys(hash) collection_objects_for_ids(Project, hash.keys) end |
#gather_attributes_per_project(nodes, attribute) ⇒ Object
Returns a Hash containing attribute values per project ID.
The returned Hash uses the following format:
{ project id => [value1, value2, ...] }
nodes - An Array of HTML nodes to process. attribute - The name of the attribute (as a String) for which to gather
values.
Returns a Hash.
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 124 def gather_attributes_per_project(nodes, attribute) per_project = Hash.new { |hash, key| hash[key] = Set.new } nodes.each do |node| project_id = node.attr('data-project').to_i id = node.attr(attribute) per_project[project_id] << id if id end per_project end |
#gather_references(nodes, ids_only: false) ⇒ Object
Gathers the references for the given HTML nodes. Returns visible references and a list of nodes which are not visible to the user
227 228 229 230 231 232 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 227 def gather_references(nodes, ids_only: false) nodes = nodes_user_can_reference(current_user, nodes) visible = nodes_visible_to_user(current_user, nodes) { visible: referenced_by(visible, ids_only: ids_only), nodes: nodes, visible_nodes: visible } end |
#grouped_objects_for_nodes(nodes, collection, attribute) ⇒ Object
Returns a Hash containing objects for an attribute grouped per the nodes that reference them.
The returned Hash uses the following format:
{ node => row }
nodes - An Array of HTML nodes to process.
collection - The model or ActiveRecord relation to use for retrieving
rows from the database.
attribute - The name of the attribute containing the primary key values
for every row.
Returns a Hash.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 153 def grouped_objects_for_nodes(nodes, collection, attribute) return {} if nodes.empty? ids = unique_attribute_values(nodes, attribute) collection_objects = collection_objects_for_ids(collection, ids) objects_by_id = collection_objects.index_by(&:id) nodes.each_with_object({}) do |node, hash| if node.has_attribute?(attribute) obj = objects_by_id[node.attr(attribute).to_i] hash[node] = obj if obj end end end |
#groups_for_nodes(nodes) ⇒ Object
244 245 246 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 244 def groups_for_nodes(nodes) @groups_for_nodes ||= grouped_objects_for_nodes(nodes, Group, 'data-group') end |
#nodes_user_can_reference(user, nodes) ⇒ Object
Returns all the nodes containing references that the user can refer to.
68 69 70 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 68 def nodes_user_can_reference(user, nodes) nodes end |
#nodes_visible_to_user(user, nodes) ⇒ Object
Returns all the nodes that are visible to the given user.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 73 def nodes_visible_to_user(user, nodes) projects = lazy { projects_for_nodes(nodes) } groups = lazy { groups_for_nodes(nodes) } project_attr = 'data-project' group_attr = 'data-group' preload_associations(projects, user) preload_group_associations(groups, user) nodes.select do |node| if node.has_attribute?(project_attr) can_read_reference?(user, projects[node], node) elsif node.has_attribute?(group_attr) can_read_reference?(user, groups[node], node) else true end end end |
#process(documents, ids_only: false) ⇒ Object
Processes the list of HTML documents and returns an Array containing all the references.
214 215 216 217 218 219 220 221 222 223 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 214 def process(documents, ids_only: false) type = self.class.reference_type = self.class. nodes = documents.flat_map do |document| .css(document, "a[data-reference-type='#{type}'].gfm", ).to_a end gather_references(nodes, ids_only: ids_only) end |
#project_for_node(node) ⇒ Object
63 64 65 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 63 def project_for_node(node) context.project_for_node(node) end |
#projects_for_nodes(nodes) ⇒ Object
Returns a Hash containing the projects for a given list of HTML nodes.
The returned Hash uses the following format:
{ node => project }
240 241 242 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 240 def projects_for_nodes(nodes) @projects_for_nodes ||= grouped_objects_for_nodes(nodes, Project.includes(:project_feature), 'data-project') end |
#referenced_by(nodes, options = {}) ⇒ Object
Returns an Array of objects referenced by any of the given HTML nodes.
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 94 def referenced_by(nodes, = {}) ids = unique_attribute_values(nodes, self.class.data_attribute) return ids if .fetch(:ids_only, false) if ids.empty? references_relation.none else references_relation.where(id: ids) end end |
#references_relation ⇒ Object
Returns the ActiveRecord::Relation to use for querying references in the DB.
108 109 110 111 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 108 def references_relation raise NotImplementedError, "#{self.class} does not implement #{__method__}" end |
#unique_attribute_values(nodes, attribute) ⇒ Object
Returns an Array containing all unique values of an attribute of the given nodes.
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 170 def unique_attribute_values(nodes, attribute) values = Set.new nodes.each do |node| if node.has_attribute?(attribute) values << node.attr(attribute) end end values.to_a end |