add rspec tests for the import module + debug the cms to handle correctly the default theme
This commit is contained in:
parent
680a42b8f5
commit
cc0b50e22e
1
Gemfile
1
Gemfile
@ -10,6 +10,7 @@ gem 'devise', '= 1.1.3'
|
|||||||
gem 'mongoid', '2.0.0.beta.19'
|
gem 'mongoid', '2.0.0.beta.19'
|
||||||
gem 'bson_ext', '1.1.1'
|
gem 'bson_ext', '1.1.1'
|
||||||
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.1', :require => 'mongoid_acts_as_tree'
|
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.1', :require => 'mongoid_acts_as_tree'
|
||||||
|
gem 'will_paginate'
|
||||||
|
|
||||||
gem 'haml', '= 3.0.18'
|
gem 'haml', '= 3.0.18'
|
||||||
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
||||||
|
@ -266,3 +266,4 @@ DEPENDENCIES
|
|||||||
rubyzip
|
rubyzip
|
||||||
spork
|
spork
|
||||||
warden
|
warden
|
||||||
|
will_paginate
|
||||||
|
@ -13,8 +13,17 @@ module Admin
|
|||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @content.save
|
if @content.save
|
||||||
format.json { render :json => { :content => @content } }
|
format.json { render :json => { :content => @content } }
|
||||||
|
format.html do
|
||||||
|
flash[@content_type.slug.singularize] = @content.aliased_attributes
|
||||||
|
redirect_to params[:success_callback]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
format.json { render :json => { :content => @content, :errors => @content.errors } }
|
format.json { render :json => { :content => @content, :errors => @content.errors } }
|
||||||
|
format.html do
|
||||||
|
flash[@content_type.slug.singularize] = @content.aliased_attributes
|
||||||
|
flash[:errors] = content.errors
|
||||||
|
redirect_to params[:error_callback]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,11 +42,12 @@ module Admin
|
|||||||
@site.save
|
@site.save
|
||||||
|
|
||||||
if @site.valid?
|
if @site.valid?
|
||||||
# begin
|
begin
|
||||||
job = Locomotive::Import::Job.new(params[:zipfile], @site)
|
job = Locomotive::Import::Job.new(params[:zipfile], @site, { :samples => true })
|
||||||
Delayed::Job.enqueue job, { :site => @site, :job_type => 'import' }
|
Delayed::Job.enqueue job, { :site => @site, :job_type => 'import' }
|
||||||
# rescue;
|
rescue Exception => e
|
||||||
# end # not a big deal if it did not work
|
logger.error "Import failed because of #{e.message}"
|
||||||
|
end
|
||||||
|
|
||||||
redirect_to admin_session_url(:host => Site.first.domains.first, :port => request.port)
|
redirect_to admin_session_url(:host => Site.first.domains.first, :port => request.port)
|
||||||
else
|
else
|
||||||
|
@ -38,6 +38,20 @@ class ContentInstance
|
|||||||
self._visible || self._visible.nil?
|
self._visible || self._visible.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def aliased_attributes # TODO: move it to the custom_fields gem
|
||||||
|
hash = { :created_at => self.created_at, :updated_at => self.updated_at }
|
||||||
|
|
||||||
|
self.custom_fields.each do |field|
|
||||||
|
case field.kind
|
||||||
|
when 'file' then hash[field._alias] = self.send(field._name.to_sym).url
|
||||||
|
else
|
||||||
|
hash[field._alias] = self.send(field._name.to_sym)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
def to_liquid
|
def to_liquid
|
||||||
Locomotive::Liquid::Drops::Content.new(self)
|
Locomotive::Liquid::Drops::Content.new(self)
|
||||||
end
|
end
|
||||||
|
@ -62,7 +62,16 @@ class ContentType
|
|||||||
(if conditions.nil? || conditions.empty?
|
(if conditions.nil? || conditions.empty?
|
||||||
self.contents
|
self.contents
|
||||||
else
|
else
|
||||||
self.contents.where(conditions)
|
conditions_with_names = {}
|
||||||
|
|
||||||
|
conditions.each do |key, value|
|
||||||
|
# convert alias (key) to name
|
||||||
|
field = self.content_custom_fields.detect { |f| f._alias == key }
|
||||||
|
|
||||||
|
conditions_with_names[field._name.to_sym] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
self.contents.where(conditions_with_names)
|
||||||
end).sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
|
end).sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
39
doc/TODO
39
doc/TODO
@ -5,22 +5,24 @@ BOARD:
|
|||||||
- editable elements should wrap a tag: div, h1, ...etc (default span)
|
- editable elements should wrap a tag: div, h1, ...etc (default span)
|
||||||
- edit images (upload new ones, ...etc) => wait for aloha or send them an email ?
|
- edit images (upload new ones, ...etc) => wait for aloha or send them an email ?
|
||||||
|
|
||||||
- import tool:
|
x import tool:
|
||||||
- add samples option
|
x asset whitelist
|
||||||
- remove existing pages / contents option
|
x do not override existing site name
|
||||||
- do not override existing site name
|
x add samples option
|
||||||
- page templatized (tied to content type)
|
x content types
|
||||||
- samples
|
x asset collections
|
||||||
|
x page templatized (tied to content type)
|
||||||
|
x remove existing pages / contents option => reset
|
||||||
|
|
||||||
- cosmetic / ui bugs / bugs:
|
- cosmetic / ui bugs / bugs:
|
||||||
|
x segmentation with with_scope
|
||||||
|
x paginate is not working
|
||||||
|
- assets within custom contents are not deleted when the whole content type gets destroyed (after_destroy callback ?)
|
||||||
- increase the input field for domain names
|
- increase the input field for domain names
|
||||||
- drag&drop for assets ('last' class issue)
|
- drag&drop for assets ('last' class issue)
|
||||||
- paginate is not working
|
|
||||||
- segmentation with with_scope
|
|
||||||
- asset whitelist
|
|
||||||
|
|
||||||
- api
|
x api
|
||||||
- handle html request (for now, it's just json)
|
x handle html request (for now, it's just json)
|
||||||
|
|
||||||
- refactor slugify method (use parameterize + create a module)
|
- refactor slugify method (use parameterize + create a module)
|
||||||
- [content types] the "display column" selector should not include file types
|
- [content types] the "display column" selector should not include file types
|
||||||
@ -28,14 +30,13 @@ BOARD:
|
|||||||
- global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)
|
- global regions: keyword in editable element (http://www.mongodb.org/display/DOCS/Updating)
|
||||||
- write my first tutorial about locomotive
|
- write my first tutorial about locomotive
|
||||||
|
|
||||||
- installation guide
|
x installation guide
|
||||||
- detect if new installation
|
x detect if new installation
|
||||||
- no-site error redirects to the first step
|
x no-site error redirects to the first step
|
||||||
- steps:
|
x steps:
|
||||||
0/ welcome: domains, ...etc
|
x welcome: domains, ...etc
|
||||||
1/ Create account
|
x Create account
|
||||||
2/ Create new site (name, subdomain)
|
x Create new site (name, subdomain) / Import theme (worker or list of sites from fs)
|
||||||
3/ Import theme (worker or list of sites from fs)
|
|
||||||
|
|
||||||
! add dom_id and css_class fields in page (body structure ?)
|
! add dom_id and css_class fields in page (body structure ?)
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ module CustomFields
|
|||||||
class FileUploader < ::CarrierWave::Uploader::Base
|
class FileUploader < ::CarrierWave::Uploader::Base
|
||||||
|
|
||||||
def store_dir
|
def store_dir
|
||||||
puts
|
|
||||||
"sites/#{model.site_id}/contents/#{model.class.model_name.underscore}/#{model.id}/files"
|
"sites/#{model.site_id}/contents/#{model.class.model_name.underscore}/#{model.id}/files"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ require 'actionmailer_with_request'
|
|||||||
require 'zip/zipfilesystem'
|
require 'zip/zipfilesystem'
|
||||||
require 'custom_fields'
|
require 'custom_fields'
|
||||||
require 'delayed_job_mongoid'
|
require 'delayed_job_mongoid'
|
||||||
|
require 'will_paginate'
|
||||||
|
|
||||||
$:.unshift File.dirname(__FILE__)
|
$:.unshift File.dirname(__FILE__)
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
require 'locomotive/import/logger'
|
||||||
|
require 'locomotive/import/base'
|
||||||
require 'locomotive/import/job'
|
require 'locomotive/import/job'
|
||||||
require 'locomotive/import/site'
|
require 'locomotive/import/site'
|
||||||
require 'locomotive/import/assets'
|
require 'locomotive/import/assets'
|
||||||
|
@ -1,30 +1,34 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module AssetCollections
|
class AssetCollections < Base
|
||||||
|
|
||||||
def self.process(context)
|
|
||||||
site, database = context[:site], context[:database]
|
|
||||||
|
|
||||||
|
def process
|
||||||
asset_collections = database['site']['asset_collections']
|
asset_collections = database['site']['asset_collections']
|
||||||
|
|
||||||
return if asset_collections.nil?
|
return if asset_collections.nil?
|
||||||
|
|
||||||
asset_collections.each do |name, attributes|
|
asset_collections.each do |name, attributes|
|
||||||
puts "....asset_collection = #{attributes['slug']}"
|
self.log "slug = #{attributes['slug']}"
|
||||||
|
|
||||||
asset_collection = site.asset_collections.where(:slug => attributes['slug']).first
|
asset_collection = site.asset_collections.where(:slug => attributes['slug']).first
|
||||||
|
|
||||||
asset_collection ||= self.build_asset_collection(site, attributes.merge(:name => name))
|
asset_collection ||= self.build_asset_collection(attributes.merge(:name => name))
|
||||||
|
|
||||||
self.add_or_update_fields(asset_collection, attributes['fields'])
|
self.add_or_update_fields(asset_collection, attributes['fields'])
|
||||||
|
|
||||||
|
if options[:samples] && attributes['assets']
|
||||||
|
self.insert_samples(asset_collection, attributes['assets'].symbolize_keys)
|
||||||
|
end
|
||||||
|
|
||||||
asset_collection.save!
|
asset_collection.save!
|
||||||
|
|
||||||
site.reload
|
site.reload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build_asset_collection(site, data)
|
protected
|
||||||
|
|
||||||
|
def build_asset_collection(data)
|
||||||
attributes = { :internal => false }.merge(data)
|
attributes = { :internal => false }.merge(data)
|
||||||
|
|
||||||
attributes.delete_if { |name, value| %w{fields assets}.include?(name) }
|
attributes.delete_if { |name, value| %w{fields assets}.include?(name) }
|
||||||
@ -32,7 +36,7 @@ module Locomotive
|
|||||||
site.asset_collections.build(attributes)
|
site.asset_collections.build(attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_or_update_fields(asset_collection, fields)
|
def add_or_update_fields(asset_collection, fields)
|
||||||
fields.each_with_index do |data, position|
|
fields.each_with_index do |data, position|
|
||||||
name, data = data.keys.first, data.values.first
|
name, data = data.keys.first, data.values.first
|
||||||
|
|
||||||
@ -48,6 +52,34 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def insert_samples(asset_collection, assets)
|
||||||
|
assets.each_with_index do |data, position|
|
||||||
|
value, attributes = data.is_a?(Array) ? [data.first, data.last] : [data.keys.first, data.values.first]
|
||||||
|
|
||||||
|
url = attributes.delete('url')
|
||||||
|
|
||||||
|
# build with default attributes
|
||||||
|
asset = asset_collection.assets.build(:name => value, :position => position, :url => self.open_sample_asset(url))
|
||||||
|
|
||||||
|
attributes.each do |name, value|
|
||||||
|
field = asset_collection.asset_custom_fields.detect { |f| f._alias == name }
|
||||||
|
|
||||||
|
value = (case field.kind.downcase
|
||||||
|
when 'file' then self.open_sample_asset(value)
|
||||||
|
when 'boolean' then Boolean.set(value)
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end)
|
||||||
|
|
||||||
|
asset.send("#{name}=", value)
|
||||||
|
end
|
||||||
|
|
||||||
|
asset.save
|
||||||
|
|
||||||
|
self.log "insert asset '#{name}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,24 +1,26 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module Assets
|
class Assets < Base
|
||||||
|
|
||||||
def self.process(context)
|
def process
|
||||||
site, theme_path = context[:site], context[:theme_path]
|
whitelist = self.build_regexps_in_withlist(database['site']['assets']['whitelist']) rescue nil
|
||||||
|
|
||||||
whitelist = self.build_regexps_in_withlist(context[:database]['site']['assets']['whitelist']) rescue nil
|
self.log "white list = #{whitelist.inspect}"
|
||||||
|
|
||||||
self.add_theme_assets(site, theme_path, whitelist)
|
self.add_theme_assets(whitelist)
|
||||||
|
|
||||||
self.add_other_assets(site, theme_path)
|
self.add_other_assets
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_theme_assets(site, theme_path, whitelist)
|
protected
|
||||||
|
|
||||||
|
def add_theme_assets(whitelist)
|
||||||
%w(images media fonts javascripts stylesheets).each do |kind|
|
%w(images media fonts javascripts stylesheets).each do |kind|
|
||||||
Dir[File.join(theme_path, 'public', kind, '**/*')].each do |asset_path|
|
Dir[File.join(theme_path, 'public', kind, '**/*')].each do |asset_path|
|
||||||
|
|
||||||
next if File.directory?(asset_path)
|
next if File.directory?(asset_path)
|
||||||
|
|
||||||
visible = self.check_against_whitelist(whitelist, asset_path.gsub(File.join(theme_path, 'public'), ''))
|
visible = self.check_against_whitelist(whitelist, asset_path.gsub(File.join(theme_path, 'public'), '').gsub(/^\//, ''))
|
||||||
|
|
||||||
folder = asset_path.gsub(File.join(theme_path, 'public'), '').gsub(File.basename(asset_path), '').gsub(/^\//, '').gsub(/\/$/, '')
|
folder = asset_path.gsub(File.join(theme_path, 'public'), '').gsub(File.basename(asset_path), '').gsub(/^\//, '').gsub(/\/$/, '')
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ module Locomotive
|
|||||||
begin
|
begin
|
||||||
asset.save!
|
asset.save!
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts "\t\t !!! asset_path = #{asset_path}, folder = #{folder}, error = #{e.message}"
|
self.log "!ERROR! = #{e.message}, #{asset_path}"
|
||||||
end
|
end
|
||||||
|
|
||||||
site.reload
|
site.reload
|
||||||
@ -39,7 +41,7 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_other_assets(site, theme_path)
|
def add_other_assets
|
||||||
collection = AssetCollection.find_or_create_internal(site)
|
collection = AssetCollection.find_or_create_internal(site)
|
||||||
|
|
||||||
Dir[File.join(theme_path, 'public', 'samples', '*')].each do |asset_path|
|
Dir[File.join(theme_path, 'public', 'samples', '*')].each do |asset_path|
|
||||||
@ -52,7 +54,7 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build_regexps_in_withlist(rules)
|
def build_regexps_in_withlist(rules)
|
||||||
rules.collect do |rule|
|
rules.collect do |rule|
|
||||||
if rule.start_with?('^')
|
if rule.start_with?('^')
|
||||||
Regexp.new(rule.gsub('/', '\/'))
|
Regexp.new(rule.gsub('/', '\/'))
|
||||||
@ -62,7 +64,7 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_against_whitelist(whitelist, path)
|
def check_against_whitelist(whitelist, path)
|
||||||
(whitelist || []).each do |rule|
|
(whitelist || []).each do |rule|
|
||||||
case rule
|
case rule
|
||||||
when Regexp
|
when Regexp
|
||||||
|
46
lib/locomotive/import/base.rb
Normal file
46
lib/locomotive/import/base.rb
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Import
|
||||||
|
class Base
|
||||||
|
|
||||||
|
include Logger
|
||||||
|
|
||||||
|
attr_reader :context, :options
|
||||||
|
|
||||||
|
def initialize(context, options)
|
||||||
|
@context = context
|
||||||
|
@options = options
|
||||||
|
self.log "*** starting to process ***"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.process(context, options)
|
||||||
|
self.new(context, options).process
|
||||||
|
end
|
||||||
|
|
||||||
|
def process
|
||||||
|
raise 'this method has to be overidden'
|
||||||
|
end
|
||||||
|
|
||||||
|
def log(message)
|
||||||
|
super(message, self.class.name.demodulize.underscore)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def site
|
||||||
|
@context[:site]
|
||||||
|
end
|
||||||
|
|
||||||
|
def database
|
||||||
|
@context[:database]
|
||||||
|
end
|
||||||
|
|
||||||
|
def theme_path
|
||||||
|
@context[:theme_path]
|
||||||
|
end
|
||||||
|
|
||||||
|
def open_sample_asset(url)
|
||||||
|
File.open(File.join(self.theme_path, 'public', url))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,20 +1,16 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module ContentTypes
|
class ContentTypes < Base
|
||||||
|
|
||||||
def self.process(context)
|
|
||||||
site, database = context[:site], context[:database]
|
|
||||||
|
|
||||||
content_types = database['site']['content_types']
|
|
||||||
|
|
||||||
|
def process
|
||||||
return if content_types.nil?
|
return if content_types.nil?
|
||||||
|
|
||||||
content_types.each do |name, attributes|
|
content_types.each do |name, attributes|
|
||||||
puts "\t\t....content_type = #{attributes['slug']}"
|
self.log "[content_types] slug = #{attributes['slug']}"
|
||||||
|
|
||||||
content_type = site.content_types.where(:slug => attributes['slug']).first
|
content_type = site.content_types.where(:slug => attributes['slug']).first
|
||||||
|
|
||||||
content_type ||= self.build_content_type(site, attributes.merge(:name => name))
|
content_type ||= self.build_content_type(attributes.merge(:name => name))
|
||||||
|
|
||||||
self.add_or_update_fields(content_type, attributes['fields'])
|
self.add_or_update_fields(content_type, attributes['fields'])
|
||||||
|
|
||||||
@ -24,13 +20,23 @@ module Locomotive
|
|||||||
|
|
||||||
self.set_group_by_value(content_type)
|
self.set_group_by_value(content_type)
|
||||||
|
|
||||||
|
if options[:samples] && attributes['contents']
|
||||||
|
self.insert_samples(content_type, attributes['contents'])
|
||||||
|
end
|
||||||
|
|
||||||
content_type.save!
|
content_type.save!
|
||||||
|
|
||||||
site.reload
|
site.reload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build_content_type(site, data)
|
protected
|
||||||
|
|
||||||
|
def content_types
|
||||||
|
database['site']['content_types']
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_content_type(data)
|
||||||
attributes = { :order_by => '_position_in_list', :group_by_field_name => data.delete('group_by') }.merge(data)
|
attributes = { :order_by => '_position_in_list', :group_by_field_name => data.delete('group_by') }.merge(data)
|
||||||
|
|
||||||
attributes.delete_if { |name, value| %w{fields contents}.include?(name) }
|
attributes.delete_if { |name, value| %w{fields contents}.include?(name) }
|
||||||
@ -38,7 +44,7 @@ module Locomotive
|
|||||||
site.content_types.build(attributes)
|
site.content_types.build(attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_or_update_fields(content_type, fields)
|
def add_or_update_fields(content_type, fields)
|
||||||
fields.each_with_index do |data, position|
|
fields.each_with_index do |data, position|
|
||||||
name, data = data.keys.first, data.values.first
|
name, data = data.keys.first, data.values.first
|
||||||
|
|
||||||
@ -54,13 +60,39 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_highlighted_field_name(content_type)
|
def insert_samples(content_type, contents)
|
||||||
|
contents.each_with_index do |data, position|
|
||||||
|
value, attributes = data.is_a?(Array) ? [data.first, data.last] : [data.keys.first, data.values.first]
|
||||||
|
|
||||||
|
# build with default attributes
|
||||||
|
content = content_type.contents.build(content_type.highlighted_field_name.to_sym => value, :_position_in_list => position)
|
||||||
|
|
||||||
|
attributes.each do |name, value|
|
||||||
|
field = content_type.content_custom_fields.detect { |f| f._alias == name }
|
||||||
|
|
||||||
|
value = (case field.kind.downcase
|
||||||
|
when 'file' then self.open_sample_asset(value)
|
||||||
|
when 'boolean' then Boolean.set(value)
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end)
|
||||||
|
|
||||||
|
content.send("#{name}=", value)
|
||||||
|
end
|
||||||
|
|
||||||
|
content.save
|
||||||
|
|
||||||
|
self.log "insert content '#{value}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_highlighted_field_name(content_type)
|
||||||
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.highlighted_field_name }
|
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.highlighted_field_name }
|
||||||
|
|
||||||
content_type.highlighted_field_name = field._name if field
|
content_type.highlighted_field_name = field._name if field
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_order_by_value(content_type)
|
def set_order_by_value(content_type)
|
||||||
order_by = (case content_type.order_by
|
order_by = (case content_type.order_by
|
||||||
when 'manually', '_position_in_list' then '_position_in_list'
|
when 'manually', '_position_in_list' then '_position_in_list'
|
||||||
when 'date', 'updated_at' then 'updated_at'
|
when 'date', 'updated_at' then 'updated_at'
|
||||||
@ -71,7 +103,7 @@ module Locomotive
|
|||||||
content_type.order_by = order_by || '_position_in_list'
|
content_type.order_by = order_by || '_position_in_list'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_group_by_value(content_type)
|
def set_group_by_value(content_type)
|
||||||
return if content_type.group_by_field_name.blank?
|
return if content_type.group_by_field_name.blank?
|
||||||
|
|
||||||
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.group_by_field_name }
|
field = content_type.content_custom_fields.detect { |f| f._alias == content_type.group_by_field_name }
|
||||||
|
@ -4,9 +4,15 @@ module Locomotive
|
|||||||
module Import
|
module Import
|
||||||
class Job
|
class Job
|
||||||
|
|
||||||
def initialize(zipfile, site, enabled = {})
|
include Logger
|
||||||
|
|
||||||
|
def initialize(zipfile, site, options = {})
|
||||||
@site = site
|
@site = site
|
||||||
@enabled = enabled
|
@options = {
|
||||||
|
:reset => false,
|
||||||
|
:samples => false,
|
||||||
|
:enabled => {}
|
||||||
|
}.merge(options)
|
||||||
|
|
||||||
@identifier = self.store_zipfile(zipfile)
|
@identifier = self.store_zipfile(zipfile)
|
||||||
|
|
||||||
@ -18,7 +24,7 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
self.log "theme identifier #{@identifier} / enabled steps = #{@enabled.inspect}"
|
self.log "theme identifier #{@identifier}"
|
||||||
|
|
||||||
self.unzip!
|
self.unzip!
|
||||||
|
|
||||||
@ -32,10 +38,11 @@ module Locomotive
|
|||||||
:worker => @worker
|
:worker => @worker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.reset! if @options[:reset]
|
||||||
|
|
||||||
%w(site content_types assets asset_collections snippets pages).each do |step|
|
%w(site content_types assets asset_collections snippets pages).each do |step|
|
||||||
if @enabled[step] != false
|
if @options[:enabled][step] != false
|
||||||
self.log "performing '#{step}' step"
|
"Locomotive::Import::#{step.camelize}".constantize.process(context, @options)
|
||||||
"Locomotive::Import::#{step.camelize}".constantize.process(context)
|
|
||||||
@worker.update_attributes :step => step if @worker
|
@worker.update_attributes :step => step if @worker
|
||||||
else
|
else
|
||||||
self.log "skipping #{step}"
|
self.log "skipping #{step}"
|
||||||
@ -59,10 +66,6 @@ module Locomotive
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def log(message)
|
|
||||||
puts "\t[import_theme] #{message}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def themes_folder
|
def themes_folder
|
||||||
File.join(Rails.root, 'tmp', 'themes', @site.id.to_s)
|
File.join(Rails.root, 'tmp', 'themes', @site.id.to_s)
|
||||||
end
|
end
|
||||||
@ -136,6 +139,13 @@ module Locomotive
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset!
|
||||||
|
@site.pages.destroy_all
|
||||||
|
@site.theme_assets.destroy_all
|
||||||
|
@site.content_types.destroy_all
|
||||||
|
@site.asset_collections.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
13
lib/locomotive/import/logger.rb
Normal file
13
lib/locomotive/import/logger.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Import
|
||||||
|
module Logger
|
||||||
|
|
||||||
|
def log(message, domain = '')
|
||||||
|
head = "[import_theme]"
|
||||||
|
head += "[#{domain}]" unless domain.blank?
|
||||||
|
::Locomotive::Logger.info "\t#{head} #{message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,13 +1,11 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module Pages
|
class Pages < Base
|
||||||
|
|
||||||
def self.process(context)
|
|
||||||
site, pages, theme_path = context[:site], context[:database]['pages'], context[:theme_path]
|
|
||||||
|
|
||||||
|
def process
|
||||||
context[:done] = {} # initialize the hash storing pages already processed
|
context[:done] = {} # initialize the hash storing pages already processed
|
||||||
|
|
||||||
self.add_index_and_404(context)
|
self.add_index_and_404
|
||||||
|
|
||||||
Dir[File.join(theme_path, 'templates', '**/*')].each do |template_path|
|
Dir[File.join(theme_path, 'templates', '**/*')].each do |template_path|
|
||||||
|
|
||||||
@ -15,43 +13,47 @@ module Locomotive
|
|||||||
|
|
||||||
next if %w(index 404).include?(fullpath)
|
next if %w(index 404).include?(fullpath)
|
||||||
|
|
||||||
self.add_page(fullpath, context)
|
self.add_page(fullpath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_page(fullpath, context)
|
protected
|
||||||
puts "\t\t....adding #{fullpath}"
|
|
||||||
|
|
||||||
|
def add_page(fullpath)
|
||||||
page = context[:done][fullpath]
|
page = context[:done][fullpath]
|
||||||
|
|
||||||
return page if page # already added, so skip it
|
return page if page # already added, so skip it
|
||||||
|
|
||||||
site, pages, theme_path = context[:site], context[:database]['site']['pages'], context[:theme_path]
|
|
||||||
|
|
||||||
template = File.read(File.join(theme_path, 'templates', "#{fullpath}.liquid")) rescue "Unable to find #{fullpath}.liquid"
|
template = File.read(File.join(theme_path, 'templates', "#{fullpath}.liquid")) rescue "Unable to find #{fullpath}.liquid"
|
||||||
|
|
||||||
self.build_parent_template(template, context)
|
self.build_parent_template(template)
|
||||||
|
|
||||||
parent = self.find_parent(fullpath, context)
|
parent = self.find_parent(fullpath)
|
||||||
|
|
||||||
page = site.pages.where(:fullpath => fullpath).first || site.pages.build
|
|
||||||
|
|
||||||
attributes = {
|
attributes = {
|
||||||
:title => fullpath.split('/').last.humanize,
|
:title => fullpath.split('/').last.humanize,
|
||||||
:slug => fullpath.split('/').last,
|
:slug => fullpath.split('/').last,
|
||||||
:parent => parent,
|
:parent => parent,
|
||||||
:raw_template => template
|
:raw_template => template
|
||||||
}.merge(pages[fullpath] || {}).symbolize_keys
|
}.merge(self.pages[fullpath] || {}).symbolize_keys
|
||||||
|
|
||||||
# templatized ?
|
# templatized ?
|
||||||
if content_type_slug = attributes.delete(:content_type)
|
if content_type_slug = attributes.delete(:content_type)
|
||||||
attributes[:content_type] = site.content_types.where(:slug => content_type_slug).first
|
fullpath.gsub!(/\/template$/, '/content_type_template')
|
||||||
|
attributes.merge!({
|
||||||
|
:templatized => true,
|
||||||
|
:content_type => site.content_types.where(:slug => content_type_slug).first
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
page = site.pages.where(:fullpath => fullpath).first || site.pages.build
|
||||||
|
|
||||||
page.attributes = attributes
|
page.attributes = attributes
|
||||||
|
|
||||||
page.save!
|
page.save!
|
||||||
|
|
||||||
|
self.log "adding #{page.fullpath}"
|
||||||
|
|
||||||
site.reload
|
site.reload
|
||||||
|
|
||||||
context[:done][fullpath] = page
|
context[:done][fullpath] = page
|
||||||
@ -59,7 +61,7 @@ module Locomotive
|
|||||||
page
|
page
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build_parent_template(template, context)
|
def build_parent_template(template)
|
||||||
# just check if the template contains the extends keyword
|
# just check if the template contains the extends keyword
|
||||||
fullpath = template.scan(/\{% extends (\w+) %\}/).flatten.first
|
fullpath = template.scan(/\{% extends (\w+) %\}/).flatten.first
|
||||||
|
|
||||||
@ -68,13 +70,11 @@ module Locomotive
|
|||||||
|
|
||||||
return if fullpath == 'parent'
|
return if fullpath == 'parent'
|
||||||
|
|
||||||
self.add_page(fullpath, context)
|
self.add_page(fullpath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.find_parent(fullpath, context)
|
def find_parent(fullpath)
|
||||||
site = context[:site]
|
|
||||||
|
|
||||||
segments = fullpath.split('/')
|
segments = fullpath.split('/')
|
||||||
|
|
||||||
return site.pages.index.first if segments.size == 1
|
return site.pages.index.first if segments.size == 1
|
||||||
@ -86,12 +86,10 @@ module Locomotive
|
|||||||
# look for a local index page in db
|
# look for a local index page in db
|
||||||
parent = site.pages.where(:fullpath => parent_fullpath).first
|
parent = site.pages.where(:fullpath => parent_fullpath).first
|
||||||
|
|
||||||
parent || self.add_page(parent_fullpath, context)
|
parent || self.add_page(parent_fullpath)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_index_and_404(context)
|
def add_index_and_404
|
||||||
site, pages, theme_path = context[:site], context[:database]['site']['pages'], context[:theme_path]
|
|
||||||
|
|
||||||
%w(index 404).each_with_index do |slug, position|
|
%w(index 404).each_with_index do |slug, position|
|
||||||
page = site.pages.where({ :slug => slug, :depth => 0 }).first
|
page = site.pages.where({ :slug => slug, :depth => 0 }).first
|
||||||
|
|
||||||
@ -99,7 +97,7 @@ module Locomotive
|
|||||||
|
|
||||||
template = File.read(File.join(theme_path, 'templates', "#{slug}.liquid"))
|
template = File.read(File.join(theme_path, 'templates', "#{slug}.liquid"))
|
||||||
|
|
||||||
page.attributes = { :raw_template => template, :position => position }.merge(pages[slug] || {})
|
page.attributes = { :raw_template => template, :position => position }.merge(self.pages[slug] || {})
|
||||||
|
|
||||||
page.save! rescue nil # TODO better error handling
|
page.save! rescue nil # TODO better error handling
|
||||||
|
|
||||||
@ -109,6 +107,10 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def pages
|
||||||
|
context[:database]['site']['pages']
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,11 +1,9 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module Site
|
class Site < Base
|
||||||
|
|
||||||
def self.process(context)
|
def process
|
||||||
site, database = context[:site], context[:database]
|
attributes = database['site'].clone.delete_if { |name, value| %w{name pages assets content_types asset_collections}.include?(name) }
|
||||||
|
|
||||||
attributes = database['site'].clone.delete_if { |name, value| %w{pages assets content_types asset_collections}.include?(name) }
|
|
||||||
|
|
||||||
site.attributes = attributes
|
site.attributes = attributes
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
module Import
|
module Import
|
||||||
module Snippets
|
class Snippets < Base
|
||||||
|
|
||||||
def self.process(context)
|
|
||||||
site, theme_path = context[:site], context[:theme_path]
|
|
||||||
|
|
||||||
|
def process
|
||||||
Dir[File.join(theme_path, 'snippets', '*')].each do |snippet_path|
|
Dir[File.join(theme_path, 'snippets', '*')].each do |snippet_path|
|
||||||
|
self.log "path = #{snippet_path}"
|
||||||
|
|
||||||
name = File.basename(snippet_path, File.extname(snippet_path)).parameterize('_')
|
name = File.basename(snippet_path, File.extname(snippet_path)).parameterize('_')
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ module Locomotive
|
|||||||
snippet.template = File.read(snippet_path) # = site.snippets.create! :name => name, :template =>
|
snippet.template = File.read(snippet_path) # = site.snippets.create! :name => name, :template =>
|
||||||
|
|
||||||
snippet.save!
|
snippet.save!
|
||||||
# puts "snippet = #{snippet.inspect}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ module Locomotive
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def paginate(options = {})
|
def paginate(options = {})
|
||||||
@collection ||= self.collection.paginate(options)
|
@collection = self.collection.paginate(options)
|
||||||
{
|
{
|
||||||
:collection => @collection,
|
:collection => @collection,
|
||||||
:current_page => @collection.current_page,
|
:current_page => @collection.current_page,
|
||||||
@ -58,7 +58,7 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
|
|
||||||
def collection
|
def collection
|
||||||
@collection ||= @content_type.ordered_contents(@context['with_scope']) # remove per_page, page keys
|
@collection ||= @content_type.ordered_contents(@context['with_scope'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -60,7 +60,7 @@ module Locomotive
|
|||||||
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new,
|
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new,
|
||||||
'contents' => Locomotive::Liquid::Drops::Contents.new,
|
'contents' => Locomotive::Liquid::Drops::Contents.new,
|
||||||
'current_page' => self.params[:page]
|
'current_page' => self.params[:page]
|
||||||
}
|
}.merge(flash.stringify_keys) # data from api
|
||||||
|
|
||||||
if @page.templatized? # add instance from content type
|
if @page.templatized? # add instance from content type
|
||||||
assigns['content_instance'] = @content_instance
|
assigns['content_instance'] = @content_instance
|
||||||
@ -79,6 +79,8 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
|
|
||||||
def prepare_and_set_response(output)
|
def prepare_and_set_response(output)
|
||||||
|
flash.discard
|
||||||
|
|
||||||
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
||||||
|
|
||||||
if @page.with_cache?
|
if @page.with_cache?
|
||||||
|
@ -39,6 +39,7 @@ Gem::Specification.new do |s|
|
|||||||
s.add_dependency "delayed_job_mongoid", "1.0.0.rc"
|
s.add_dependency "delayed_job_mongoid", "1.0.0.rc"
|
||||||
s.add_dependency "custom_fields", "1.0.0.beta2"
|
s.add_dependency "custom_fields", "1.0.0.beta2"
|
||||||
s.add_dependency "rubyzip"
|
s.add_dependency "rubyzip"
|
||||||
|
s.add_dependency "will_paginate"
|
||||||
|
|
||||||
s.files = Dir[ "Gemfile",
|
s.files = Dir[ "Gemfile",
|
||||||
"{app}/**/*",
|
"{app}/**/*",
|
||||||
|
BIN
spec/fixtures/themes/default.zip
vendored
Normal file
BIN
spec/fixtures/themes/default.zip
vendored
Normal file
Binary file not shown.
76
spec/lib/locomotive/import_spec.rb
Normal file
76
spec/lib/locomotive/import_spec.rb
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Locomotive::Import::Job do
|
||||||
|
|
||||||
|
context 'when successful' do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
@site = Factory(:site)
|
||||||
|
|
||||||
|
job = Locomotive::Import::Job.new(FixturedTheme.duplicate_and_open('default.zip'), @site, { :samples => true, :reset => true })
|
||||||
|
job.perform
|
||||||
|
|
||||||
|
job.success nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the site information' do
|
||||||
|
@site.name.should_not == "HTML5 portfolio"
|
||||||
|
@site.meta_keywords.should == "html5 portfolio theme locomotive cms"
|
||||||
|
@site.meta_description.should == "portfolio powered by html5"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds content types' do
|
||||||
|
@site.content_types.count.should == 2
|
||||||
|
content_type = @site.content_types.where(:slug => 'projects').first
|
||||||
|
content_type.content_custom_fields.size.should == 6
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'converts correctly the order_by option for content types' do
|
||||||
|
content_type = @site.content_types.where(:slug => 'messages').first
|
||||||
|
content_type.order_by.should == 'updated_at'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds samples coming with content types' do
|
||||||
|
content_type = @site.content_types.where(:slug => 'projects').first
|
||||||
|
content_type.contents.size.should == 5
|
||||||
|
|
||||||
|
content = content_type.contents.first
|
||||||
|
content.name.should == 'Locomotive App'
|
||||||
|
content.thumbnail.url.should_not be_nil
|
||||||
|
content.featured.should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'inserts theme assets' do
|
||||||
|
@site.theme_assets.count.should == 10
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'hides some theme assets' do
|
||||||
|
asset = @site.theme_assets.where(:local_path => 'stylesheets/style.css').first
|
||||||
|
asset.hidden.should == false
|
||||||
|
|
||||||
|
asset = @site.theme_assets.where(:local_path => 'stylesheets/ie7.css').first
|
||||||
|
asset.hidden.should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'inserts all the pages' do
|
||||||
|
@site.pages.count.should == 8
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'inserts the index and 404 pages' do
|
||||||
|
@site.pages.index.first.should_not be_nil
|
||||||
|
@site.pages.not_found.first.should_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'inserts templatized page' do
|
||||||
|
page = @site.pages.where(:templatized => true).first
|
||||||
|
page.should_not be_nil
|
||||||
|
page.fullpath.should == 'portfolio/content_type_template'
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
Site.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -21,6 +21,8 @@ Rspec.configure do |config|
|
|||||||
DatabaseCleaner.orm = "mongoid"
|
DatabaseCleaner.orm = "mongoid"
|
||||||
end
|
end
|
||||||
config.before(:each) do
|
config.before(:each) do
|
||||||
|
if self.described_class != Locomotive::Import::Job
|
||||||
DatabaseCleaner.clean
|
DatabaseCleaner.clean
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@ CarrierWave.configure do |config|
|
|||||||
config.store_dir = "spec/tmp/uploads"
|
config.store_dir = "spec/tmp/uploads"
|
||||||
config.cache_dir = "spec/tmp/cache"
|
config.cache_dir = "spec/tmp/cache"
|
||||||
config.root = File.join(Rails.root, 'spec', 'tmp')
|
config.root = File.join(Rails.root, 'spec', 'tmp')
|
||||||
# config.enable_processing = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module FixturedAsset
|
module FixturedAsset
|
||||||
@ -29,4 +28,24 @@ module FixturedAsset
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module FixturedTheme
|
||||||
|
def self.open(filename)
|
||||||
|
File.new(self.path(filename))
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.path(filename)
|
||||||
|
File.join(File.dirname(__FILE__), '..', 'fixtures', 'themes', filename)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.duplicate(filename)
|
||||||
|
dst = File.join(File.dirname(__FILE__), '..', 'tmp', filename)
|
||||||
|
FileUtils.cp self.path(filename), dst
|
||||||
|
dst
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.duplicate_and_open(filename)
|
||||||
|
File.open(self.duplicate(filename))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
FixturedAsset.reset!
|
FixturedAsset.reset!
|
||||||
|
Loading…
Reference in New Issue
Block a user