module Scrivito class AttributeSerializer def serialize(attributes, attribute_definitions) return attributes if attributes.blank? serialized_attributes = attributes.map do |attribute_name, attribute_value| serialize_attribute(attribute_name, attribute_value, attribute_definitions) end Hash[serialized_attributes] end private def serialize_attribute(attribute_name, attribute_value, attribute_definitions) attribute_name = attribute_name.to_s if attribute_name.starts_with?('_') serialize_system_attribute(attribute_name, attribute_value) else attribute_definition = attribute_definitions[attribute_name] serialize_custom_attribute(attribute_name, attribute_value, attribute_definition) end end def serialize_system_attribute(attribute_name, attribute_value) if %w[ _id _obj_class _path _permalink ].include?(attribute_name) [attribute_name, attribute_value.to_s] else raise ScrivitoError, "Unknown attribute '#{attribute_name}'" end end def serialize_custom_attribute(attribute_name, attribute_value, attribute_definition) raise ScrivitoError, "Unknown attribute '#{attribute_name}'" unless attribute_definition attribute_value = case attribute_type = attribute_definition.type when 'binary' then serialize_binary_value(attribute_value, attribute_definition) when 'date' then serialize_date_value(attribute_value, attribute_definition) when 'enum' then serialize_enum_value(attribute_value, attribute_definition) when 'html' then serialize_html_value(attribute_value) when 'link' then serialize_link_value(attribute_value, attribute_definition) when 'linklist' then serialize_linklist_value(attribute_value, attribute_definition) when 'multienum' then serialize_multienum_value(attribute_value, attribute_definition) when 'reference' then serialize_reference_value(attribute_value) when 'referencelist' then serialize_referencelist_value(attribute_value, attribute_definition) when 'string' then serialize_string_value(attribute_value) when 'stringlist' then serialize_stringlist_value(attribute_value, attribute_definition) when 'widget' then serialize_widget_value(attribute_value, attribute_definition) when 'widgetlist' then serialize_widgetlist_value(attribute_value, attribute_definition) end [attribute_name, [serialize_attribute_type(attribute_type), attribute_value]] end def serialize_attribute_type(attribute_type) case attribute_type when 'enum' then 'string' when 'multienum' then 'stringlist' else attribute_type end end def serialize_binary_value(attribute_value, attribute_definition) return unless attribute_value case attribute_value when File then CmsRestApi.upload_file(attribute_value) when UploadedBinary then attribute_value.params else raise_validation_error(attribute_definition.name, 'an instance of File, Scrivito::UploadedBinary or nil', attribute_value) end end def serialize_date_value(attribute_value, attribute_definition) return unless attribute_value attribute_value = DateAttribute.serialize(attribute_value) unless attribute_value raise_validation_error(attribute_definition.name, 'an instance of Date or Time', attribute_value) end attribute_value end def serialize_enum_value(attribute_value, attribute_definition) return unless attribute_value attribute_value = attribute_value.to_s attribute_values = attribute_definition.values if attribute_values.include?(attribute_value) attribute_value else raise_validation_error(attribute_definition.name, format_array(attribute_values), attribute_value) end end def serialize_html_value(attribute_value) attribute_value.to_s end def serialize_link_value(attribute_value, attribute_definition) return unless attribute_value if attribute_value.is_a?(Link) attribute_value.to_cms_api_linklist_params else raise_validation_error(attribute_definition.name, 'an instance of Scrivito::Link', attribute_value) end end def serialize_linklist_value(attribute_value, attribute_definition) if attribute_value.is_a?(Enumerable) && attribute_value.all? { |item| item.is_a?(Link) } attribute_value.map(&:to_cms_api_linklist_params) else raise_validation_error(attribute_definition.name, 'Enumerable containing instances of Scrivito::Link', attribute_value) end end def serialize_multienum_value(attribute_value, attribute_definition) attribute_value = attribute_value.map(&:to_s) attribute_values = attribute_definition.values forbidden_values = attribute_value - attribute_values if forbidden_values.any? raise_validation_error(attribute_definition.name, format_array(attribute_values), attribute_value) end attribute_value end def serialize_reference_value(attribute_value) return unless attribute_value attribute_value.is_a?(BasicObj) ? attribute_value.id : attribute_value.to_s end def serialize_referencelist_value(attribute_value, attribute_definition) if attribute_value.is_a?(Enumerable) attribute_value.map(&method(:serialize_reference_value)) else raise_validation_error(attribute_definition.name, 'Enumerable containing instances of String or Scrivito::BasicWidget', attribute_value) end end def serialize_string_value(attribute_value) attribute_value.to_s end def serialize_stringlist_value(attribute_value, attribute_definition) if attribute_value.is_a?(Enumerable) attrubute_value.map(&:to_s) else raise_validation_error(attribute_definition.name, 'Enumerable containing instances of String', attribute_value) end end def serialize_widget_value(attribute_value, attribute_definition) return unless attribute_value if attribute_value.is_a?(BasicWidget) attribute_value.id else raise_validation_error(attribute_definition.name, 'an instance of Scrivito::BasicWidget', attribute_value) end end def serialize_widgetlist_value(attribute_value, attribute_definition) if attribute_value.is_a?(Enumerable) && attribute_value.all? { |item| item.is_a?(BasicWidget) } attribute_value.map(&:id) else raise_validation_error(attribute_definition.name, 'Enumerable containing instances of Scrivito::BasicWidget', attribute_value) end end def raise_validation_error(attribute_name, expected_value, actual_value) error_message = "Unexpected value #{actual_value.inspect} for attribute '#{attribute_name}'."\ " Expected: #{expected_value}." raise ClientError.new(error_message, 412) end def format_array(values) values.map(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ' or ') end end end