BigW Consortium Gitlab

redactor.rb 2.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
module Banzai
  # Class for removing Markdown references a certain user is not allowed to
  # view.
  class Redactor
    attr_reader :user, :project

    # project - A Project to use for redacting links.
    # user - The currently logged in user (if any).
    def initialize(project, user = nil)
      @project = project
      @user = user
    end

    # Redacts the references in the given Array of documents.
    #
    # This method modifies the given documents in-place.
    #
    # documents - A list of HTML documents containing references to redact.
    #
    # Returns the documents passed as the first argument.
    def redact(documents)
22
      all_document_nodes = document_nodes(documents)
23

24
      redact_document_nodes(all_document_nodes)
25 26
    end

27
    # Redacts the given node documents
28
    #
29 30 31 32 33
    # data - An Array of a Hashes mapping an HTML document to nodes to redact.
    def redact_document_nodes(all_document_nodes)
      all_nodes = all_document_nodes.map { |x| x[:nodes] }.flatten
      visible = nodes_visible_to_user(all_nodes)
      metadata = []
34

35 36 37 38 39 40 41 42 43
      all_document_nodes.each do |entry|
        nodes_for_document = entry[:nodes]
        doc_data = { document: entry[:document], visible_reference_count: nodes_for_document.count }
        metadata << doc_data

        nodes_for_document.each do |node|
          next if visible.include?(node)

          doc_data[:visible_reference_count] -= 1
44 45 46 47
          # The reference should be replaced by the original link's content,
          # which is not always the same as the rendered one.
          content = node.attr('data-original') || node.inner_html
          node.replace(content)
48 49
        end
      end
50 51

      metadata
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    end

    # Returns the nodes visible to the current user.
    #
    # nodes - The input nodes to check.
    #
    # Returns a new Array containing the visible nodes.
    def nodes_visible_to_user(nodes)
      per_type = Hash.new { |h, k| h[k] = [] }
      visible = Set.new

      nodes.each do |node|
        per_type[node.attr('data-reference-type')] << node
      end

      per_type.each do |type, nodes|
        parser = Banzai::ReferenceParser[type].new(project, user)

        visible.merge(parser.nodes_visible_to_user(user, nodes))
      end

      visible
    end
75 76 77 78 79 80

    def document_nodes(documents)
      documents.map do |document|
        { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') }
      end
    end
81 82
  end
end