diff options
Diffstat (limited to 'lib/banzai/filter/inline_metrics_redactor_filter.rb')
-rw-r--r-- | lib/banzai/filter/inline_metrics_redactor_filter.rb | 89 |
1 files changed, 58 insertions, 31 deletions
diff --git a/lib/banzai/filter/inline_metrics_redactor_filter.rb b/lib/banzai/filter/inline_metrics_redactor_filter.rb index 4d8a5028898..e84ba83e03e 100644 --- a/lib/banzai/filter/inline_metrics_redactor_filter.rb +++ b/lib/banzai/filter/inline_metrics_redactor_filter.rb @@ -8,14 +8,17 @@ module Banzai include Gitlab::Utils::StrongMemoize METRICS_CSS_CLASS = '.js-render-metrics' + URL = Gitlab::Metrics::Dashboard::Url + + Embed = Struct.new(:project_path, :permission) # Finds all embeds based on the css class the FE # uses to identify the embedded content, removing # only unnecessary nodes. def call nodes.each do |node| - path = paths_by_node[node] - user_has_access = user_access_by_path[path] + embed = embeds_by_node[node] + user_has_access = user_access_by_embed[embed] node.remove unless user_has_access end @@ -30,40 +33,69 @@ module Banzai end # Returns all nodes which the FE will identify as - # a metrics dashboard placeholder element + # a metrics embed placeholder element # # @return [Nokogiri::XML::NodeSet] def nodes @nodes ||= doc.css(METRICS_CSS_CLASS) end - # Maps a node to the full path of a project. + # Maps a node to key properties of an embed. # Memoized so we only need to run the regex to get # the project full path from the url once per node. # - # @return [Hash<Nokogiri::XML::Node, String>] - def paths_by_node - strong_memoize(:paths_by_node) do - nodes.each_with_object({}) do |node, paths| - paths[node] = path_for_node(node) + # @return [Hash<Nokogiri::XML::Node, Embed>] + def embeds_by_node + strong_memoize(:embeds_by_node) do + nodes.each_with_object({}) do |node, embeds| + embed = Embed.new + url = node.attribute('data-dashboard-url').to_s + + set_path_and_permission(embed, url, URL.regex, :read_environment) + set_path_and_permission(embed, url, URL.grafana_regex, :read_project) unless embed.permission + + embeds[node] = embed if embed.permission end end end - # Gets a project's full_path from the dashboard url - # in the placeholder node. The FE will use the attr - # `data-dashboard-url`, so we want to check against that - # attribute directly in case a user has manually - # created a metrics element (rather than supporting - # an alternate attr in InlineMetricsFilter). + # Attempts to determine the path and permission attributes + # of a url based on expected dashboard url formats and + # sets the attributes on an Embed object # - # @return [String] - def path_for_node(node) - url = node.attribute('data-dashboard-url').to_s - - Gitlab::Metrics::Dashboard::Url.regex.match(url) do |m| + # @param embed [Embed] + # @param url [String] + # @param regex [RegExp] + # @param permission [Symbol] + def set_path_and_permission(embed, url, regex, permission) + return unless path = regex.match(url) do |m| "#{$~[:namespace]}/#{$~[:project]}" end + + embed.project_path = path + embed.permission = permission + end + + # Returns a mapping representing whether the current user + # has permission to view the embed for the project. + # Determined in a batch + # + # @return [Hash<Embed, Boolean>] + def user_access_by_embed + strong_memoize(:user_access_by_embed) do + unique_embeds.each_with_object({}) do |embed, access| + project = projects_by_path[embed.project_path] + + access[embed] = Ability.allowed?(user, embed.permission, project) + end + end + end + + # Returns a unique list of embeds + # + # @return [Array<Embed>] + def unique_embeds + embeds_by_node.values.uniq end # Maps a project's full path to a Project object. @@ -74,22 +106,17 @@ module Banzai def projects_by_path strong_memoize(:projects_by_path) do Project.eager_load(:route, namespace: [:route]) - .where_full_path_in(paths_by_node.values.uniq) + .where_full_path_in(unique_project_paths) .index_by(&:full_path) end end - # Returns a mapping representing whether the current user - # has permission to view the metrics for the project. - # Determined in a batch + # Returns a list of the full_paths of every project which + # has an embed in the doc # - # @return [Hash<Project, Boolean>] - def user_access_by_path - strong_memoize(:user_access_by_path) do - projects_by_path.each_with_object({}) do |(path, project), access| - access[path] = Ability.allowed?(user, :read_environment, project) - end - end + # @return [Array<String>] + def unique_project_paths + embeds_by_node.values.map(&:project_path).uniq end end end |