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
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.
-
#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 @reference_options 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
240 241 242 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 240 def can?(user, , subject = :global) Ability.allowed?(user, , subject) end |
#collection_cache_key(collection) ⇒ Object
Returns the cache key to use for a collection.
203 204 205 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 203 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.
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 182 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
244 245 246 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 244 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.
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 119 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
222 223 224 225 226 227 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 222 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.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 148 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 |
#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 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 73 def nodes_visible_to_user(user, nodes) projects = lazy { projects_for_nodes(nodes) } project_attr = 'data-project' preload_associations(projects, user) nodes.select do |node| if node.has_attribute?(project_attr) can_read_reference?(user, projects[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.
209 210 211 212 213 214 215 216 217 218 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 209 def process(documents, ids_only: false) type = self.class.reference_type = self.class. nodes = documents.flat_map do |document| Querying.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 }
235 236 237 238 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 235 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.
89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 89 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.
103 104 105 106 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 103 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.
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/banzai/reference_parser/base_parser.rb', line 165 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 |