PageRenderTime 110ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/locomotive/import/content_types.rb

https://github.com/Epictetus/engine
Ruby | 243 lines | 165 code | 74 blank | 4 comment | 29 complexity | 1e22a28a96c3c3b35ee45ac8accfd4f4 MD5 | raw file
  1. require 'ostruct'
  2. module Locomotive
  3. module Import
  4. class ContentTypes < Base
  5. def process
  6. return if content_types.nil?
  7. contents_with_associations, content_types_with_associations = [], []
  8. content_types.each do |name, attributes|
  9. self.log "[content_types] slug = #{attributes['slug']}"
  10. content_type = site.content_types.where(:slug => attributes['slug']).first
  11. content_type_name = attributes['name'] || name
  12. if content_type.nil?
  13. content_type = self.build_content_type(attributes.merge(:name => content_type_name))
  14. else
  15. self.update_attributes(content_type, attributes.merge(:name => content_type_name))
  16. end
  17. self.add_or_update_fields(content_type, attributes['fields'])
  18. if content_type.content_custom_fields.any? { |f| ['has_many', 'has_one'].include?(f.kind) }
  19. content_types_with_associations << content_type
  20. end
  21. self.set_highlighted_field_name(content_type)
  22. self.set_order_by_value(content_type)
  23. self.set_group_by_value(content_type)
  24. if options[:samples] && attributes['contents']
  25. contents_with_associations += self.insert_samples(content_type, attributes['contents'])
  26. end
  27. content_type.save!
  28. end
  29. # look up for associations and replace their target field by the real class name
  30. self.replace_target(content_types_with_associations)
  31. # update all the contents with associations now that every content is stored in mongodb
  32. self.insert_samples_with_associations(contents_with_associations)
  33. # invalidate the cache of the dynamic classes (custom fields)
  34. site.content_types.all.collect { |c| c.invalidate_content_klass; c.fetch_content_klass }
  35. end
  36. protected
  37. def content_types
  38. database['site']['content_types']
  39. end
  40. def cleanse_attributes(data)
  41. attributes = { :group_by_field_name => data.delete('group_by') }.merge(data)
  42. attributes.delete_if { |name, value| %w{fields contents}.include?(name) }
  43. attributes
  44. end
  45. def build_content_type(data)
  46. attributes = cleanse_attributes(data)
  47. site.content_types.build(attributes)
  48. end
  49. def update_attributes(content_type, data)
  50. attributes = cleanse_attributes(data)
  51. content_type.update_attributes!(attributes)
  52. end
  53. def add_or_update_fields(content_type, fields)
  54. fields.each_with_index do |data, position|
  55. name, data = data.keys.first, data.values.first
  56. reverse_lookup = data.delete('reverse')
  57. attributes = { :_alias => name, :label => name.humanize, :kind => 'string', :position => position }.merge(data).symbolize_keys
  58. field = content_type.content_custom_fields.detect { |f| f._alias == attributes[:_alias] }
  59. field ||= content_type.content_custom_fields.build(attributes)
  60. field.send(:set_unique_name!) if field.new_record?
  61. field.attributes = attributes
  62. field[:kind] = field[:kind].downcase # old versions of the kind field are capitalized
  63. field[:tmp_reverse_lookup] = reverse_lookup # use the ability in mongoid to set free attributes on the fly
  64. end
  65. end
  66. def replace_target(content_types)
  67. content_types.each do |content_type|
  68. content_type.content_custom_fields.each do |field|
  69. next unless ['has_many', 'has_one'].include?(field.kind)
  70. target_content_type = site.content_types.where(:slug => field.target).first
  71. if target_content_type
  72. field.target = target_content_type.content_klass.to_s
  73. if field[:tmp_reverse_lookup]
  74. field.reverse_lookup = field[:tmp_reverse_lookup]
  75. field.reverse_lookup = field.safe_reverse_lookup # make sure we store the true value
  76. end
  77. end
  78. end
  79. content_type.save
  80. end
  81. end
  82. def insert_samples(content_type, contents)
  83. contents_with_associations = []
  84. contents.each_with_index do |data, position|
  85. value, attributes = data.is_a?(Array) ? [data.first, data.last] : [data.keys.first, data.values.first]
  86. associations = []
  87. # build with default attributes
  88. content = content_type.contents.where(content_type.highlighted_field_name.to_sym => value).first
  89. if content.nil?
  90. content = content_type.contents.build(content_type.highlighted_field_name.to_sym => value, :_position_in_list => position)
  91. end
  92. %w(_permalink seo_title meta_description meta_keywords).each do |attribute|
  93. new_value = attributes.delete(attribute)
  94. next if new_value.blank?
  95. content.send("#{attribute}=".to_sym, new_value)
  96. end
  97. attributes.each do |name, value|
  98. field = content_type.content_custom_fields.detect { |f| f._alias == name }
  99. next if field.nil? # the attribute name is not related to a field (name misspelled ?)
  100. kind = field.kind
  101. if ['has_many', 'has_one'].include?(kind)
  102. associations << OpenStruct.new(:name => name, :kind => kind, :value => value, :target => field.target)
  103. next
  104. end
  105. value = (case kind
  106. when 'file' then self.open_sample_asset(value)
  107. when 'boolean' then Boolean.set(value)
  108. when 'date' then value.is_a?(Date) ? value : Date.parse(value)
  109. when 'category'
  110. if field.category_items.detect { |item| item.name == value }.nil?
  111. field.category_items.build :name => value
  112. end
  113. value
  114. else # string, text
  115. value
  116. end)
  117. content.send("#{name}=", value)
  118. end
  119. content.send(:set_slug)
  120. content.save(:validate => false)
  121. contents_with_associations << [content, associations] unless associations.empty?
  122. self.log "insert content '#{content.send(content_type.highlighted_field_name.to_sym)}'"
  123. end
  124. contents_with_associations
  125. end
  126. def insert_samples_with_associations(contents)
  127. contents.each do |content_information|
  128. next if content_information.empty?
  129. content, associations = content_information
  130. content = content._parent.reload.contents.find(content._id) # target should be updated
  131. associations.each do |association|
  132. target_content_type = site.content_types.where(:name => association.target).first
  133. next if target_content_type.nil?
  134. value = (case association.kind
  135. when 'has_one' then
  136. target_content_type.contents.detect { |c| c.highlighted_field_value == association.value }
  137. when 'has_many' then
  138. association.value.collect do |v|
  139. target_content_type.contents.detect { |c| c.highlighted_field_value == v }._id
  140. end
  141. end)
  142. content.send("#{association.name}=", value)
  143. end
  144. content.save
  145. end
  146. end
  147. def set_highlighted_field_name(content_type)
  148. field = content_type.content_custom_fields.detect { |f| f._alias == content_type.highlighted_field_name }
  149. content_type.highlighted_field_name = field._name if field
  150. end
  151. def set_order_by_value(content_type)
  152. self.log "order by #{content_type.order_by}"
  153. order_by = (case content_type.order_by
  154. when 'manually', '_position_in_list' then '_position_in_list'
  155. when 'default', 'created_at' then 'created_at'
  156. else
  157. content_type.content_custom_fields.detect { |f| f._alias == content_type.order_by }._name rescue nil
  158. end)
  159. self.log "order by (after) #{order_by}"
  160. content_type.order_by = order_by || '_position_in_list'
  161. end
  162. def set_group_by_value(content_type)
  163. return if content_type.group_by_field_name.blank?
  164. field = content_type.content_custom_fields.detect { |f| f._alias == content_type.group_by_field_name }
  165. content_type.group_by_field_name = field._name if field
  166. end
  167. end
  168. end
  169. end