module Fiona7 module JSON class ObjDecorator end end end require 'fiona7/assert' require 'fiona7/type_register_mixin' require 'fiona7/link_converter/fiona_to_scrivito' require 'fiona7/json/widget_decorator' require 'fiona7/widget_resolver' module Fiona7 module JSON class ObjDecorator include TypeRegisterMixin def initialize(klass, obj) @klass = klass @obj = obj @link_converter = LinkConverter::FionaToScrivito.new(obj) end def as_json(*args) attrs = standard_attrs add_custom_attributes(attrs, *args) replace_widget_pool(attrs, *args) attrs end protected def standard_attrs attrs = { _id: [@obj.id], _path: [@obj.path], _obj_class: [@obj.obj_class], _last_changed: [@obj.last_changed.try(:to_iso)], _widget_pool: [{}] } attrs[:_permalink] = [@obj.permalink] if @obj.permalink.present? attrs end def add_custom_attributes(attrs, *args) type_register.annotated_attributes(@obj.obj_class).each do |attribute| virtual_attribute_name = attribute.virtual_name real_attribute_name = attribute.real_name virtual_attribute_type = attribute.virtual_type val = case virtual_attribute_type when :link deserialize_link(@obj[real_attribute_name].try(:first)) when :linklist (@obj[real_attribute_name] || []).map {|link| deserialize_link(link) } when :multienum @obj[real_attribute_name] || [] when :reference deserialize_reference(@obj[real_attribute_name].try(:first)) when :referencelist (@obj[real_attribute_name] || []).map {|link| deserialize_reference(link) }.compact when :date @obj[real_attribute_name].try(:to_iso) when :widget deserialize_widget_field(@obj[real_attribute_name] || []) when :html deserialize_html(@obj[real_attribute_name]) when :binary deserialize_binary(@obj[real_attribute_name].try(:first)) when :enum, :multienum, :text, :string @obj[real_attribute_name] else Assert.success( false, "Unknown attribute type #{virtual_attribute_type} for attribute: #{virtual_attribute_name}" ) end attrs[virtual_attribute_name] = [val, virtual_attribute_type] end end def deserialize_link(link) if link { # remove possible external prefix for protcol-less urls url: link.url.try(:gsub, /\Aexternal:/, ''), title: link.title, target: link.target, # content service uses destination destination: link.destination_object_id, # rest api uses obj_id obj_id: link.destination_object_id, query: link.query, fragment: link.fragment } end end def deserialize_reference(link) if link && link.internal? link.destination_object_id end end def deserialize_widget_field(linklist) if !linklist.empty? widgets = linklist.map do |link| widget_id = link.title {widget: widget_id} end {list: widgets} end end def deserialize_html(html) @link_converter.convert(html) end def deserialize_binary(link) if link binary_id = link.title if binary_id.length == 32 && binary_id =~ /0{16,}0*[0-9]+/ {id: binary_id} end end end def replace_widget_pool(attrs, *args) if (widget_links = @obj[:X_widget_pool]) resolver = WidgetResolver.new(widget_links, @klass) Assert.success( resolver.instance_map.all? {|_, instance| !instance.nil?}, "Widget structure in object #{@obj.id} is broken, a widget could not be found" ) result = Hash[ resolver.instance_map.map {|widget_id, widget| [widget_id, WidgetDecorator.new(@klass, widget).as_json(*args)] } ] attrs[:_widget_pool] = [result] end end end end end