# frozen_string_literal: true # This service passes Markdown content through our GFM rewriter classes # which rewrite references to GitLab objects and uploads within the content # based on their visibility by the `target_parent`. class MarkdownContentRewriterService include Gitlab::Utils::StrongMemoize REWRITERS = [Gitlab::Gfm::ReferenceRewriter, Gitlab::Gfm::UploadsRewriter].freeze def initialize(current_user, object, field, source_parent, target_parent) @current_user = current_user @source_parent = source_parent @target_parent = target_parent @object = object @field = field validate_parameters! @content = object[field].dup.presence @html_field = object.cached_markdown_fields.html_field(field) @content_html = object.cached_html_for(field) @rewriters = REWRITERS.map do |rewriter_class| rewriter_class.new(@content, content_html, source_parent, current_user) end @result = { field => nil, html_field => nil }.with_indifferent_access end def execute return result unless content unless safe_to_copy_markdown? rewriters.each do |rewriter| rewriter.rewrite(target_parent) end end result[field] = content result[html_field] = content_html if safe_to_copy_markdown? result[:skip_markdown_cache_validation] = safe_to_copy_markdown? result end def safe_to_copy_markdown? strong_memoize(:safe_to_copy_markdown) do rewriters.none?(&:needs_rewrite?) end end private def validate_parameters! # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39654#note_399095117 raise ArgumentError, 'The rewriter classes require that `source_parent` is a `Project`' \ unless source_parent.is_a?(Project) if object.cached_markdown_fields[field].nil? raise ArgumentError, 'The `field` attribute does not contain cached markdown' end end attr_reader :current_user, :content, :source_parent, :target_parent, :rewriters, :content_html, :field, :html_field, :object, :result end