module Fiona7 module JSON class ObjDecorator end end end require 'fiona7/assert' require 'fiona7/link_converter/fiona_to_scrivito' require 'fiona7/json/widget_decorator' require 'fiona7/widget_resolver' module Fiona7 module JSON class ObjDecorator 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.to_s], _obj_class: [@obj.obj_class.gsub("__", "::")], _last_changed: [@obj.last_changed.try(:to_iso)], _widget_pool: [{}] } if !@obj.edited? && !@obj.released? attrs[:_modification] = "new" elsif @obj.edited? && !@obj.released? attrs[:_modification] = "new" elsif @obj.edited? && @obj.released? attrs[:_modification] = "edited" end attrs[:_path] = [@obj.path] unless @obj.path =~ /^\/_orphaned/ attrs[:_permalink] = [@obj.permalink] if @obj.permalink.present? attrs end def add_custom_attributes(attrs, *args) type_definition = Fiona7::TypeRegister.instance.read_mangled(@obj.obj_class) type_definition.attrs.each do |attribute| virtual_attribute_name = attribute.name real_attribute_name = attribute.real_name virtual_attribute_type = attribute.type.to_sym val = case virtual_attribute_type when :link deserialize_link(@obj.attr_values[real_attribute_name].try(:first)) when :linklist (@obj.attr_values[real_attribute_name] || []).map {|link| deserialize_link(link) } when :multienum @obj[real_attribute_name] || [] when :reference deserialize_reference(@obj.attr_values[real_attribute_name].try(:first)) when :referencelist (@obj.attr_values[real_attribute_name] || []).map {|link| deserialize_reference(link) }.compact when :date @obj[real_attribute_name].try(:to_iso) when :widgetlist deserialize_widget_field(@obj.attr_values[real_attribute_name] || []) when :html deserialize_html(@obj[real_attribute_name]) when :binary if !Fiona7.mode == :legacy || !@obj.binary? deserialize_binary(@obj.attr_values[real_attribute_name].try(:first)) else {id: "%032d" % @obj.id.to_s} end when :enum, :multienum, :text, :string @obj[real_attribute_name] when :stringlist # TODO: get rid of this rescue nil ::JSON.parse(@obj[real_attribute_name]) rescue nil 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 deserialized = { # 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"].to_s, # rest api uses obj_id obj_id: link["destination"].to_s, query: link["search"], fragment: link["fragment"] } # TODO: refactor this code if deserialized[:url].present? deserialized.delete(:destination) deserialized.delete(:obj_id) end deserialized end end def deserialize_reference(link) if link && link["type"] == "internal" link["destination"].to_s end end def deserialize_widget_field(linklist) if !linklist.empty? widget_ids = [] widgets = linklist.map do |link| widget_id = link["title"] widget_ids << widget_id end widget_ids 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.attr_values["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