locomotive_cms 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/locomotive/api/base_controller.rb +11 -0
- data/lib/locomotive/custom_fields.rb +1 -1
- data/lib/locomotive/middlewares/seo_trailing_slash.rb +26 -5
- data/lib/locomotive/version.rb +1 -1
- data/mongodb/migrate/20130204072721_make_editable_elements_consistent.rb +107 -0
- data/mongodb/migrate/20130326201349_rename_entry_to_content_entry.rb +107 -0
- data/spec/models/locomotive/content_entry_spec.rb +46 -33
- data/spec/requests/seo_trailing_slash_spec.rb +6 -0
- metadata +6 -4
@@ -15,6 +15,8 @@ module Locomotive
|
|
15
15
|
|
16
16
|
before_filter :set_current_thread_variables
|
17
17
|
|
18
|
+
rescue_from Exception, with: :render_access_denied
|
19
|
+
|
18
20
|
self.responder = Locomotive::ActionController::Responder # custom responder
|
19
21
|
|
20
22
|
respond_to :json, :xml
|
@@ -41,6 +43,15 @@ module Locomotive
|
|
41
43
|
self.setup_i18n_fallbacks
|
42
44
|
end
|
43
45
|
|
46
|
+
def render_access_denied(exception)
|
47
|
+
status = (case exception
|
48
|
+
when ::CanCan::AccessDenied then 401
|
49
|
+
when ::Mongoid::Errors::DocumentNotFound then 404
|
50
|
+
else 500
|
51
|
+
end)
|
52
|
+
render json: { error: exception.message }, status: status, layout: false
|
53
|
+
end
|
54
|
+
|
44
55
|
def self.cancan_resource_class
|
45
56
|
Locomotive::Api::CanCan::ControllerResource
|
46
57
|
end
|
@@ -38,7 +38,7 @@ module CustomFields
|
|
38
38
|
|
39
39
|
# Set correct paths
|
40
40
|
def store_dir
|
41
|
-
"sites/#{model.site_id}
|
41
|
+
"sites/#{model.site_id}/#{model.class.model_name.demodulize.underscore}/#{model.id}/files"
|
42
42
|
end
|
43
43
|
|
44
44
|
# In some situations, for instance, for the notification email when a content entry is created,
|
@@ -7,18 +7,39 @@ module Locomotive
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call(env)
|
10
|
-
path = env['PATH_INFO']
|
10
|
+
path, query = env['PATH_INFO'], env['QUERY_STRING']
|
11
11
|
|
12
12
|
if !path.starts_with?("#{Locomotive.mounted_on}/") && (match = path.match(%r{(.+)/$}))
|
13
|
-
|
14
|
-
|
15
|
-
response.finish
|
16
|
-
response.to_a
|
13
|
+
url = self.redirect_url(match[1], query)
|
14
|
+
self.redirect_to(url)
|
17
15
|
else
|
18
16
|
@app.call(env)
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
20
|
+
protected
|
21
|
+
|
22
|
+
# Create a 301 response and set it up accordingly.
|
23
|
+
#
|
24
|
+
# @params [ String ] url The url for the redirection
|
25
|
+
#
|
26
|
+
# @return [ Array ] It has the 3 parameters (status, header, body)
|
27
|
+
#
|
28
|
+
def redirect_to(url)
|
29
|
+
response = Rack::Response.new
|
30
|
+
response.redirect(url, 301) # moved permanently
|
31
|
+
response.finish
|
32
|
+
response.to_a
|
33
|
+
end
|
34
|
+
|
35
|
+
def redirect_url(base, query)
|
36
|
+
if query.blank?
|
37
|
+
base
|
38
|
+
else
|
39
|
+
"#{base}?#{query}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
22
43
|
end
|
23
44
|
end
|
24
45
|
end
|
data/lib/locomotive/version.rb
CHANGED
@@ -0,0 +1,107 @@
|
|
1
|
+
class MakeEditableElementsConsistent < MongoidMigration::Migration
|
2
|
+
def self.up
|
3
|
+
Locomotive::Site.all.each do |site|
|
4
|
+
site.locales.each do |locale|
|
5
|
+
::Mongoid::Fields::I18n.locale = locale
|
6
|
+
site.pages.each do |page|
|
7
|
+
puts "[#{site.name}] #{page.fullpath} (#{locale})"
|
8
|
+
|
9
|
+
found_elements = []
|
10
|
+
|
11
|
+
page.template.walk do |node, memo|
|
12
|
+
case node
|
13
|
+
when Locomotive::Liquid::Tags::InheritedBlock
|
14
|
+
puts "found block ! #{node.name} --- #{memo[:parent_block_name]}"
|
15
|
+
|
16
|
+
# set the new name based on a potential parent block
|
17
|
+
name = node.name.gsub(/[\"\']/o, '')
|
18
|
+
|
19
|
+
if memo[:parent_block_name] && !name.starts_with?(memo[:parent_block_name])
|
20
|
+
name = "#{memo[:parent_block_name]}/#{name}"
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "new_name = #{name}"
|
24
|
+
|
25
|
+
# retrieve all the editable elements of this block and set them the new name
|
26
|
+
page.find_editable_elements(node.name).each do |el|
|
27
|
+
# puts "**> hurray found the element #{el.block} _ #{el.slug}"
|
28
|
+
el.block = name
|
29
|
+
puts "**> hurray found the element #{el.block} _ #{el.slug} | #{page.find_editable_element(name, el.slug).present?.inspect}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# assign the new name to the block
|
33
|
+
node.instance_variable_set :@name, name
|
34
|
+
|
35
|
+
# record the new parent block name for children
|
36
|
+
memo[:parent_block_name] = name
|
37
|
+
|
38
|
+
when Locomotive::Liquid::Tags::Editable::ShortText,
|
39
|
+
Locomotive::Liquid::Tags::Editable::LongText,
|
40
|
+
Locomotive::Liquid::Tags::Editable::Control,
|
41
|
+
Locomotive::Liquid::Tags::Editable::File
|
42
|
+
|
43
|
+
puts "\tfound editable_element ! #{node.slug} --- #{memo[:parent_block_name]}"
|
44
|
+
|
45
|
+
slug = node.slug.gsub(/[\"\']/o, '')
|
46
|
+
|
47
|
+
# assign the new slug to the editable element
|
48
|
+
puts "\t\t...looking for #{node.slug} inside #{memo[:parent_block_name]}"
|
49
|
+
|
50
|
+
options = node.instance_variable_get :@options
|
51
|
+
block = options[:block].blank? ? memo[:parent_block_name] : options[:block]
|
52
|
+
|
53
|
+
if el = page.find_editable_element(block, node.slug)
|
54
|
+
puts "\t\t--> yep found the element"
|
55
|
+
|
56
|
+
el.slug = slug
|
57
|
+
el.block = memo[:parent_block_name] # just to make sure
|
58
|
+
|
59
|
+
node.instance_variable_set :@slug, slug
|
60
|
+
|
61
|
+
options.delete(:block)
|
62
|
+
node.instance_variable_set :@block, nil # just to make sure
|
63
|
+
|
64
|
+
found_elements << el._id
|
65
|
+
else
|
66
|
+
puts "\t\t[WARNING] el not found (#{block} - #{slug})"
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
memo
|
72
|
+
end # page walk
|
73
|
+
|
74
|
+
puts "found elements = #{found_elements.join(', ')} / #{page.editable_elements.count}"
|
75
|
+
|
76
|
+
# "hide" useless editable elements
|
77
|
+
page.editable_elements.each do |el|
|
78
|
+
next if found_elements.include?(el._id)
|
79
|
+
el.disabled = true
|
80
|
+
end
|
81
|
+
|
82
|
+
# serialize
|
83
|
+
page.send(:_serialize_template)
|
84
|
+
|
85
|
+
# puts page.template.inspect
|
86
|
+
|
87
|
+
# save ?
|
88
|
+
page.instance_variable_set :@template_changed, false
|
89
|
+
page.save
|
90
|
+
|
91
|
+
# TODO:
|
92
|
+
# x ", block: 'Asset #1'"" ???? les re-assigner a "main" d'une facon ou d'une autre
|
93
|
+
# => en fait, ce sont des editable elements qui n'ont pas vrais blocks
|
94
|
+
# x hide useless editable elements
|
95
|
+
# x re-serializer le template
|
96
|
+
# ? skipper la methode parse (quoique pas besoin car template non modifie)
|
97
|
+
# x snippets
|
98
|
+
# x sauvegarder (sans callbacks ??)
|
99
|
+
end # loop: pages
|
100
|
+
end # loop: locales
|
101
|
+
end # loop: sites
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.down
|
105
|
+
raise MongoidMigration::IrreversibleMigration
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class RenameEntryToContentEntry < MongoidMigration::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
regexp = /(^|Locomotive::)(Content)*Entry([0-9a-fA-F]{24})$/
|
5
|
+
replacement = "\\1ContentEntry\\3"
|
6
|
+
|
7
|
+
# content entries
|
8
|
+
self.update_content_entries(regexp, replacement)
|
9
|
+
|
10
|
+
# content types
|
11
|
+
self.update_content_types(regexp, replacement)
|
12
|
+
|
13
|
+
# templatized pages
|
14
|
+
self.update_templatized_pages(regexp, replacement)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
regexp = /(^|Locomotive::)(Content)+Entry([0-9a-fA-F]{24})$/
|
19
|
+
replacement = "\\1Entry\\3"
|
20
|
+
|
21
|
+
# content entries
|
22
|
+
self.update_content_entries(regexp, replacement)
|
23
|
+
|
24
|
+
# content types
|
25
|
+
self.update_content_types(regexp, replacement)
|
26
|
+
|
27
|
+
# templatized pages
|
28
|
+
self.update_templatized_pages(regexp, replacement)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.update_content_entries(regexp, replacement)
|
34
|
+
self.fetch_rows(Locomotive::ContentEntry) do |collection, attributes|
|
35
|
+
recipe = attributes['custom_fields_recipe']
|
36
|
+
type = attributes['_type']
|
37
|
+
new_recipe = replace_value_by(recipe, regexp, replacement)
|
38
|
+
selector = { '_id' => attributes['_id'] }
|
39
|
+
operations = { '$set' => {
|
40
|
+
'_type' => replace_value_by(type, regexp, replacement),
|
41
|
+
'custom_fields_recipe' => new_recipe
|
42
|
+
} }
|
43
|
+
collection.update selector, operations
|
44
|
+
end
|
45
|
+
puts "content entries UPDATED"
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.update_content_types(regexp, replacement)
|
49
|
+
self.fetch_rows(Locomotive::ContentType) do |collection, attributes|
|
50
|
+
updates = {}
|
51
|
+
attributes['entries_custom_fields'].each_with_index do |custom_field, index|
|
52
|
+
new_custom_field = replace_value_by(custom_field, regexp, replacement)
|
53
|
+
updates["entries_custom_fields.#{index}"] = new_custom_field
|
54
|
+
end
|
55
|
+
|
56
|
+
selector = { '_id' => attributes['_id'] }
|
57
|
+
operations = { '$set' => updates }
|
58
|
+
collection.update selector, operations
|
59
|
+
end
|
60
|
+
puts "content types UPDATED"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.update_templatized_pages(regexp, replacement)
|
64
|
+
self.fetch_rows(Locomotive::Page) do |collection, attributes|
|
65
|
+
if klass_name = attributes['target_klass_name']
|
66
|
+
new_klass_name = replace_value_by(klass_name, regexp, replacement)
|
67
|
+
selector = { '_id' => attributes['_id'] }
|
68
|
+
operations = { '$set' => { 'target_klass_name' => new_klass_name } }
|
69
|
+
collection.update selector, operations
|
70
|
+
end
|
71
|
+
end
|
72
|
+
puts "templatized pages UPDATED"
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.fetch_rows(klass, &block)
|
76
|
+
per_page = 100
|
77
|
+
collection = klass.collection.driver
|
78
|
+
count = collection.count
|
79
|
+
num_pages = (count.to_f / per_page).floor
|
80
|
+
|
81
|
+
# paginate the whole collection to avoid mongodb cursor error
|
82
|
+
(0..num_pages).each do |page|
|
83
|
+
offset = per_page * page.to_i
|
84
|
+
collection.find.sort("_id").limit(per_page).skip(offset).each do |attributes|
|
85
|
+
block.call(collection, attributes)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.replace_value_by(object, regexp, replacement)
|
91
|
+
return object.gsub(regexp, replacement) if object.is_a?(String)
|
92
|
+
|
93
|
+
list = nil
|
94
|
+
list = object if object.is_a?(Array)
|
95
|
+
list = object.values if object.is_a?(Hash)
|
96
|
+
|
97
|
+
list.each do |value|
|
98
|
+
case value
|
99
|
+
when String then value.gsub!(regexp, replacement)
|
100
|
+
when Array, Hash then self.replace_value_by(value, regexp, replacement)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
object
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -7,10 +7,10 @@ describe Locomotive::ContentEntry do
|
|
7
7
|
before(:each) do
|
8
8
|
Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true)
|
9
9
|
@content_type = FactoryGirl.build(:content_type)
|
10
|
-
@content_type.entries_custom_fields.build :
|
11
|
-
@content_type.entries_custom_fields.build :
|
12
|
-
@content_type.entries_custom_fields.build :
|
13
|
-
@content_type.entries_custom_fields.build :
|
10
|
+
@content_type.entries_custom_fields.build label: 'Title', type: 'string'
|
11
|
+
@content_type.entries_custom_fields.build label: 'Description', type: 'text'
|
12
|
+
@content_type.entries_custom_fields.build label: 'Visible ?', type: 'boolean', name: 'visible'
|
13
|
+
@content_type.entries_custom_fields.build label: 'File', type: 'file'
|
14
14
|
@content_type.valid?
|
15
15
|
@content_type.send(:set_label_field)
|
16
16
|
end
|
@@ -24,56 +24,57 @@ describe Locomotive::ContentEntry do
|
|
24
24
|
## Validations ##
|
25
25
|
|
26
26
|
it 'requires the presence of title' do
|
27
|
-
content_entry = build_content_entry :
|
27
|
+
content_entry = build_content_entry title: nil
|
28
28
|
content_entry.should_not be_valid
|
29
29
|
content_entry.errors[:title].should == ["can't be blank"]
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'requires the presence of the permalink (_slug)' do
|
33
|
-
content_entry = build_content_entry :
|
33
|
+
content_entry = build_content_entry title: nil
|
34
34
|
content_entry.should_not be_valid
|
35
35
|
content_entry.errors[:_slug].should == ["can't be blank"]
|
36
36
|
end
|
37
37
|
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
describe '#slug' do
|
41
|
+
|
41
42
|
before :each do
|
42
|
-
build_content_entry(:
|
43
|
+
build_content_entry(_slug: 'dogs').tap(&:save!)._slug.should == 'dogs'
|
43
44
|
end
|
44
45
|
|
45
46
|
it 'uses the given slug if it is unique' do
|
46
|
-
build_content_entry(:
|
47
|
-
build_content_entry(:
|
47
|
+
build_content_entry(_slug: 'monkeys').tap(&:save!)._slug.should == 'monkeys'
|
48
|
+
build_content_entry(_slug: 'cats-2').tap(&:save!)._slug.should == 'cats-2'
|
48
49
|
end
|
49
50
|
|
50
51
|
it 'appends a number to the end of the slug if it is not unique' do
|
51
|
-
build_content_entry(:
|
52
|
-
build_content_entry(:
|
53
|
-
build_content_entry(:
|
54
|
-
build_content_entry(:
|
52
|
+
build_content_entry(_slug: 'dogs').tap(&:save!)._slug.should == 'dogs-1'
|
53
|
+
build_content_entry(_slug: 'dogs').tap(&:save!)._slug.should == 'dogs-2'
|
54
|
+
build_content_entry(_slug: 'dogs-2').tap(&:save!)._slug.should == 'dogs-3'
|
55
|
+
build_content_entry(_slug: 'dogs-2').tap(&:save!)._slug.should == 'dogs-4'
|
55
56
|
end
|
56
57
|
|
57
58
|
it 'ignores the case of a slug' do
|
58
|
-
build_content_entry(:
|
59
|
-
build_content_entry(:
|
59
|
+
build_content_entry(_slug: 'dogs').tap(&:save!)._slug.should == 'dogs-1'
|
60
|
+
build_content_entry(_slug: 'DOGS').tap(&:save!)._slug.should == 'dogs-2'
|
60
61
|
end
|
61
62
|
|
62
63
|
it 'correctly handles slugs with multiple numbers' do
|
63
|
-
build_content_entry(:
|
64
|
-
build_content_entry(:
|
64
|
+
build_content_entry(_slug: 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-2'
|
65
|
+
build_content_entry(_slug: 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-3'
|
65
66
|
|
66
|
-
build_content_entry(:
|
67
|
-
build_content_entry(:
|
67
|
+
build_content_entry(_slug: 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi'
|
68
|
+
build_content_entry(_slug: 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi-1'
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
|
-
|
72
|
+
describe '#i18n' do
|
72
73
|
|
73
74
|
before(:each) do
|
74
75
|
localize_content_type @content_type
|
75
76
|
::Mongoid::Fields::I18n.locale = 'en'
|
76
|
-
@content_entry = build_content_entry(:
|
77
|
+
@content_entry = build_content_entry(title: 'Hello world')
|
77
78
|
::Mongoid::Fields::I18n.locale = 'fr'
|
78
79
|
end
|
79
80
|
|
@@ -90,12 +91,13 @@ describe Locomotive::ContentEntry do
|
|
90
91
|
end
|
91
92
|
|
92
93
|
describe "#navigation" do
|
94
|
+
|
93
95
|
before(:each) do
|
94
96
|
@content_type.order_by = '_position'
|
95
97
|
@content_type.save
|
96
98
|
|
97
99
|
%w(first second third).each_with_index do |item, index|
|
98
|
-
content = build_content_entry(:
|
100
|
+
content = build_content_entry(title: item.to_s, _position: index)
|
99
101
|
content.save
|
100
102
|
instance_variable_set "@#{item}", content
|
101
103
|
end
|
@@ -196,24 +198,35 @@ describe Locomotive::ContentEntry do
|
|
196
198
|
end
|
197
199
|
|
198
200
|
it 'uses the to_label method if the value of the label field defined it' do
|
199
|
-
entry = build_content_entry(:
|
200
|
-
entry.stubs(:with_to_label).returns(mock('with_to_label', :
|
201
|
+
entry = build_content_entry(_label_field_name: 'with_to_label')
|
202
|
+
entry.stubs(:with_to_label).returns(mock('with_to_label', to_label: 'acme'))
|
201
203
|
entry._label.should == 'acme'
|
202
204
|
end
|
203
205
|
|
204
206
|
it 'uses the to_s method at last if the label field did not define the to_label method' do
|
205
|
-
entry = build_content_entry(:
|
206
|
-
entry.stubs(:not_a_string).returns(mock('not_a_string', :
|
207
|
+
entry = build_content_entry(_label_field_name: 'not_a_string')
|
208
|
+
entry.stubs(:not_a_string).returns(mock('not_a_string', to_s: 'not_a_string'))
|
207
209
|
entry._label.should == 'not_a_string'
|
208
210
|
end
|
209
211
|
|
210
212
|
end
|
211
213
|
|
214
|
+
describe '#file' do
|
215
|
+
|
216
|
+
let(:entry) { build_content_entry(title: 'Hello world', file: FixturedAsset.open('5k.png')) }
|
217
|
+
|
218
|
+
it 'writes the file to the filesystem' do
|
219
|
+
entry.save
|
220
|
+
entry.file.url.should_not =~ /content_content_entry/
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
212
225
|
describe '#public_submission' do
|
213
226
|
|
214
227
|
before(:each) do
|
215
|
-
@account_1 = FactoryGirl.build('admin user', :
|
216
|
-
@account_2 = FactoryGirl.build('frenchy user', :
|
228
|
+
@account_1 = FactoryGirl.build('admin user', id: fake_bson_id('1'))
|
229
|
+
@account_2 = FactoryGirl.build('frenchy user', id: fake_bson_id('2'))
|
217
230
|
|
218
231
|
@content_type.public_submission_enabled = true
|
219
232
|
@content_type.public_submission_accounts = ['', @account_1._id, @account_2._id.to_s]
|
@@ -221,7 +234,7 @@ describe Locomotive::ContentEntry do
|
|
221
234
|
site = FactoryGirl.build(:site)
|
222
235
|
site.stubs(:accounts).returns([@account_1, @account_2])
|
223
236
|
|
224
|
-
@content_entry = build_content_entry(:
|
237
|
+
@content_entry = build_content_entry(site: site)
|
225
238
|
end
|
226
239
|
|
227
240
|
it 'does not send email notifications if the api is disabled' do
|
@@ -237,8 +250,8 @@ describe Locomotive::ContentEntry do
|
|
237
250
|
end
|
238
251
|
|
239
252
|
it 'sends email notifications when a new instance is created' do
|
240
|
-
Locomotive::Notifications.expects(:new_content_entry).with(@account_1, @content_entry).returns(mock('mailer', :
|
241
|
-
Locomotive::Notifications.expects(:new_content_entry).with(@account_2, @content_entry).returns(mock('mailer', :
|
253
|
+
Locomotive::Notifications.expects(:new_content_entry).with(@account_1, @content_entry).returns(mock('mailer', deliver: true))
|
254
|
+
Locomotive::Notifications.expects(:new_content_entry).with(@account_2, @content_entry).returns(mock('mailer', deliver: true))
|
242
255
|
@content_entry.save
|
243
256
|
end
|
244
257
|
|
@@ -260,7 +273,7 @@ describe Locomotive::ContentEntry do
|
|
260
273
|
end
|
261
274
|
|
262
275
|
def build_content_entry(options = {})
|
263
|
-
@content_type.entries.build({ :
|
276
|
+
@content_type.entries.build({ title: 'Locomotive', description: 'Lorem ipsum....', _label_field_name: 'title' }.merge(options))
|
264
277
|
end
|
265
278
|
|
266
279
|
def fake_bson_id(id)
|
@@ -22,4 +22,10 @@ describe 'Locomotive::Middlewares::SeoTrailingSlash' do
|
|
22
22
|
response.status.should be(301)
|
23
23
|
end
|
24
24
|
|
25
|
+
it 'removes the trailing slash but preserves the query' do
|
26
|
+
get '/hello_world/?test=name'
|
27
|
+
response.status.should be(301)
|
28
|
+
response.location.should == '/hello_world?test=name'
|
29
|
+
end
|
30
|
+
|
25
31
|
end
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: locomotive_cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.0.
|
5
|
+
version: 2.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Didier Lafforgue
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
type: :runtime
|
@@ -1104,6 +1104,8 @@ files:
|
|
1104
1104
|
- lib/locomotive_cms.rb
|
1105
1105
|
- lib/tasks/development.rake
|
1106
1106
|
- lib/tasks/locomotive.rake
|
1107
|
+
- mongodb/migrate/20130204072721_make_editable_elements_consistent.rb
|
1108
|
+
- mongodb/migrate/20130326201349_rename_entry_to_content_entry.rb
|
1107
1109
|
- public/favicon.ico
|
1108
1110
|
- vendor/assets/fonts/locomotive/fontawesome-webfont.eot
|
1109
1111
|
- vendor/assets/fonts/locomotive/fontawesome-webfont.svg
|
@@ -1337,7 +1339,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
1337
1339
|
- !ruby/object:Gem::Version
|
1338
1340
|
segments:
|
1339
1341
|
- 0
|
1340
|
-
hash: -
|
1342
|
+
hash: -4389909398335603459
|
1341
1343
|
version: '0'
|
1342
1344
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
1343
1345
|
none: false
|
@@ -1346,7 +1348,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1346
1348
|
- !ruby/object:Gem::Version
|
1347
1349
|
segments:
|
1348
1350
|
- 0
|
1349
|
-
hash: -
|
1351
|
+
hash: -4389909398335603459
|
1350
1352
|
version: '0'
|
1351
1353
|
requirements: []
|
1352
1354
|
rubyforge_project:
|