lib/cloud_controller/rest_controller/object_renderer.rb
require 'addressable/uri'
module VCAP::CloudController::RestController
class ObjectRenderer
attr_reader :object_transformer
def initialize(eager_loader, serializer, opts)
@eager_loader = eager_loader
@serializer = serializer
@max_inline_relations_depth = opts.fetch(:max_inline_relations_depth)
@default_inline_relations_depth = 0
@object_transformer = opts[:object_transformer]
end
# Render an object to json, using export and security properties
# set by its controller.
#
# @param [RestController] controller Controller for the object being
# encoded.
#
# @param [Sequel::Model] obj Object to encode.
#
# @option opts [Integer] :inline_relations_depth Depth to recursively
# expand relationships in addition to providing the URLs.
#
# @option opts [Integer] :max_inline Maximum number of objects to
# expand inline in a relationship.
def render_json(controller, obj, opts)
inline_relations_depth = opts[:inline_relations_depth] || @default_inline_relations_depth
if inline_relations_depth > @max_inline_relations_depth
raise CloudController::Errors::ApiError.new_from_details('BadQueryParameter',
"inline_relations_depth must be <= #{@max_inline_relations_depth}")
end
eager_loaded_objects = @eager_loader.eager_load_dataset(
obj.model.dataset,
controller,
opts[:default_visibility_filter] || default_visibility_filter,
opts[:additional_visibility_filters] || {},
inline_relations_depth
)
eager_loaded_object = eager_loaded_objects.where(id: obj.id).all.first
transform_opts = opts[:transform_opts] || {}
object_transformer.transform(eager_loaded_object, transform_opts) if object_transformer
# The class of object and eager_loaded_object could be different
# if they are part of STI. Attributes exported by the object
# are the ones that are expected in the response.
# (e.g. Domain vs SharedDomain < Domain)
export_attributes = eager_loaded_object.export_attrs
if obj.respond_to? :transient_attrs
obj.transient_attrs.each { |attr| eager_loaded_object.send("#{attr}=", obj.send(attr)) }
export_attributes += obj.transient_attrs
end
hash = @serializer.serialize(
controller,
eager_loaded_object,
opts.merge(export_attrs: export_attributes)
)
Oj.dump(hash, mode: :compat)
end
def render_json_with_read_privileges(controller, obj, opts)
render_json(controller, obj, opts.merge(default_visibility_filter: default_visibility_filter_with_read_privileges))
end
private
def default_visibility_filter
access_context = VCAP::CloudController::Security::AccessContext.new
proc { |ds| ds.filter(ds.model.user_visibility(access_context.user, access_context.admin_override)) }
end
def default_visibility_filter_with_read_privileges
access_context = VCAP::CloudController::Security::AccessContext.new
proc { |ds| ds.filter(ds.model.user_visibility_for_read(access_context.user, access_context.admin_override)) }
end
end
end