summaryrefslogtreecommitdiff
path: root/lib/banzai/object_renderer.rb
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2018-04-03 15:45:17 +0200
committerYorick Peterse <yorickpeterse@gmail.com>2018-04-11 14:10:19 +0200
commitdaad7144ec7c0173439eeadd61590442e40a6051 (patch)
tree80a738c17196d0235cbc4c5589d6b04f96688b5c /lib/banzai/object_renderer.rb
parent23fb465c75d00fd7156a540b7421a79e22df3966 (diff)
downloadgitlab-ce-daad7144ec7c0173439eeadd61590442e40a6051.tar.gz
Support Markdown rendering using multiple projectsrendering-markdown-multiple-projects
This refactors the Markdown pipeline so it supports the rendering of multiple documents that may belong to different projects. An example of where this happens is when displaying the event feed of a group. In this case we retrieve events for all projects in the group. Previously we would group events per project and render these chunks separately, but this would result in many SQL queries being executed. By extending the Markdown pipeline to support this out of the box we can drastically reduce the number of SQL queries. To achieve this we introduce a new object to the pipeline: Banzai::RenderContext. This object simply wraps two other objects: an optional Project instance, and an optional User instance. On its own this wouldn't be very helpful, but a RenderContext can also be used to associate HTML documents with specific Project instances. This work is done in Banzai::ObjectRenderer and allows us to reuse as many queries (and results) as possible.
Diffstat (limited to 'lib/banzai/object_renderer.rb')
-rw-r--r--lib/banzai/object_renderer.rb32
1 files changed, 18 insertions, 14 deletions
diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb
index 2691be81623..a176f1e261b 100644
--- a/lib/banzai/object_renderer.rb
+++ b/lib/banzai/object_renderer.rb
@@ -13,14 +13,13 @@ module Banzai
# As an example, rendering the attribute `note` would place the unredacted
# HTML into `note_html` and the redacted HTML into `redacted_note_html`.
class ObjectRenderer
- attr_reader :project, :user
+ attr_reader :context
- # project - A Project to use for redacting Markdown.
+ # default_project - A default Project to use for redacting Markdown.
# user - The user viewing the Markdown/HTML documents, if any.
# redaction_context - A Hash containing extra attributes to use during redaction
- def initialize(project, user = nil, redaction_context = {})
- @project = project
- @user = user
+ def initialize(default_project: nil, user: nil, redaction_context: {})
+ @context = RenderContext.new(default_project, user)
@redaction_context = base_context.merge(redaction_context)
end
@@ -48,17 +47,21 @@ module Banzai
pipeline = HTML::Pipeline.new([])
objects.map do |object|
- pipeline.to_document(Banzai.render_field(object, attribute))
+ document = pipeline.to_document(Banzai.render_field(object, attribute))
+
+ context.associate_document(document, object)
+
+ document
end
end
def post_process_documents(documents, objects, attribute)
# Called here to populate cache, refer to IssuableExtractor docs
- IssuableExtractor.new(project, user).extract(documents)
+ IssuableExtractor.new(context).extract(documents)
documents.zip(objects).map do |document, object|
- context = context_for(object, attribute)
- Banzai::Pipeline[:post_process].to_document(document, context)
+ pipeline_context = context_for(document, object, attribute)
+ Banzai::Pipeline[:post_process].to_document(document, pipeline_context)
end
end
@@ -66,20 +69,21 @@ module Banzai
#
# Returns an Array containing the redacted documents.
def redact_documents(documents)
- redactor = Redactor.new(project, user)
+ redactor = Redactor.new(context)
redactor.redact(documents)
end
# Returns a Banzai context for the given object and attribute.
- def context_for(object, attribute)
- @redaction_context.merge(object.banzai_render_context(attribute))
+ def context_for(document, object, attribute)
+ @redaction_context.merge(object.banzai_render_context(attribute)).merge(
+ project: context.project_for_node(document)
+ )
end
def base_context
{
- current_user: user,
- project: project,
+ current_user: context.current_user,
skip_redaction: true
}
end