module Fiona7 module Builder class ObjBuilder end end end require 'fiona7/type_register' require 'fiona7/obj_class_name_mangler' require 'fiona7/obj_class_name_demangler' #require 'fiona7/write_obj' #require 'fiona7/released_obj' require 'fiona7/builder/batch_widget_writer' require 'fiona7/widget_resolver' require 'fiona7/prefetch/obj_prefetch' require 'fiona7/attribute_writers/factory' module Fiona7 module Builder class ObjBuilder def initialize(values) @values = values.symbolize_keys # garbage @values.delete(:_modification) # revert command sends this info. which is silly. @values.delete(:_last_changed) end def build assert_valid prepare_object write_widget_pool store_attributes @obj end def validate true end protected def update? false end def assert_valid validate || (raise Scrivito::ClientError.new(@error_msg || "Invalid input", 422)) end def prepare_object @path = @values.delete(:_path) || generate_orphaned_path @obj_class = @values.delete(:_obj_class) @real_obj_class = Fiona7::ObjClassNameMangler.new(@obj_class).mangle @widget_pool = @values.delete(:_widget_pool) @permalink = @values.delete(:_permalink) @path = "/#{@path}" unless @path.start_with?('/') @name, parent_path = name_and_parent_path_from_path(@path) @parent = ensure_parent_exists(parent_path) if parent_path ensure_obj_class_exists @obj = WriteObj.create!(name: @name, parent_obj_id: @parent.id, obj_class: @real_obj_class) end def write_widget_pool resolver = WidgetResolver.new(@obj.attr_values["X_widget_pool"]||[], Prefetch::ObjPrefetch.new(WriteObj)) @id_map = resolver.id_map @widget_path_map = resolver.path_map if @widget_pool && !@widget_pool.empty? @new_full_text = rewrite_full_text @widgets = BatchWidgetWriter.new(@obj, @id_map, @widget_pool, @widget_path_map) @widgets.write # FIXME: refactor this code if @widgets.pool_changed? # after widget writing this either has new widgets # or some widgets have been removed @new_widget_pool = @widget_pool.map do |widget_id, definition| # widget deleted next if definition.nil? {title: widget_id, destination_object: @widget_path_map[widget_id]} end.compact # newly added widgets @widget_path_map.each do |widget_id, path| next if !@widget_pool[widget_id].nil? @new_widget_pool << {title: widget_id, destination_object: path} end end end end def store_attributes if @obj.obj_class != @real_obj_class @obj.obj_class = @real_obj_class @obj.save! @obj.reload end @obj.send(:reload_attributes) factory = Fiona7::AttributeWriters::Factory.new(@obj, @obj_class, WriteObj, @widget_path_map) @values.each do |attribute_name, possible_pair| (claimed_type, value) = *possible_pair worker = factory.call(attribute_name) worker.call(value, claimed_type) end if (@new_full_text) @obj.set(:X_full_text, @new_full_text) end @obj.set(:X_widget_pool, @new_widget_pool) if @new_widget_pool @obj.set(:permalink, @permalink) if @permalink @obj.save! #if !@values.empty? || !@new_widget_pool.nil? @obj.edit! unless @obj.really_edited? #end end def rewrite_full_text full_text = ::YAML.load(@obj.attr_values["X_full_text"]) rescue {} full_text = {} unless full_text.kind_of?(Hash) full_text["_widget_pool"] ||= {} full_text["_widget_pool"].deep_merge!(@widget_pool) full_text.to_yaml rescue => e Rails.logger.error("Unable to store information for search engine: #{e.message}") nil end def name_and_parent_path_from_path(path) components = path.split('/') name = components.pop.presence parent_path= components.join('/').presence || '/' return name, parent_path end def ensure_parent_exists(path) remaining = path.split("/") current = [] paths = [] original = path while !remaining.empty? current.push(remaining.shift) path = current.join('/').presence || '/' paths.push(path) end paths.each do |path| if !WriteObj.exists?(path: path) name, parent_path = name_and_parent_path_from_path(path) WriteObj.create!(name: name, parent_obj_id: WriteObj.find_by_path(parent_path).id, obj_class: 'X_Container') end end WriteObj.find_by_path(original) || (raise "Tried to make sure that the parent under '#{original}' exist, but it does not :(") end def generate_orphaned_path return nil if update? "_orphaned/#{SecureRandom.hex(16)}" end def ensure_obj_class_exists values = @values.with_indifferent_access obj_class = @obj_class Fiona7::TypeRegister.instance.ad_hoc_synchronize( Fiona7::TypeRegister::AdHocTypeDefinition.new(values, obj_class).type_definition ) end end end end